vm: add script check functions

These are required for future interops.
This commit is contained in:
Roman Khimov 2019-10-10 19:52:10 +03:00
parent 7ab58ff8cb
commit d007cc00cc
2 changed files with 325 additions and 0 deletions

98
pkg/vm/contract_checks.go Normal file
View file

@ -0,0 +1,98 @@
package vm
import (
"encoding/binary"
)
func getNumOfThingsFromInstr(instr Instruction, param []byte) (int, bool) {
var nthings int
switch instr {
case PUSH1, PUSH2, PUSH3, PUSH4, PUSH5, PUSH6, PUSH7, PUSH8,
PUSH9, PUSH10, PUSH11, PUSH12, PUSH13, PUSH14, PUSH15, PUSH16:
nthings = int(instr-PUSH1) + 1
case PUSHBYTES1:
nthings = int(param[0])
case 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 != 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 != CHECKMULTISIG {
return false
}
instr, _, err = ctx.Next()
if err != nil || instr != 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 != PUSHBYTES33 {
return false
}
instr, _, err = ctx.Next()
if err != nil || instr != CHECKSIG {
return false
}
instr, _, err = ctx.Next()
if err != nil || instr != 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)
}

View file

@ -0,0 +1,227 @@
package vm
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestIsSignatureContractGood(t *testing.T) {
prog := make([]byte, 35)
prog[0] = byte(PUSHBYTES33)
prog[34] = byte(CHECKSIG)
assert.Equal(t, true, IsSignatureContract(prog))
assert.Equal(t, true, IsStandardContract(prog))
}
func TestIsSignatureContractBadNoCheckSig(t *testing.T) {
prog := make([]byte, 34)
prog[0] = byte(PUSHBYTES33)
assert.Equal(t, false, IsSignatureContract(prog))
assert.Equal(t, false, IsStandardContract(prog))
}
func TestIsSignatureContractBadNoCheckSig2(t *testing.T) {
prog := make([]byte, 35)
prog[0] = byte(PUSHBYTES33)
prog[34] = byte(CHECKMULTISIG)
assert.Equal(t, false, IsSignatureContract(prog))
}
func TestIsSignatureContractBadWrongPush(t *testing.T) {
prog := make([]byte, 35)
prog[0] = byte(PUSHBYTES32)
prog[33] = byte(NOP)
prog[34] = byte(CHECKSIG)
assert.Equal(t, false, IsSignatureContract(prog))
}
func TestIsSignatureContractBadWrongInstr(t *testing.T) {
prog := make([]byte, 30)
prog[0] = byte(PUSHBYTES33)
assert.Equal(t, false, IsSignatureContract(prog))
}
func TestIsSignatureContractBadExcessiveInstr(t *testing.T) {
prog := make([]byte, 36)
prog[0] = byte(PUSHBYTES33)
prog[34] = byte(CHECKSIG)
prog[35] = byte(RET)
assert.Equal(t, false, IsSignatureContract(prog))
}
func TestIsMultiSigContractGood(t *testing.T) {
prog := make([]byte, 71)
prog[0] = byte(PUSH2)
prog[1] = byte(PUSHBYTES33)
prog[35] = byte(PUSHBYTES33)
prog[69] = byte(PUSH2)
prog[70] = byte(CHECKMULTISIG)
assert.Equal(t, true, IsMultiSigContract(prog))
assert.Equal(t, true, IsStandardContract(prog))
}
func TestIsMultiSigContractGoodPushBytes1(t *testing.T) {
prog := make([]byte, 73)
prog[0] = byte(PUSHBYTES1)
prog[1] = 2
prog[2] = byte(PUSHBYTES33)
prog[36] = byte(PUSHBYTES33)
prog[70] = byte(PUSHBYTES1)
prog[71] = 2
prog[72] = byte(CHECKMULTISIG)
assert.Equal(t, true, IsMultiSigContract(prog))
}
func TestIsMultiSigContractGoodPushBytes2(t *testing.T) {
prog := make([]byte, 75)
prog[0] = byte(PUSHBYTES2)
prog[1] = 2
prog[3] = byte(PUSHBYTES33)
prog[37] = byte(PUSHBYTES33)
prog[71] = byte(PUSHBYTES2)
prog[72] = 2
prog[74] = byte(CHECKMULTISIG)
assert.Equal(t, true, IsMultiSigContract(prog))
}
func TestIsMultiSigContractBadNSigs1(t *testing.T) {
prog := make([]byte, 71)
prog[0] = byte(PUSH0)
prog[1] = byte(PUSHBYTES33)
prog[35] = byte(PUSHBYTES33)
prog[69] = byte(PUSH2)
prog[70] = byte(CHECKMULTISIG)
assert.Equal(t, false, IsMultiSigContract(prog))
assert.Equal(t, false, IsStandardContract(prog))
}
func TestIsMultiSigContractBadNSigs2(t *testing.T) {
prog := make([]byte, 73)
prog[0] = byte(PUSHBYTES2)
prog[1] = 0xff
prog[2] = 0xff
prog[3] = byte(PUSHBYTES33)
prog[37] = byte(PUSHBYTES33)
prog[71] = byte(PUSH2)
prog[72] = byte(CHECKMULTISIG)
assert.Equal(t, false, IsMultiSigContract(prog))
}
func TestIsMultiSigContractBadNSigs3(t *testing.T) {
prog := make([]byte, 71)
prog[0] = byte(PUSH5)
prog[1] = byte(PUSHBYTES33)
prog[35] = byte(PUSHBYTES33)
prog[69] = byte(PUSH2)
prog[70] = byte(CHECKMULTISIG)
assert.Equal(t, false, IsMultiSigContract(prog))
}
func TestIsMultiSigContractBadExcessiveNOP1(t *testing.T) {
prog := make([]byte, 72)
prog[0] = byte(PUSH2)
prog[1] = byte(NOP)
prog[2] = byte(PUSHBYTES33)
prog[36] = byte(PUSHBYTES33)
prog[70] = byte(PUSH2)
prog[71] = byte(CHECKMULTISIG)
assert.Equal(t, false, IsMultiSigContract(prog))
}
func TestIsMultiSigContractBadExcessiveNOP2(t *testing.T) {
prog := make([]byte, 72)
prog[0] = byte(PUSH2)
prog[1] = byte(PUSHBYTES33)
prog[35] = byte(NOP)
prog[36] = byte(PUSHBYTES33)
prog[70] = byte(PUSH2)
prog[71] = byte(CHECKMULTISIG)
assert.Equal(t, false, IsMultiSigContract(prog))
}
func TestIsMultiSigContractBadExcessiveNOP3(t *testing.T) {
prog := make([]byte, 72)
prog[0] = byte(PUSH2)
prog[1] = byte(PUSHBYTES33)
prog[35] = byte(PUSHBYTES33)
prog[69] = byte(NOP)
prog[70] = byte(PUSH2)
prog[71] = byte(CHECKMULTISIG)
assert.Equal(t, false, IsMultiSigContract(prog))
}
func TestIsMultiSigContractBadExcessiveNOP4(t *testing.T) {
prog := make([]byte, 72)
prog[0] = byte(PUSH2)
prog[1] = byte(PUSHBYTES33)
prog[35] = byte(PUSHBYTES33)
prog[69] = byte(PUSH2)
prog[70] = byte(NOP)
prog[71] = byte(CHECKMULTISIG)
assert.Equal(t, false, IsMultiSigContract(prog))
}
func TestIsMultiSigContractBadExcessiveNOP5(t *testing.T) {
prog := make([]byte, 72)
prog[0] = byte(PUSH2)
prog[1] = byte(PUSHBYTES33)
prog[35] = byte(PUSHBYTES33)
prog[69] = byte(PUSH2)
prog[70] = byte(CHECKMULTISIG)
prog[71] = byte(NOP)
assert.Equal(t, false, IsMultiSigContract(prog))
}
func TestIsMultiSigContractBadNKeys1(t *testing.T) {
prog := make([]byte, 71)
prog[0] = byte(PUSH2)
prog[1] = byte(PUSHBYTES33)
prog[35] = byte(PUSHBYTES33)
prog[69] = byte(PUSH3)
prog[70] = byte(CHECKMULTISIG)
assert.Equal(t, false, IsMultiSigContract(prog))
}
func TestIsMultiSigContractBadNKeys2(t *testing.T) {
prog := make([]byte, 1)
prog[0] = byte(PUSH10)
key := make([]byte, 33)
var asize = uint16(MaxArraySize + 1)
for i := 0; i < int(asize); i++ {
prog = append(prog, byte(PUSHBYTES33))
prog = append(prog, key...)
}
prog = append(prog, byte(PUSHBYTES2), byte(asize&0xff), byte((asize<<8)&0xff), byte(CHECKMULTISIG))
assert.Equal(t, false, IsMultiSigContract(prog))
}
func TestIsMultiSigContractBadRead1(t *testing.T) {
prog := make([]byte, 71)
prog[0] = byte(PUSHBYTES75)
prog[1] = byte(PUSHBYTES33)
prog[35] = byte(PUSHBYTES33)
prog[69] = byte(PUSH2)
prog[70] = byte(CHECKMULTISIG)
assert.Equal(t, false, IsMultiSigContract(prog))
}
func TestIsMultiSigContractBadRead2(t *testing.T) {
prog := make([]byte, 71)
prog[0] = byte(PUSH2)
prog[1] = byte(PUSHBYTES33)
prog[35] = byte(PUSHBYTES75)
prog[69] = byte(PUSH2)
prog[70] = byte(CHECKMULTISIG)
assert.Equal(t, false, IsMultiSigContract(prog))
}
func TestIsMultiSigContractBadRead3(t *testing.T) {
prog := make([]byte, 71)
prog[0] = byte(PUSH2)
prog[1] = byte(PUSHBYTES33)
prog[35] = byte(PUSHBYTES33)
prog[69] = byte(PUSH2)
prog[70] = byte(PUSHBYTES1)
assert.Equal(t, false, IsMultiSigContract(prog))
}