neo-go/pkg/vm/contract_checks.go
Roman Khimov 8d4dd2d2e1 vm: move opcodes into their own package
This allows easier reuse of opcodes and in some cases allows to eliminate
dependencies on the whole vm package, like in compiler that only needs opcodes
and doesn't care about VM for any other purpose.

And yes, they're opcodes because an instruction is a whole thing with
operands, that's what context.Next() returns.
2019-12-03 18:22:14 +03:00

102 lines
2.3 KiB
Go

package vm
import (
"encoding/binary"
"github.com/CityOfZion/neo-go/pkg/vm/opcode"
)
func getNumOfThingsFromInstr(instr opcode.Opcode, param []byte) (int, bool) {
var nthings int
switch instr {
case opcode.PUSH1, opcode.PUSH2, opcode.PUSH3, opcode.PUSH4,
opcode.PUSH5, opcode.PUSH6, opcode.PUSH7, opcode.PUSH8,
opcode.PUSH9, opcode.PUSH10, opcode.PUSH11, opcode.PUSH12,
opcode.PUSH13, opcode.PUSH14, opcode.PUSH15, opcode.PUSH16:
nthings = int(instr-opcode.PUSH1) + 1
case opcode.PUSHBYTES1:
nthings = int(param[0])
case opcode.PUSHBYTES2:
nthings = int(binary.LittleEndian.Uint16(param))
default:
return 0, false
}
if nthings < 1 || nthings > MaxArraySize {
return 0, false
}
return nthings, true
}
// IsMultiSigContract checks whether the passed script is a multi-signature
// contract.
func IsMultiSigContract(script []byte) bool {
var nsigs, nkeys int
ctx := NewContext(script)
instr, param, err := ctx.Next()
if err != nil {
return false
}
nsigs, ok := getNumOfThingsFromInstr(instr, param)
if !ok {
return false
}
for {
instr, param, err = ctx.Next()
if err != nil {
return false
}
if instr != opcode.PUSHBYTES33 {
break
}
nkeys++
if nkeys > MaxArraySize {
return false
}
}
if nkeys < nsigs {
return false
}
nkeys2, ok := getNumOfThingsFromInstr(instr, param)
if !ok {
return false
}
if nkeys2 != nkeys {
return false
}
instr, _, err = ctx.Next()
if err != nil || instr != opcode.CHECKMULTISIG {
return false
}
instr, _, err = ctx.Next()
if err != nil || instr != opcode.RET || ctx.ip != len(script) {
return false
}
return true
}
// IsSignatureContract checks whether the passed script is a signature check
// contract.
func IsSignatureContract(script []byte) bool {
ctx := NewContext(script)
instr, _, err := ctx.Next()
if err != nil || instr != opcode.PUSHBYTES33 {
return false
}
instr, _, err = ctx.Next()
if err != nil || instr != opcode.CHECKSIG {
return false
}
instr, _, err = ctx.Next()
if err != nil || instr != opcode.RET || ctx.ip != len(script) {
return false
}
return true
}
// IsStandardContract checks whether the passed script is a signature or
// multi-signature contract.
func IsStandardContract(script []byte) bool {
return IsSignatureContract(script) || IsMultiSigContract(script)
}