Skip to content

Commit

Permalink
DRY changes and adding support for BIP-239 Extended Transaction Format (
Browse files Browse the repository at this point in the history
#130)

* Merge branch 'master' of https://github.com/libsv/go-bt

* Fix panic in ToAsm() caused by last commit. (#109)

* Fix rename of variable

* Fixed an old test that was failing due to changes in ToAsm() method

* Explicity check error

* Spelling

* All transaction parsing functions now use one function.  Added BIP-239 support (extended transaction format)

* Add comments and extra test

* Overcome linter

* Linter workarounds

* Linter fix

* More linting workarounds

* Minor changes to address comments in PR
  • Loading branch information
ordishs committed Nov 16, 2022
1 parent 34e82d8 commit 4208458
Show file tree
Hide file tree
Showing 21 changed files with 336 additions and 168 deletions.
5 changes: 3 additions & 2 deletions bscript/address.go
@@ -1,3 +1,4 @@
// Package bscript comment
package bscript

import (
Expand Down Expand Up @@ -83,7 +84,7 @@ func NewAddressFromPublicKeyHash(hash []byte, mainnet bool) (*Address, error) {
if !mainnet {
bb[0] = 111
}
// nolint: makezero // we need to set up the array with 1
//nolint: makezero // we need to set up the array with 1
bb = append(bb, hash...)

return &Address{
Expand All @@ -105,7 +106,7 @@ func NewAddressFromPublicKey(pubKey *bec.PublicKey, mainnet bool) (*Address, err
if !mainnet {
bb[0] = 111
}
// nolint: makezero // we need to set up the array with 1
//nolint: makezero // we need to set up the array with 1
bb = append(bb, hash...)

return &Address{
Expand Down
18 changes: 10 additions & 8 deletions bscript/interpreter/debug/debugger.go
@@ -1,3 +1,4 @@
// Package debug comment
package debug

import "github.com/libsv/go-bt/v2/bscript/interpreter"
Expand Down Expand Up @@ -66,14 +67,15 @@ type debugger struct {
// functions.
//
// Example usage:
// debugger := debug.NewDebugger()
// debugger.AttachBeforeExecuteOpcode(func (state *interpreter.State) {
// fmt.Println(state.DataStack)
// })
// debugger.AttachAfterStackPush(func (state *interpreter.State, data []byte) {
// fmt.Println(hex.EncodeToString(data))
// })
// engine.Execute(interpreter.WithDebugger(debugger))
//
// debugger := debug.NewDebugger()
// debugger.AttachBeforeExecuteOpcode(func (state *interpreter.State) {
// fmt.Println(state.DataStack)
// })
// debugger.AttachAfterStackPush(func (state *interpreter.State, data []byte) {
// fmt.Println(hex.EncodeToString(data))
// })
// engine.Execute(interpreter.WithDebugger(debugger))
func NewDebugger(oo ...DebuggerOptionFunc) DefaultDebugger {
opts := &debugOpts{}
for _, o := range oo {
Expand Down
16 changes: 8 additions & 8 deletions bscript/interpreter/engine_test.go
Expand Up @@ -122,7 +122,7 @@ func TestCheckErrorCondition(t *testing.T) {
tx: tx,
})
if err != nil {
t.Errorf("failed to configure thread %w", err)
t.Errorf("failed to configure thread %v", err)
}

var done bool
Expand All @@ -132,7 +132,7 @@ func TestCheckErrorCondition(t *testing.T) {
t.Fatalf("failed to step %dth time: %v", i, err)
}
if done && i != len(*lscript)-1 {
t.Fatalf("finshed early on %dth time", i)
t.Fatalf("finished early on %dth time", i)
}
}
err = vm.CheckErrorCondition(false)
Expand Down Expand Up @@ -289,7 +289,7 @@ func TestValidateParams(t *testing.T) {
},
expErr: errors.New("tx and previous output must be supplied for checksig"),
},
"provided locking script that differs from previoustxout's errors": {
"provided locking script that differs from previous txout's errors": {
params: execOpts{
lockingScript: func() *bscript.Script {
script, err := bscript.NewFromHexString("52529387")
Expand Down Expand Up @@ -322,7 +322,7 @@ func TestValidateParams(t *testing.T) {
},
expErr: errors.New("locking script does not match the previous outputs locking script"),
},
"provided unlocking scropt that differs from tx input's errors": {
"provided unlocking script that differs from tx input's errors": {
params: execOpts{
lockingScript: func() *bscript.Script {
script, err := bscript.NewFromHexString("76a91454807ccc44c0eec0b0e187b3ce0e137e9c6cd65d88ac")
Expand Down Expand Up @@ -501,7 +501,7 @@ func TestCheckPubKeyEncoding(t *testing.T) {
"when it should have succeeded: %v", test.name,
err)
} else if err == nil && !test.isValid {
t.Errorf("checkSignatureEncooding test '%s' succeeded "+
t.Errorf("checkSignatureEncoding test '%s' succeeded "+
"when it should have failed", test.name)
}
}
Expand Down Expand Up @@ -673,7 +673,7 @@ func TestCheckSignatureEncoding(t *testing.T) {
"when it should have succeeded: %v", test.name,
err)
} else if err == nil && !test.isValid {
t.Errorf("checkSignatureEncooding test '%s' succeeded "+
t.Errorf("checkSignatureEncoding test '%s' succeeded "+
"when it should have failed", test.name)
}
}
Expand Down Expand Up @@ -845,7 +845,7 @@ func TestEngine_WithState(t *testing.T) {
CondStack: []int{},
ElseStack: [][]byte{},
Flags: scriptflag.UTXOAfterGenesis | scriptflag.EnableSighashForkID,
LastCodeSeperatorIdx: 0,
LastCodeSeparatorIdx: 0,
NumOps: 3,
SavedFirstStack: [][]byte{},
Scripts: func() []ParsedScript {
Expand Down Expand Up @@ -884,7 +884,7 @@ func TestEngine_WithState(t *testing.T) {
CondStack: []int{},
ElseStack: [][]byte{},
Flags: scriptflag.UTXOAfterGenesis | scriptflag.EnableSighashForkID,
LastCodeSeperatorIdx: 0,
LastCodeSeparatorIdx: 0,
NumOps: 8,
SavedFirstStack: [][]byte{},
Scripts: func() []ParsedScript {
Expand Down
9 changes: 5 additions & 4 deletions bscript/interpreter/errs/error.go
Expand Up @@ -2,6 +2,7 @@
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

// Package errs comment
package errs

import (
Expand Down Expand Up @@ -405,10 +406,10 @@ func (e ErrorCode) String() string {

// Error identifies a script-related error. It is used to indicate three
// classes of errors:
// 1) Script execution failures due to violating one of the many requirements
// imposed by the script engine or evaluating to false
// 2) Improper API usage by callers
// 3) Internal consistency check failures
// 1. Script execution failures due to violating one of the many requirements
// imposed by the script engine or evaluating to false
// 2. Improper API usage by callers
// 3. Internal consistency check failures
//
// The caller can use type assertions on the returned errors to access the
// ErrorCode field to ascertain the specific reason for the error. As an
Expand Down
2 changes: 1 addition & 1 deletion bscript/interpreter/operations.go
Expand Up @@ -1836,7 +1836,7 @@ func opcodeSha1(op *ParsedOpcode, t *thread) error {
return err
}

hash := sha1.Sum(buf) // nolint:gosec // operation is for sha1
hash := sha1.Sum(buf) //nolint:gosec // operation is for sha1
t.dstack.PushByteArray(hash[:])
return nil
}
Expand Down
1 change: 1 addition & 0 deletions bscript/interpreter/scriptflag/scriptflag.go
@@ -1,3 +1,4 @@
// Package scriptflag comment
package scriptflag

// Flag is a bitmask defining additional operations or tests that will be
Expand Down
6 changes: 3 additions & 3 deletions bscript/interpreter/state.go
Expand Up @@ -12,7 +12,7 @@ type State struct {
Scripts []ParsedScript
ScriptIdx int
OpcodeIdx int
LastCodeSeperatorIdx int
LastCodeSeparatorIdx int
NumOps int
Flags scriptflag.Flag
IsFinished bool
Expand Down Expand Up @@ -66,7 +66,7 @@ func (t *thread) State() *State {
Scripts: make([]ParsedScript, len(t.scripts)),
ScriptIdx: scriptIdx,
OpcodeIdx: offsetIdx,
LastCodeSeperatorIdx: t.lastCodeSep,
LastCodeSeparatorIdx: t.lastCodeSep,
NumOps: t.numOps,
Flags: t.flags,
IsFinished: t.scriptIdx > scriptIdx,
Expand Down Expand Up @@ -127,7 +127,7 @@ func (t *thread) SetState(state *State) {
t.scripts = state.Scripts
t.scriptIdx = state.ScriptIdx
t.scriptOff = state.OpcodeIdx
t.lastCodeSep = state.LastCodeSeperatorIdx
t.lastCodeSep = state.LastCodeSeparatorIdx
t.numOps = state.NumOps
t.flags = state.Flags
t.afterGenesis = state.Genesis.AfterGenesis
Expand Down
23 changes: 21 additions & 2 deletions bscript/script.go
Expand Up @@ -233,13 +233,32 @@ func (s *Script) ToASM() (string, error) {
parts, err := DecodeParts(*s)
// if err != nil, we will append [error] to the ASM script below (as done in the node).

data := false
if len(*s) > 1 && ((*s)[0] == OpRETURN || ((*s)[0] == OpFALSE && (*s)[1] == OpRETURN)) {
data = true
}

var asm strings.Builder

for _, p := range parts {
asm.WriteRune(' ')
if len(p) == 1 {
asm.WriteString(opCodeValues[p[0]])
if data && p[0] != 0x6a {
asm.WriteString(fmt.Sprintf("%d", p[0]))
} else {
asm.WriteString(opCodeValues[p[0]])
}
} else {
asm.WriteString(hex.EncodeToString(p))
if data && len(p) <= 4 {
b := make([]byte, 0)
b = append(b, p...)
for i := 0; i < 4-len(p); i++ {
b = append(b, 0)
}
asm.WriteString(fmt.Sprintf("%d", binary.LittleEndian.Uint32(b)))
} else {
asm.WriteString(hex.EncodeToString(p))
}
}
}

Expand Down
50 changes: 50 additions & 0 deletions bscript/script_test.go
Expand Up @@ -514,3 +514,53 @@ func TestScript_UnmarshalJSON(t *testing.T) {
})
}
}

func TestScriptToAsm(t *testing.T) {
script, _ := hex.DecodeString("006a2231394878696756345179427633744870515663554551797131707a5a56646f4175744d7301e4b8bbe381aa54574954544552e381a8425356e381ae547765746368e381a7e381aee98195e381840a547765746368e381a7e381afe887aae58886e381aee69bb8e38184e3819fe38384e382a8e383bce38388e381afe4b880e795aae69c80e5889de381bee381a70ae38195e3818be381aee381bce381a3e381a6e38184e381a4e381a7e38282e7a2bae8aa8de58fafe883bde381a7e8aaade381bfe8bebce381bfe381a7e995b7e69982e996930ae5819ce6ada2e381afe38182e3828ae381bee3819be38293e380825954e383aae383b3e382afe381aee58b95e794bbe38292e8a696e881b4e38197e3819fe5a0b4e590880ae99fb3e6a5bde381afe382b9e382afe383ade383bce383abe38197e381a6e38282e98094e58887e3828ce3819ae881b4e38193e38188e3819fe381bee381be0ae38384e382a4e38383e382bfe383bce381afe69c80e5889de381aee383ace382b9e381bee381a7e8a18ce38191e381aae38184e381a7e38197e38287e380820a746578742f706c61696e04746578741f7477657463685f7477746578745f313634343834393439353138332e747874017c223150755161374b36324d694b43747373534c4b79316b683536575755374d74555235035345540b7477646174615f6a736f6e046e756c6c0375726c046e756c6c07636f6d6d656e74046e756c6c076d625f757365720439373038057265706c794035366462363536376363306230663539316265363561396135313731663533396635316334333165643837356464326136373431643733353061353539363762047479706504706f73740974696d657374616d70046e756c6c036170700674776574636807696e766f6963652461366637336133312d336334342d346164612d393937352d386537386261666661623765017c22313550636948473232534e4c514a584d6f53556157566937575371633768436676610d424954434f494e5f454344534122314c6970354b335671677743415662674d7842536547434d344355364e344e6b75744c58494b4b554a35765a7753336b4c456e353749356a36485a2b43325733393834314e543532334a4c374534387655706d6f57306b4677613767392b51703246434f4d42776a556a7a76454150624252784d496a746c6b476b3d")
s := bscript.Script(script)

asm, err := s.ToASM()
if err != nil {
t.Error(err)
t.FailNow()
}

expected := "0 OP_RETURN 31394878696756345179427633744870515663554551797131707a5a56646f417574 e4b8bbe381aa54574954544552e381a8425356e381ae547765746368e381a7e381aee98195e381840a547765746368e381a7e381afe887aae58886e381aee69bb8e38184e3819fe38384e382a8e383bce38388e381afe4b880e795aae69c80e5889de381bee381a70ae38195e3818be381aee381bce381a3e381a6e38184e381a4e381a7e38282e7a2bae8aa8de58fafe883bde381a7e8aaade381bfe8bebce381bfe381a7e995b7e69982e996930ae5819ce6ada2e381afe38182e3828ae381bee3819be38293e380825954e383aae383b3e382afe381aee58b95e794bbe38292e8a696e881b4e38197e3819fe5a0b4e590880ae99fb3e6a5bde381afe382b9e382afe383ade383bce383abe38197e381a6e38282e98094e58887e3828ce3819ae881b4e38193e38188e3819fe381bee381be0ae38384e382a4e38383e382bfe383bce381afe69c80e5889de381aee383ace382b9e381bee381a7e8a18ce38191e381aae38184e381a7e38197e38287e38082 746578742f706c61696e 1954047348 7477657463685f7477746578745f313634343834393439353138332e747874 124 3150755161374b36324d694b43747373534c4b79316b683536575755374d74555235 5522771 7477646174615f6a736f6e 1819047278 7107189 1819047278 636f6d6d656e74 1819047278 6d625f75736572 942683961 7265706c79 35366462363536376363306230663539316265363561396135313731663533396635316334333165643837356464326136373431643733353061353539363762 1701869940 1953722224 74696d657374616d70 1819047278 7368801 747765746368 696e766f696365 61366637336133312d336334342d346164612d393937352d386537386261666661623765 124 313550636948473232534e4c514a584d6f5355615756693757537163376843667661 424954434f494e5f4543445341 314c6970354b335671677743415662674d7842536547434d344355364e344e6b7574 494b4b554a35765a7753336b4c456e353749356a36485a2b43325733393834314e543532334a4c374534387655706d6f57306b4677613767392b51703246434f4d42776a556a7a76454150624252784d496a746c6b476b3d"

if asm != expected {
t.Errorf("\nExpected %q\ngot %q", expected, asm)
}

}

func TestRunScriptExample2(t *testing.T) {
script, _ := hex.DecodeString("006a0372756e01050c63727970746f6669676874734d16057b22696e223a312c22726566223a5b22343561666530303862396634393663333130356663396132636234373234316565643566646531333531303532616339353938323531636666623939376136385f6f31222c22643335343933633964313266656538363134313663333366653336346662336566373531363234373532313833316264623232303933333731303330383663325f6f31222c22306338623636326339363862316537376164626535666161653566666436633033653537353965373833376132353534653438643561356535326335346634385f6f31222c22336136376365633363313662646238343762393732626565326663316330373137633539656463616537626635663438633931666563636661363335616633335f6f31222c22313465323738633638666635323165303931366164376337313361653461303135366537363336316462643362326233353764666236303238653064636137615f6f31222c22613738663561366437326637383731316536366336323131666262643061306266643135616439316264643030343034393238613966616363363364613664395f6f31222c22373535633932326336366363656533353766356265656437383164323631336634313739346230323839333963333435316466653438393032303238343263355f6f31222c22316661333532383030333363343534663465313263323134383333343436643335313734663031666565373064346639653633366664393462363237316436325f6f31222c22636233356534656361336635616334303561636261636464383632346366303835636333626535336639323633663531616565373037393234616265316237385f6f31222c22373166626133383633343162393332333830656335626665646333613430626365343364343937346465636463393463343139613934613863653564666332335f6f31222c22363161653132323165646438626431646438336332326461326232616237643131346139313239363439366365336664306562613737333236623638613238335f6f31222c22386462643166643638373934353131636364616338333938333136393638306662616338356233613961626439636166366361326666343839633862313633385f6f31222c22386564316564633665656439386135326635373234396333353032663266333764623561336666356233643135613930363732353063383465363035366531315f6f31222c22343062396534373865333766383733636532386364383162666635323532346631383063623538353837376331656139383636343933383039363363646237385f6f31225d2c226f7574223a5b2262633038643265323932623036313031323463313337656361356566393632383464363534363139616162366630313461333932353532613066336339666162225d2c2264656c223a5b5d2c22637265223a5b5d2c2265786563223a5b7b226f70223a2243414c4c222c2264617461223a5b7b22246a6967223a307d2c227265736f6c7665222c5b2263633031363466343332613563383635306331393731376430373161656561646261393065643761303939386234396464656535663537316430323139373032222c313634373630333734373833342c302c2230336339386161663266623237393930613130356364336362616462656461383536613064363238343262666564633430353730343966636232343163333563222c5b302c302c305d5d5d7d5d7d")
s := bscript.Script(script)

asm, err := s.ToASM()
if err != nil {
t.Error(err)
t.FailNow()
}

expected := "0 OP_RETURN 7239026 5 63727970746f666967687473 7b22696e223a312c22726566223a5b22343561666530303862396634393663333130356663396132636234373234316565643566646531333531303532616339353938323531636666623939376136385f6f31222c22643335343933633964313266656538363134313663333366653336346662336566373531363234373532313833316264623232303933333731303330383663325f6f31222c22306338623636326339363862316537376164626535666161653566666436633033653537353965373833376132353534653438643561356535326335346634385f6f31222c22336136376365633363313662646238343762393732626565326663316330373137633539656463616537626635663438633931666563636661363335616633335f6f31222c22313465323738633638666635323165303931366164376337313361653461303135366537363336316462643362326233353764666236303238653064636137615f6f31222c22613738663561366437326637383731316536366336323131666262643061306266643135616439316264643030343034393238613966616363363364613664395f6f31222c22373535633932326336366363656533353766356265656437383164323631336634313739346230323839333963333435316466653438393032303238343263355f6f31222c22316661333532383030333363343534663465313263323134383333343436643335313734663031666565373064346639653633366664393462363237316436325f6f31222c22636233356534656361336635616334303561636261636464383632346366303835636333626535336639323633663531616565373037393234616265316237385f6f31222c22373166626133383633343162393332333830656335626665646333613430626365343364343937346465636463393463343139613934613863653564666332335f6f31222c22363161653132323165646438626431646438336332326461326232616237643131346139313239363439366365336664306562613737333236623638613238335f6f31222c22386462643166643638373934353131636364616338333938333136393638306662616338356233613961626439636166366361326666343839633862313633385f6f31222c22386564316564633665656439386135326635373234396333353032663266333764623561336666356233643135613930363732353063383465363035366531315f6f31222c22343062396534373865333766383733636532386364383162666635323532346631383063623538353837376331656139383636343933383039363363646237385f6f31225d2c226f7574223a5b2262633038643265323932623036313031323463313337656361356566393632383464363534363139616162366630313461333932353532613066336339666162225d2c2264656c223a5b5d2c22637265223a5b5d2c2265786563223a5b7b226f70223a2243414c4c222c2264617461223a5b7b22246a6967223a307d2c227265736f6c7665222c5b2263633031363466343332613563383635306331393731376430373161656561646261393065643761303939386234396464656535663537316430323139373032222c313634373630333734373833342c302c2230336339386161663266623237393930613130356364336362616462656461383536613064363238343262666564633430353730343966636232343163333563222c5b302c302c305d5d5d7d5d7d"
if asm != expected {
t.Errorf("\nExpected %q\ngot %q", expected, asm)
}
}

func TestRunScriptExample3(t *testing.T) {
script, _ := hex.DecodeString("006a223139694733575459537362796f7333754a373333794b347a45696f69314665734e55010042666166383166326364346433663239383061623162363564616166656231656631333561626339643534386461633466366134656361623230653033656365362d300274780134")
s := bscript.Script(script)

asm, err := s.ToASM()
if err != nil {
t.Error(err)
t.FailNow()
}

expected := "0 OP_RETURN 3139694733575459537362796f7333754a373333794b347a45696f69314665734e55 0 666166383166326364346433663239383061623162363564616166656231656631333561626339643534386461633466366134656361623230653033656365362d30 30836 52"
if asm != expected {
t.Errorf("\nExpected %q\ngot %q", expected, asm)
}
}
4 changes: 2 additions & 2 deletions examples/read_txs_from_block/read_txs_from_block.go
Expand Up @@ -12,7 +12,7 @@ import (
// In this example, all txs from a block are being read in via chunking, so at no point
// does the entire block have to be held in memory, and instead can be streamed.
//
// We represent the block by interatively reading a file, however it could be any data
// We represent the block by interactively reading a file, however it could be any data
// stream that satisfies the io.Reader interface.

func main() {
Expand All @@ -27,7 +27,7 @@ func main() {
r := bufio.NewReader(f)

// Read file header. This step is specific to file reading and
// may need omitted or modified for other implentations.
// may need omitted or modified for other implementations.
_, err = io.ReadFull(f, make([]byte, 80))
if err != nil {
panic(err)
Expand Down

0 comments on commit 4208458

Please sign in to comment.