Skip to content

Commit

Permalink
Enhancement: Append Opcodes (#89)
Browse files Browse the repository at this point in the history
* fixed linter

* removed uppercase code in AppendOpcodes

* removed uppercase code in AppendOpcodes

* docstring
  • Loading branch information
tigh-latte authored Dec 2, 2021
1 parent 83c90f3 commit 83b0701
Show file tree
Hide file tree
Showing 5 changed files with 72 additions and 27 deletions.
9 changes: 5 additions & 4 deletions bscript/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,9 @@ var (

// Sentinel errors raised by the package.
var (
ErrInvalidPKLen = errors.New("invalid public key length")
ErrInvalidOpCode = errors.New("invalid opcode data")
ErrEmptyScript = errors.New("script is empty")
ErrNotP2PKH = errors.New("not a P2PKH")
ErrInvalidPKLen = errors.New("invalid public key length")
ErrInvalidOpCode = errors.New("invalid opcode data")
ErrEmptyScript = errors.New("script is empty")
ErrNotP2PKH = errors.New("not a P2PKH")
ErrInvalidOpcodeType = errors.New("use AppendPushData for push data funcs")
)
6 changes: 3 additions & 3 deletions bscript/interpreter/reference_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,9 +89,9 @@ func parseShortForm(script string) (*bscript.Script, error) {
// if parses as a plain number
if num, err := strconv.ParseInt(tok, 10, 64); err == nil {
if num == 0 {
scr.AppendOpCode(bscript.Op0)
scr.AppendOpcodes(bscript.Op0)
} else if num == -1 || (1 <= num && num <= 16) {
scr.AppendOpCode((bscript.Op1 - 1) + byte(num))
scr.AppendOpcodes((bscript.Op1 - 1) + byte(num))
} else {
n := &scriptNumber{val: big.NewInt(num)}
scr.AppendPushData(n.Bytes())
Expand All @@ -106,7 +106,7 @@ func parseShortForm(script string) (*bscript.Script, error) {
tok[0] == '\'' && tok[len(tok)-1] == '\'' {
scr.AppendPushData([]byte(tok[1 : len(tok)-1]))
} else if opcode, ok := shortFormOps[tok]; ok {
scr.AppendOpCode(opcode)
scr = append(scr, opcode)
} else {
return nil, fmt.Errorf("bad token %q", tok)
}
Expand Down
25 changes: 15 additions & 10 deletions bscript/script.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ func NewFromASM(str string) (*Script, error) {

for _, section := range strings.Split(str, " ") {
if val, ok := opCodeStrings[section]; ok {
s.AppendOpCode(val)
_ = s.AppendOpcodes(val)
} else {
if err := s.AppendPushDataHexString(section); err != nil {
return nil, ErrInvalidOpCode
Expand Down Expand Up @@ -124,14 +124,12 @@ func NewP2PKHFromAddress(addr string) (*Script, error) {
return nil, err
}

s := new(Script).
AppendOpCode(OpDUP).
AppendOpCode(OpHASH160)
s := new(Script)
_ = s.AppendOpcodes(OpDUP, OpHASH160)
if err = s.AppendPushData(publicKeyHashBytes); err != nil {
return nil, err
}
s.AppendOpCode(OpEQUALVERIFY).
AppendOpCode(OpCHECKSIG)
_ = s.AppendOpcodes(OpEQUALVERIFY, OpCHECKSIG)

return s, nil
}
Expand Down Expand Up @@ -210,10 +208,17 @@ func (s *Script) AppendPushDataStrings(pushDataStrings []string) error {
return s.AppendPushDataArray(dataBytes)
}

// AppendOpCode appends an opcode type to the script
func (s *Script) AppendOpCode(o uint8) *Script {
*s = append(*s, o)
return s
// AppendOpcodes appends opcodes type to the script.
// This does not support appending OP_PUSHDATA opcodes, so use `Script.AppendPushData` instead.
func (s *Script) AppendOpcodes(oo ...uint8) error {
for _, o := range oo {
switch o {
case OpPUSHDATA1, OpPUSHDATA2, OpPUSHDATA4:
return fmt.Errorf("%w: %s", ErrInvalidOpcodeType, opCodeValues[o])
}
}
*s = append(*s, oo...)
return nil
}

// String implements the stringer interface and returns the hex string of script.
Expand Down
44 changes: 44 additions & 0 deletions bscript/script_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"github.com/libsv/go-bk/bec"
"github.com/libsv/go-bk/bip32"
"github.com/libsv/go-bk/chaincfg"
"github.com/pkg/errors"
"github.com/stretchr/testify/assert"

"github.com/libsv/go-bt/v2/bscript"
Expand Down Expand Up @@ -218,6 +219,49 @@ func TestErrorIsAppended(t *testing.T) {
assert.True(t, strings.HasSuffix(asm, "[error]"), "toASM() should end with [error]")
}

func TestScript_AppendOpcodes(t *testing.T) {
tests := map[string]struct {
script string
appends []byte
expScript string
expErr error
}{
"successful single append": {
script: "OP_2 OP_2 OP_ADD",
appends: []byte{bscript.OpEQUALVERIFY},
expScript: "OP_2 OP_2 OP_ADD OP_EQUALVERIFY",
},
"successful multiple append": {
script: "OP_2 OP_2 OP_ADD",
appends: []byte{bscript.OpEQUAL, bscript.OpVERIFY},
expScript: "OP_2 OP_2 OP_ADD OP_EQUAL OP_VERIFY",
},
"unsuccessful push adata append": {
script: "OP_2 OP_2 OP_ADD",
appends: []byte{bscript.OpEQUAL, bscript.OpPUSHDATA1, 0x44},
expErr: bscript.ErrInvalidOpcodeType,
},
}

for name, test := range tests {
t.Run(name, func(t *testing.T) {
script, err := bscript.NewFromASM(test.script)
assert.NoError(t, err)

err = script.AppendOpcodes(test.appends...)
if test.expErr != nil {
assert.Error(t, err)
assert.EqualError(t, test.expErr, errors.Unwrap(err).Error())
} else {
assert.NoError(t, err)
asm, err := script.ToASM()
assert.NoError(t, err)
assert.Equal(t, test.expScript, asm)
}
})
}
}

func TestScript_Equals(t *testing.T) {
t.Parallel()
tests := map[string]struct {
Expand Down
15 changes: 5 additions & 10 deletions txoutput.go
Original file line number Diff line number Diff line change
Expand Up @@ -135,21 +135,18 @@ func (tx *Tx) AddHashPuzzleOutput(secret, publicKeyHash string, satoshis uint64)

s := &bscript.Script{}

s.AppendOpCode(bscript.OpHASH160)
_ = s.AppendOpcodes(bscript.OpHASH160)
secretBytesHash := crypto.Hash160([]byte(secret))

if err = s.AppendPushData(secretBytesHash); err != nil {
return err
}
s.AppendOpCode(bscript.OpEQUALVERIFY).
AppendOpCode(bscript.OpDUP).
AppendOpCode(bscript.OpHASH160)
_ = s.AppendOpcodes(bscript.OpEQUALVERIFY, bscript.OpDUP, bscript.OpHASH160)

if err = s.AppendPushData(publicKeyHashBytes); err != nil {
return err
}
s.AppendOpCode(bscript.OpEQUALVERIFY).
AppendOpCode(bscript.OpCHECKSIG)
_ = s.AppendOpcodes(bscript.OpEQUALVERIFY, bscript.OpCHECKSIG)

tx.AddOutput(&Output{
Satoshis: satoshis,
Expand Down Expand Up @@ -184,10 +181,8 @@ func (tx *Tx) AddOpReturnPartsOutput(data [][]byte) error {
func createOpReturnOutput(data [][]byte) (*Output, error) {
s := &bscript.Script{}

s.AppendOpCode(bscript.OpFALSE)
s.AppendOpCode(bscript.OpRETURN)
err := s.AppendPushDataArray(data)
if err != nil {
_ = s.AppendOpcodes(bscript.OpFALSE, bscript.OpRETURN)
if err := s.AppendPushDataArray(data); err != nil {
return nil, err
}

Expand Down

0 comments on commit 83b0701

Please sign in to comment.