Skip to content

Commit

Permalink
Fix: Max Number Length after Genesis (#78)
Browse files Browse the repository at this point in the history
  • Loading branch information
tigh-latte authored Nov 4, 2021
1 parent 0cd048b commit ea790cc
Show file tree
Hide file tree
Showing 7 changed files with 89 additions and 77 deletions.
10 changes: 10 additions & 0 deletions bscript/interpreter/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ type config interface {
MaxStackSize() int
MaxScriptSize() int
MaxScriptElementSize() int
MaxScriptNumberLength() int
MaxPubKeysPerMultiSig() int
}

Expand All @@ -16,6 +17,7 @@ const (
MaxStackSizeBeforeGenesis = 1000
MaxScriptSizeBeforeGenesis = 10000
MaxScriptElementSizeBeforeGenesis = 520
MaxScriptNumberLengthBeforeGenesis = 4
MaxPubKeysPerMultiSigBeforeGenesis = 20
)

Expand Down Expand Up @@ -46,6 +48,14 @@ func (b *beforeGenesisConfig) MaxScriptElementSize() int {
return MaxScriptElementSizeBeforeGenesis
}

func (a *afterGenesisConfig) MaxScriptNumberLength() int {
return 750 * 1000 // 750 * 1Kb
}

func (b *beforeGenesisConfig) MaxScriptNumberLength() int {
return MaxScriptNumberLengthBeforeGenesis
}

func (a *afterGenesisConfig) MaxOps() int {
return math.MaxInt32
}
Expand Down
6 changes: 3 additions & 3 deletions bscript/interpreter/operations.go
Original file line number Diff line number Diff line change
Expand Up @@ -1008,7 +1008,7 @@ func opcodeNum2bin(op *ParsedOp, t *thread) error {

size := int(n.Int32())
if size > t.cfg.MaxScriptElementSize() {
return errs.NewError(errs.ErrNumberTooBig, "n is larger than the max of %d", defaultScriptNumLen)
return errs.NewError(errs.ErrNumberTooBig, "n is larger than the max of %d", t.cfg.MaxScriptElementSize())
}

// encode a as a script num so that we we take the bytes it
Expand Down Expand Up @@ -1058,8 +1058,8 @@ func opcodeBin2num(op *ParsedOp, t *thread) error {
if err != nil {
return err
}
if len(n.Bytes()) > defaultScriptNumLen {
return errs.NewError(errs.ErrNumberTooBig, "script numbers are limited to %d bytes", defaultScriptNumLen)
if len(n.Bytes()) > t.cfg.MaxScriptNumberLength() {
return errs.NewError(errs.ErrNumberTooBig, "script numbers are limited to %d bytes", t.cfg.MaxScriptNumberLength())
}

t.dstack.PushInt(n)
Expand Down
4 changes: 0 additions & 4 deletions bscript/interpreter/scriptnum.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,6 @@ import (
const (
maxInt32 = 1<<31 - 1
minInt32 = -1 << 31

// defaultScriptNumLen is the default number of bytes
// data being interpreted as an integer may be.
defaultScriptNumLen = 4
)

// scriptNum represents a numeric value used in the scripting engine with
Expand Down
126 changes: 63 additions & 63 deletions bscript/interpreter/scriptnum_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,35 +109,35 @@ func TestMakeScriptNum(t *testing.T) {
err error
}{
// Minimal encoding must reject negative 0.
{hexToBytes("80"), 0, defaultScriptNumLen, true, errMinimalData},
{hexToBytes("80"), 0, MaxScriptNumberLengthBeforeGenesis, true, errMinimalData},

// Minimally encoded valid values with minimal encoding flag.
// Should not error and return expected integral number.
{nil, 0, defaultScriptNumLen, true, nil},
{hexToBytes("01"), 1, defaultScriptNumLen, true, nil},
{hexToBytes("81"), -1, defaultScriptNumLen, true, nil},
{hexToBytes("7f"), 127, defaultScriptNumLen, true, nil},
{hexToBytes("ff"), -127, defaultScriptNumLen, true, nil},
{hexToBytes("8000"), 128, defaultScriptNumLen, true, nil},
{hexToBytes("8080"), -128, defaultScriptNumLen, true, nil},
{hexToBytes("8100"), 129, defaultScriptNumLen, true, nil},
{hexToBytes("8180"), -129, defaultScriptNumLen, true, nil},
{hexToBytes("0001"), 256, defaultScriptNumLen, true, nil},
{hexToBytes("0081"), -256, defaultScriptNumLen, true, nil},
{hexToBytes("ff7f"), 32767, defaultScriptNumLen, true, nil},
{hexToBytes("ffff"), -32767, defaultScriptNumLen, true, nil},
{hexToBytes("008000"), 32768, defaultScriptNumLen, true, nil},
{hexToBytes("008080"), -32768, defaultScriptNumLen, true, nil},
{hexToBytes("ffff00"), 65535, defaultScriptNumLen, true, nil},
{hexToBytes("ffff80"), -65535, defaultScriptNumLen, true, nil},
{hexToBytes("000008"), 524288, defaultScriptNumLen, true, nil},
{hexToBytes("000088"), -524288, defaultScriptNumLen, true, nil},
{hexToBytes("000070"), 7340032, defaultScriptNumLen, true, nil},
{hexToBytes("0000f0"), -7340032, defaultScriptNumLen, true, nil},
{hexToBytes("00008000"), 8388608, defaultScriptNumLen, true, nil},
{hexToBytes("00008080"), -8388608, defaultScriptNumLen, true, nil},
{hexToBytes("ffffff7f"), 2147483647, defaultScriptNumLen, true, nil},
{hexToBytes("ffffffff"), -2147483647, defaultScriptNumLen, true, nil},
{nil, 0, MaxScriptNumberLengthBeforeGenesis, true, nil},
{hexToBytes("01"), 1, MaxScriptNumberLengthBeforeGenesis, true, nil},
{hexToBytes("81"), -1, MaxScriptNumberLengthBeforeGenesis, true, nil},
{hexToBytes("7f"), 127, MaxScriptNumberLengthBeforeGenesis, true, nil},
{hexToBytes("ff"), -127, MaxScriptNumberLengthBeforeGenesis, true, nil},
{hexToBytes("8000"), 128, MaxScriptNumberLengthBeforeGenesis, true, nil},
{hexToBytes("8080"), -128, MaxScriptNumberLengthBeforeGenesis, true, nil},
{hexToBytes("8100"), 129, MaxScriptNumberLengthBeforeGenesis, true, nil},
{hexToBytes("8180"), -129, MaxScriptNumberLengthBeforeGenesis, true, nil},
{hexToBytes("0001"), 256, MaxScriptNumberLengthBeforeGenesis, true, nil},
{hexToBytes("0081"), -256, MaxScriptNumberLengthBeforeGenesis, true, nil},
{hexToBytes("ff7f"), 32767, MaxScriptNumberLengthBeforeGenesis, true, nil},
{hexToBytes("ffff"), -32767, MaxScriptNumberLengthBeforeGenesis, true, nil},
{hexToBytes("008000"), 32768, MaxScriptNumberLengthBeforeGenesis, true, nil},
{hexToBytes("008080"), -32768, MaxScriptNumberLengthBeforeGenesis, true, nil},
{hexToBytes("ffff00"), 65535, MaxScriptNumberLengthBeforeGenesis, true, nil},
{hexToBytes("ffff80"), -65535, MaxScriptNumberLengthBeforeGenesis, true, nil},
{hexToBytes("000008"), 524288, MaxScriptNumberLengthBeforeGenesis, true, nil},
{hexToBytes("000088"), -524288, MaxScriptNumberLengthBeforeGenesis, true, nil},
{hexToBytes("000070"), 7340032, MaxScriptNumberLengthBeforeGenesis, true, nil},
{hexToBytes("0000f0"), -7340032, MaxScriptNumberLengthBeforeGenesis, true, nil},
{hexToBytes("00008000"), 8388608, MaxScriptNumberLengthBeforeGenesis, true, nil},
{hexToBytes("00008080"), -8388608, MaxScriptNumberLengthBeforeGenesis, true, nil},
{hexToBytes("ffffff7f"), 2147483647, MaxScriptNumberLengthBeforeGenesis, true, nil},
{hexToBytes("ffffffff"), -2147483647, MaxScriptNumberLengthBeforeGenesis, true, nil},
{hexToBytes("ffffffff7f"), 549755813887, 5, true, nil},
{hexToBytes("ffffffffff"), -549755813887, 5, true, nil},
{hexToBytes("ffffffffffffff7f"), 9223372036854775807, 8, true, nil},
Expand All @@ -150,50 +150,50 @@ func TestMakeScriptNum(t *testing.T) {
// Minimally encoded values that are out of range for data that
// is interpreted as script numbers with the minimal encoding
// flag set. Should error and return 0.
{hexToBytes("0000008000"), 0, defaultScriptNumLen, true, errNumTooBig},
{hexToBytes("0000008080"), 0, defaultScriptNumLen, true, errNumTooBig},
{hexToBytes("0000009000"), 0, defaultScriptNumLen, true, errNumTooBig},
{hexToBytes("0000009080"), 0, defaultScriptNumLen, true, errNumTooBig},
{hexToBytes("ffffffff00"), 0, defaultScriptNumLen, true, errNumTooBig},
{hexToBytes("ffffffff80"), 0, defaultScriptNumLen, true, errNumTooBig},
{hexToBytes("0000000001"), 0, defaultScriptNumLen, true, errNumTooBig},
{hexToBytes("0000000081"), 0, defaultScriptNumLen, true, errNumTooBig},
{hexToBytes("ffffffffffff00"), 0, defaultScriptNumLen, true, errNumTooBig},
{hexToBytes("ffffffffffff80"), 0, defaultScriptNumLen, true, errNumTooBig},
{hexToBytes("ffffffffffffff00"), 0, defaultScriptNumLen, true, errNumTooBig},
{hexToBytes("ffffffffffffff80"), 0, defaultScriptNumLen, true, errNumTooBig},
{hexToBytes("ffffffffffffff7f"), 0, defaultScriptNumLen, true, errNumTooBig},
{hexToBytes("ffffffffffffffff"), 0, defaultScriptNumLen, true, errNumTooBig},
{hexToBytes("0000008000"), 0, MaxScriptNumberLengthBeforeGenesis, true, errNumTooBig},
{hexToBytes("0000008080"), 0, MaxScriptNumberLengthBeforeGenesis, true, errNumTooBig},
{hexToBytes("0000009000"), 0, MaxScriptNumberLengthBeforeGenesis, true, errNumTooBig},
{hexToBytes("0000009080"), 0, MaxScriptNumberLengthBeforeGenesis, true, errNumTooBig},
{hexToBytes("ffffffff00"), 0, MaxScriptNumberLengthBeforeGenesis, true, errNumTooBig},
{hexToBytes("ffffffff80"), 0, MaxScriptNumberLengthBeforeGenesis, true, errNumTooBig},
{hexToBytes("0000000001"), 0, MaxScriptNumberLengthBeforeGenesis, true, errNumTooBig},
{hexToBytes("0000000081"), 0, MaxScriptNumberLengthBeforeGenesis, true, errNumTooBig},
{hexToBytes("ffffffffffff00"), 0, MaxScriptNumberLengthBeforeGenesis, true, errNumTooBig},
{hexToBytes("ffffffffffff80"), 0, MaxScriptNumberLengthBeforeGenesis, true, errNumTooBig},
{hexToBytes("ffffffffffffff00"), 0, MaxScriptNumberLengthBeforeGenesis, true, errNumTooBig},
{hexToBytes("ffffffffffffff80"), 0, MaxScriptNumberLengthBeforeGenesis, true, errNumTooBig},
{hexToBytes("ffffffffffffff7f"), 0, MaxScriptNumberLengthBeforeGenesis, true, errNumTooBig},
{hexToBytes("ffffffffffffffff"), 0, MaxScriptNumberLengthBeforeGenesis, true, errNumTooBig},

// Non-minimally encoded, but otherwise valid values with
// minimal encoding flag. Should error and return 0.
{hexToBytes("00"), 0, defaultScriptNumLen, true, errMinimalData}, // 0
{hexToBytes("0100"), 0, defaultScriptNumLen, true, errMinimalData}, // 1
{hexToBytes("7f00"), 0, defaultScriptNumLen, true, errMinimalData}, // 127
{hexToBytes("800000"), 0, defaultScriptNumLen, true, errMinimalData}, // 128
{hexToBytes("810000"), 0, defaultScriptNumLen, true, errMinimalData}, // 129
{hexToBytes("000100"), 0, defaultScriptNumLen, true, errMinimalData}, // 256
{hexToBytes("ff7f00"), 0, defaultScriptNumLen, true, errMinimalData}, // 32767
{hexToBytes("00800000"), 0, defaultScriptNumLen, true, errMinimalData}, // 32768
{hexToBytes("ffff0000"), 0, defaultScriptNumLen, true, errMinimalData}, // 65535
{hexToBytes("00000800"), 0, defaultScriptNumLen, true, errMinimalData}, // 524288
{hexToBytes("00007000"), 0, defaultScriptNumLen, true, errMinimalData}, // 7340032
{hexToBytes("0009000100"), 0, 5, true, errMinimalData}, // 16779520
{hexToBytes("00"), 0, MaxScriptNumberLengthBeforeGenesis, true, errMinimalData}, // 0
{hexToBytes("0100"), 0, MaxScriptNumberLengthBeforeGenesis, true, errMinimalData}, // 1
{hexToBytes("7f00"), 0, MaxScriptNumberLengthBeforeGenesis, true, errMinimalData}, // 127
{hexToBytes("800000"), 0, MaxScriptNumberLengthBeforeGenesis, true, errMinimalData}, // 128
{hexToBytes("810000"), 0, MaxScriptNumberLengthBeforeGenesis, true, errMinimalData}, // 129
{hexToBytes("000100"), 0, MaxScriptNumberLengthBeforeGenesis, true, errMinimalData}, // 256
{hexToBytes("ff7f00"), 0, MaxScriptNumberLengthBeforeGenesis, true, errMinimalData}, // 32767
{hexToBytes("00800000"), 0, MaxScriptNumberLengthBeforeGenesis, true, errMinimalData}, // 32768
{hexToBytes("ffff0000"), 0, MaxScriptNumberLengthBeforeGenesis, true, errMinimalData}, // 65535
{hexToBytes("00000800"), 0, MaxScriptNumberLengthBeforeGenesis, true, errMinimalData}, // 524288
{hexToBytes("00007000"), 0, MaxScriptNumberLengthBeforeGenesis, true, errMinimalData}, // 7340032
{hexToBytes("0009000100"), 0, 5, true, errMinimalData}, // 16779520

// Non-minimally encoded, but otherwise valid values without
// minimal encoding flag. Should not error and return expected
// integral number.
{hexToBytes("00"), 0, defaultScriptNumLen, false, nil},
{hexToBytes("0100"), 1, defaultScriptNumLen, false, nil},
{hexToBytes("7f00"), 127, defaultScriptNumLen, false, nil},
{hexToBytes("800000"), 128, defaultScriptNumLen, false, nil},
{hexToBytes("810000"), 129, defaultScriptNumLen, false, nil},
{hexToBytes("000100"), 256, defaultScriptNumLen, false, nil},
{hexToBytes("ff7f00"), 32767, defaultScriptNumLen, false, nil},
{hexToBytes("00800000"), 32768, defaultScriptNumLen, false, nil},
{hexToBytes("ffff0000"), 65535, defaultScriptNumLen, false, nil},
{hexToBytes("00000800"), 524288, defaultScriptNumLen, false, nil},
{hexToBytes("00007000"), 7340032, defaultScriptNumLen, false, nil},
{hexToBytes("00"), 0, MaxScriptNumberLengthBeforeGenesis, false, nil},
{hexToBytes("0100"), 1, MaxScriptNumberLengthBeforeGenesis, false, nil},
{hexToBytes("7f00"), 127, MaxScriptNumberLengthBeforeGenesis, false, nil},
{hexToBytes("800000"), 128, MaxScriptNumberLengthBeforeGenesis, false, nil},
{hexToBytes("810000"), 129, MaxScriptNumberLengthBeforeGenesis, false, nil},
{hexToBytes("000100"), 256, MaxScriptNumberLengthBeforeGenesis, false, nil},
{hexToBytes("ff7f00"), 32767, MaxScriptNumberLengthBeforeGenesis, false, nil},
{hexToBytes("00800000"), 32768, MaxScriptNumberLengthBeforeGenesis, false, nil},
{hexToBytes("ffff0000"), 65535, MaxScriptNumberLengthBeforeGenesis, false, nil},
{hexToBytes("00000800"), 524288, MaxScriptNumberLengthBeforeGenesis, false, nil},
{hexToBytes("00007000"), 7340032, MaxScriptNumberLengthBeforeGenesis, false, nil},
{hexToBytes("0009000100"), 16779520, 5, false, nil},
}

Expand Down
12 changes: 10 additions & 2 deletions bscript/interpreter/stack.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,17 @@ func fromBool(v bool) []byte {
// stack.
type stack struct {
stk [][]byte
maxNumLength int
verifyMinimalData bool
}

func newStack(cfg config, verifyMinimalData bool) stack {
return stack{
maxNumLength: cfg.MaxScriptNumberLength(),
verifyMinimalData: verifyMinimalData,
}
}

// Depth returns the number of items on the stack.
func (s *stack) Depth() int32 {
return int32(len(s.stk))
Expand Down Expand Up @@ -87,7 +95,7 @@ func (s *stack) PopInt() (scriptNum, error) {
return 0, err
}

return makeScriptNum(so, s.verifyMinimalData, defaultScriptNumLen)
return makeScriptNum(so, s.verifyMinimalData, s.maxNumLength)
}

// PopBool pops the value off the top of the stack, converts it into a bool, and
Expand Down Expand Up @@ -122,7 +130,7 @@ func (s *stack) PeekInt(idx int32) (scriptNum, error) {
return 0, err
}

return makeScriptNum(so, s.verifyMinimalData, defaultScriptNumLen)
return makeScriptNum(so, s.verifyMinimalData, s.maxNumLength)
}

// PeekBool returns the Nth item on the stack as a bool without removing it.
Expand Down
2 changes: 1 addition & 1 deletion bscript/interpreter/stack_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -905,7 +905,7 @@ func TestStack(t *testing.T) {

for _, test := range tests {
// Setup the initial stack state and perform the test operation.
s := stack{}
s := newStack(&beforeGenesisConfig{}, false)
for i := range test.before {
s.PushByteArray(test.before[i])
}
Expand Down
6 changes: 2 additions & 4 deletions bscript/interpreter/thread.go
Original file line number Diff line number Diff line change
Expand Up @@ -429,10 +429,8 @@ func (t *thread) apply(opts *execOpts) error {
t.bip16 = true
}

if t.hasFlag(scriptflag.VerifyMinimalData) {
t.dstack.verifyMinimalData = true
t.astack.verifyMinimalData = true
}
t.dstack = newStack(t.cfg, t.hasFlag(scriptflag.VerifyMinimalData))
t.astack = newStack(t.cfg, t.hasFlag(scriptflag.VerifyMinimalData))

if t.tx != nil {
t.tx.InputIdx(t.inputIdx).PreviousTxScript = t.prevOutput.LockingScript
Expand Down

0 comments on commit ea790cc

Please sign in to comment.