Skip to content

Commit

Permalink
Merge 08684a8 into 25661c5
Browse files Browse the repository at this point in the history
  • Loading branch information
tigh-latte authored Sep 24, 2021
2 parents 25661c5 + 08684a8 commit 079e1e8
Show file tree
Hide file tree
Showing 15 changed files with 471 additions and 455 deletions.
100 changes: 1 addition & 99 deletions bscript/interpreter/engine.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,104 +5,6 @@

package interpreter

import (
"math/big"

"github.com/libsv/go-bk/bec"
)

// ScriptFlags is a bitmask defining additional operations or tests that will be
// done when executing a script pair.
type ScriptFlags uint32

const (
// ScriptBip16 defines whether the bip16 threshold has passed and thus
// pay-to-script hash transactions will be fully validated.
ScriptBip16 ScriptFlags = 1 << iota

// ScriptStrictMultiSig defines whether to verify the stack item
// used by CHECKMULTISIG is zero length.
ScriptStrictMultiSig

// ScriptDiscourageUpgradableNops defines whether to verify that
// NOP1 through NOP10 are reserved for future soft-fork upgrades. This
// flag must not be used for consensus critical code nor applied to
// blocks as this flag is only for stricter standard transaction
// checks. This flag is only applied when the above opcodes are
// executed.
ScriptDiscourageUpgradableNops

// ScriptVerifyCheckLockTimeVerify defines whether to verify that
// a transaction output is spendable based on the locktime.
// This is BIP0065.
ScriptVerifyCheckLockTimeVerify

// ScriptVerifyCheckSequenceVerify defines whether to allow execution
// pathways of a script to be restricted based on the age of the output
// being spent. This is BIP0112.
ScriptVerifyCheckSequenceVerify

// ScriptVerifyCleanStack defines that the stack must contain only
// one stack element after evaluation and that the element must be
// true if interpreted as a boolean. This is rule 6 of BIP0062.
// This flag should never be used without the ScriptBip16 flag.
ScriptVerifyCleanStack

// ScriptVerifyDERSignatures defines that signatures are required
// to comply with the DER format.
ScriptVerifyDERSignatures

// ScriptVerifyLowS defines that signatures are required to comply with
// the DER format and whose S value is <= order / 2. This is rule 5
// of BIP0062.
ScriptVerifyLowS

// ScriptVerifyMinimalData defines that signatures must use the smallest
// push operator. This is both rules 3 and 4 of BIP0062.
ScriptVerifyMinimalData

// ScriptVerifyNullFail defines that signatures must be empty if
// a CHECKSIG or CHECKMULTISIG operation fails.
ScriptVerifyNullFail

// ScriptVerifySigPushOnly defines that signature scripts must contain
// only pushed data. This is rule 2 of BIP0062.
ScriptVerifySigPushOnly

// ScriptEnableSighashForkID defined that signature scripts have forkid
// enabled.
ScriptEnableSighashForkID

// ScriptVerifyStrictEncoding defines that signature scripts and
// public keys must follow the strict encoding requirements.
ScriptVerifyStrictEncoding

// ScriptVerifyBip143SigHash defines that signature hashes should
// be calculated using the bip0143 signature hashing algorithm.
ScriptVerifyBip143SigHash

// ScriptUTXOAfterGenesis defines that the utxo was created after
// genesis.
ScriptUTXOAfterGenesis

// ScriptVerifyMinimalIf defines the enforcement of any conditional statement using the
// minimum required data.
ScriptVerifyMinimalIf
)

// HasFlag returns whether the ScriptFlags has the passed flag set.
func (s ScriptFlags) HasFlag(flag ScriptFlags) bool {
return s&flag == flag
}

// AddFlag adds the passed flag to ScriptFlags
func (s *ScriptFlags) AddFlag(flag ScriptFlags) {
*s |= flag
}

// halfOrder is used to tame ECDSA malleability (see BIP0062).
var halfOrder = new(big.Int).Rsh(bec.S256().N, 1)

