Make opcode.Exec run a bunch of unconditional checks
Add push length and number of operations to this to match bitcoind behaviour. found that we differed here by their negative tests.
This commit is contained in:
parent
f80c3255a3
commit
8beb0dec54
2 changed files with 28 additions and 31 deletions
31
opcode.go
31
opcode.go
|
@ -932,17 +932,35 @@ func (pop *parsedOpcode) conditional() bool {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// exec peforms execution on the opcode. It takes into account whether or not
|
||||||
|
// it is hidden by conditionals, but some rules still must be tested in this
|
||||||
|
// case.
|
||||||
func (pop *parsedOpcode) exec(s *Script) error {
|
func (pop *parsedOpcode) exec(s *Script) error {
|
||||||
// *sigh* bitcoind pretty much mandates that we violate layering here.
|
// Disabled opcodes are ``fail on program counter''.
|
||||||
// Any opcode that isn't just adding data to the stack counts here
|
if pop.disabled() {
|
||||||
// as an operation. Note that OP_RESERVED is less than OP_16 and thus
|
return StackErrOpDisabled
|
||||||
// is counted as a push opcode here.
|
}
|
||||||
|
|
||||||
|
// Always-illegal opcodes are ``fail on program counter''.
|
||||||
|
if pop.alwaysIllegal() {
|
||||||
|
return StackErrAlwaysIllegal
|
||||||
|
}
|
||||||
|
|
||||||
|
// Note that this includes OP_RESERVED which counts as a push operation.
|
||||||
if pop.opcode.value > OP_16 {
|
if pop.opcode.value > OP_16 {
|
||||||
s.numOps++
|
s.numOps++
|
||||||
if s.numOps > MaxOpsPerScript {
|
if s.numOps > MaxOpsPerScript {
|
||||||
return StackErrTooManyOperations
|
return StackErrTooManyOperations
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} else if len(pop.data) > MaxScriptElementSize {
|
||||||
|
return StackErrElementTooBig
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we are not a conditional opcode and we aren't executing, then
|
||||||
|
// we are done now.
|
||||||
|
if s.condStack[0] != OpCondTrue && !pop.conditional() {
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
return pop.opcode.opfunc(pop, s)
|
return pop.opcode.opfunc(pop, s)
|
||||||
}
|
}
|
||||||
|
@ -1050,11 +1068,6 @@ func opcodeFalse(op *parsedOpcode, s *Script) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func opcodePushData(op *parsedOpcode, s *Script) error {
|
func opcodePushData(op *parsedOpcode, s *Script) error {
|
||||||
// This max script element test must occur at execution time instead
|
|
||||||
// of parse time to match bitcoind behaviour.
|
|
||||||
if len(op.data) > MaxScriptElementSize {
|
|
||||||
return StackErrElementTooBig
|
|
||||||
}
|
|
||||||
s.dstack.PushByteArray(op.data)
|
s.dstack.PushByteArray(op.data)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
28
script.go
28
script.go
|
@ -595,29 +595,13 @@ func (m *Script) Step() (done bool, err error) {
|
||||||
// verify that it is pointing to a valid script address
|
// verify that it is pointing to a valid script address
|
||||||
err = m.validPC()
|
err = m.validPC()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return true, err
|
||||||
}
|
}
|
||||||
opcode := m.scripts[m.scriptidx][m.scriptoff]
|
opcode := m.scripts[m.scriptidx][m.scriptoff]
|
||||||
|
|
||||||
executeInstr := true
|
err = opcode.exec(m)
|
||||||
if m.condStack[0] != OpCondTrue {
|
if err != nil {
|
||||||
// some opcodes still 'activate' if on the non-executing side
|
return true, err
|
||||||
// of conditional execution
|
|
||||||
if opcode.disabled() {
|
|
||||||
return true, StackErrOpDisabled
|
|
||||||
} else if opcode.alwaysIllegal() {
|
|
||||||
return true, StackErrAlwaysIllegal
|
|
||||||
} else if opcode.conditional() {
|
|
||||||
executeInstr = true
|
|
||||||
} else {
|
|
||||||
executeInstr = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if executeInstr {
|
|
||||||
err = opcode.exec(m)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// prepare for next instruction
|
// prepare for next instruction
|
||||||
|
@ -664,10 +648,10 @@ func (m *Script) Step() (done bool, err error) {
|
||||||
}
|
}
|
||||||
m.lastcodesep = 0
|
m.lastcodesep = 0
|
||||||
if m.scriptidx >= len(m.scripts) {
|
if m.scriptidx >= len(m.scripts) {
|
||||||
done = true
|
return true, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return
|
return false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// curPC returns either the current script and offset, or an error if the
|
// curPC returns either the current script and offset, or an error if the
|
||||||
|
|
Loading…
Add table
Reference in a new issue