// Engine is the virtual machine that executes scripts.
type Engine interface {
Execute(ExecutionParams) error
Expand All @@ -122,7 +24,7 @@ func NewEngine() Engine {
// for successful validation or an error if one occurred.
func (e *engine) Execute(params ExecutionParams) error {
th := &thread{
scriptParser: &parser{},
scriptParser: &DefaultOpcodeParser{},
cfg: &beforeGenesisConfig{},
}

Expand Down
72 changes: 37 additions & 35 deletions bscript/interpreter/engine_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import (

"github.com/libsv/go-bt/v2"
"github.com/libsv/go-bt/v2/bscript"
"github.com/libsv/go-bt/v2/bscript/interpreter/errs"
"github.com/libsv/go-bt/v2/bscript/interpreter/scriptflag"
"github.com/libsv/go-bt/v2/sighash"
)

Expand Down Expand Up @@ -52,7 +54,7 @@ func TestBadPC(t *testing.T) {

for _, test := range tests {
vm := &thread{
scriptParser: &parser{},
scriptParser: &DefaultOpcodeParser{},
cfg: &beforeGenesisConfig{},
}
err := vm.apply(ExecutionParams{
Expand Down Expand Up @@ -108,7 +110,7 @@ func TestCheckErrorCondition(t *testing.T) {
}

vm := &thread{
scriptParser: &parser{},
scriptParser: &DefaultOpcodeParser{},
cfg: &beforeGenesisConfig{},
}

Expand Down Expand Up @@ -142,8 +144,8 @@ func TestCheckErrorCondition(t *testing.T) {
func TestInvalidFlagCombinations(t *testing.T) {
t.Parallel()

tests := []ScriptFlags{
ScriptVerifyCleanStack,
tests := []scriptflag.Flag{
scriptflag.VerifyCleanStack,
}

uls, err := bscript.NewFromASM("OP_NOP")
Expand Down Expand Up @@ -174,7 +176,7 @@ func TestInvalidFlagCombinations(t *testing.T) {

for i, test := range tests {
vm := &thread{
scriptParser: &parser{},
scriptParser: &DefaultOpcodeParser{},
cfg: &beforeGenesisConfig{},
}
err := vm.apply(ExecutionParams{
Expand All @@ -183,7 +185,7 @@ func TestInvalidFlagCombinations(t *testing.T) {
PreviousTxOut: txOut,
Flags: test,
})
if !IsErrorCode(err, ErrInvalidFlags) {
if !errs.IsErrorCode(err, errs.ErrInvalidFlags) {
t.Fatalf("TestInvalidFlagCombinations #%d unexpected "+
"error: %v", i, err)
}
Expand Down Expand Up @@ -235,7 +237,7 @@ func TestCheckPubKeyEncoding(t *testing.T) {
},
}

vm := thread{flags: ScriptVerifyStrictEncoding}
vm := thread{scriptflag: scriptflag.VerifyStrictEncoding}
for _, test := range tests {
err := vm.checkPubKeyEncoding(test.key)
if err != nil && test.isValid {
Expand Down Expand Up @@ -407,7 +409,7 @@ func TestCheckSignatureEncoding(t *testing.T) {
},
}

vm := thread{flags: ScriptVerifyStrictEncoding}
vm := thread{scriptflag: scriptflag.VerifyStrictEncoding}
for _, test := range tests {
err := vm.checkSignatureEncoding(test.sig)
if err != nil && test.isValid {
Expand All @@ -425,140 +427,140 @@ func TestCheckHashTypeEncoding(t *testing.T) {
var SigHashBug sighash.Flag = 0x20
encodingTests := []struct {
SigHash sighash.Flag
EngineFlags ScriptFlags
EngineFlags scriptflag.Flag
ShouldFail bool
}{
{
sighash.All,
ScriptVerifyStrictEncoding,
scriptflag.VerifyStrictEncoding,
false,
},
{
sighash.None,
ScriptVerifyStrictEncoding,
scriptflag.VerifyStrictEncoding,
false,
},
{
sighash.Single,
ScriptVerifyStrictEncoding,
scriptflag.VerifyStrictEncoding,
false,
},
{
sighash.All | sighash.AnyOneCanPay,
ScriptVerifyStrictEncoding,
scriptflag.VerifyStrictEncoding,
false,
},
{
sighash.None | sighash.AnyOneCanPay,
ScriptVerifyStrictEncoding,
scriptflag.VerifyStrictEncoding,
false,
},
{
sighash.Single | sighash.AnyOneCanPay,
ScriptVerifyStrictEncoding,
scriptflag.VerifyStrictEncoding,
false,
},
{
sighash.All | sighash.ForkID,
ScriptVerifyStrictEncoding,
scriptflag.VerifyStrictEncoding,
true,
},
{
sighash.None | sighash.ForkID,
ScriptVerifyStrictEncoding,
scriptflag.VerifyStrictEncoding,
true,
},
{
sighash.Single | sighash.ForkID,
ScriptVerifyStrictEncoding,
scriptflag.VerifyStrictEncoding,
true,
},
{
sighash.All | sighash.AnyOneCanPay | sighash.ForkID,
ScriptVerifyStrictEncoding,
scriptflag.VerifyStrictEncoding,
true,
},
{
sighash.None | sighash.AnyOneCanPay | sighash.ForkID,
ScriptVerifyStrictEncoding,
scriptflag.VerifyStrictEncoding,
true,
},
{
sighash.Single | sighash.AnyOneCanPay | sighash.ForkID,
ScriptVerifyStrictEncoding,
scriptflag.VerifyStrictEncoding,
true,
},

{
sighash.All | sighash.ForkID,
ScriptVerifyStrictEncoding | ScriptVerifyBip143SigHash,
scriptflag.VerifyStrictEncoding | scriptflag.VerifyBip143SigHash,
false,
},
{
sighash.None | sighash.ForkID,
ScriptVerifyStrictEncoding | ScriptVerifyBip143SigHash,
scriptflag.VerifyStrictEncoding | scriptflag.VerifyBip143SigHash,
false,
},
{
sighash.Single | sighash.ForkID,
ScriptVerifyStrictEncoding | ScriptVerifyBip143SigHash,
scriptflag.VerifyStrictEncoding | scriptflag.VerifyBip143SigHash,
false,
},
{
sighash.All | sighash.AnyOneCanPay | sighash.ForkID,
ScriptVerifyStrictEncoding | ScriptVerifyBip143SigHash,
scriptflag.VerifyStrictEncoding | scriptflag.VerifyBip143SigHash,
false,
},
{
sighash.None | sighash.AnyOneCanPay | sighash.ForkID,
ScriptVerifyStrictEncoding | ScriptVerifyBip143SigHash,
scriptflag.VerifyStrictEncoding | scriptflag.VerifyBip143SigHash,
false,
},
{
sighash.Single | sighash.AnyOneCanPay | sighash.ForkID,
ScriptVerifyStrictEncoding | ScriptVerifyBip143SigHash,
scriptflag.VerifyStrictEncoding | scriptflag.VerifyBip143SigHash,
false,
},

{
sighash.All,
ScriptVerifyStrictEncoding | ScriptVerifyBip143SigHash,
scriptflag.VerifyStrictEncoding | scriptflag.VerifyBip143SigHash,
true,
},
{
sighash.None,
ScriptVerifyStrictEncoding | ScriptVerifyBip143SigHash,
scriptflag.VerifyStrictEncoding | scriptflag.VerifyBip143SigHash,
true,
},
{
sighash.Single,
ScriptVerifyStrictEncoding | ScriptVerifyBip143SigHash,
scriptflag.VerifyStrictEncoding | scriptflag.VerifyBip143SigHash,
true,
},
{
sighash.All | sighash.AnyOneCanPay,
ScriptVerifyStrictEncoding | ScriptVerifyBip143SigHash,
scriptflag.VerifyStrictEncoding | scriptflag.VerifyBip143SigHash,
true,
},
{
sighash.None | sighash.AnyOneCanPay,
ScriptVerifyStrictEncoding | ScriptVerifyBip143SigHash,
scriptflag.VerifyStrictEncoding | scriptflag.VerifyBip143SigHash,
true,
},
{
sighash.Single | sighash.AnyOneCanPay,
ScriptVerifyStrictEncoding | ScriptVerifyBip143SigHash,
scriptflag.VerifyStrictEncoding | scriptflag.VerifyBip143SigHash,
true,
},
{
sighash.Single | sighash.AnyOneCanPay | sighash.ForkID | SigHashBug,
ScriptVerifyStrictEncoding | ScriptVerifyBip143SigHash,
scriptflag.VerifyStrictEncoding | scriptflag.VerifyBip143SigHash,
true,
},
}

for i, test := range encodingTests {
e := thread{flags: test.EngineFlags}
e := thread{scriptflag: test.EngineFlags}
err := e.checkHashTypeEncoding(test.SigHash)
if test.ShouldFail && err == nil {
t.Errorf("Expected test %d to fail", i)
Expand Down
17 changes: 3 additions & 14 deletions bscript/interpreter/error.go → bscript/interpreter/errs/error.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,11 @@
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

package interpreter
package errs

import (
"errors"
"fmt"

"github.com/libsv/go-bt/v2/bscript"
)

// ErrorCode identifies a kind of script error.
Expand Down Expand Up @@ -421,8 +419,8 @@ func (e Error) Error() string {
return e.Description
}

// scriptError creates an Error given a set of arguments.
func scriptError(c ErrorCode, desc string, fmtArgs ...interface{}) Error {
// NewError creates an Error given a set of arguments.
func NewError(c ErrorCode, desc string, fmtArgs ...interface{}) Error {
return Error{ErrorCode: c, Description: fmt.Sprintf(desc, fmtArgs...)}
}

Expand All @@ -433,12 +431,3 @@ func IsErrorCode(err error, c ErrorCode) bool {
ok := errors.As(err, e)
return ok && e.ErrorCode == c
}

// NewErrMinimalDataPush returns an Error with code ErrMinimalData
func NewErrMinimalDataPush(op, expected opcode, length int) Error {
fmtStr := "data push of %d bytes encoded with opcode %s, use %s instead"
if (bscript.Op1 <= op.val && op.val <= bscript.Op16) || op.val == bscript.Op1NEGATE {
fmtStr = "data push of value %d encoded with opcode %s, use %s instead"
}
return scriptError(ErrMinimalData, fmt.Sprintf(fmtStr, length, op.Name(), expected.Name()))
}
Loading

0 comments on commit 079e1e8

Please sign in to comment.