import "bytes"
func opInvert(vm *virtualMachine) error {
- err := vm.applyCost(1)
- if err != nil {
+ if err := vm.applyCost(1); err != nil {
return err
}
+
top, err := vm.top()
if err != nil {
return err
}
- err = vm.applyCost(int64(len(top)))
- if err != nil {
+
+ if err = vm.applyCost(int64(len(top))); err != nil {
return err
}
// Could rewrite top in place but maybe it's a shared data
}
func opAnd(vm *virtualMachine) error {
- err := vm.applyCost(1)
- if err != nil {
+ if err := vm.applyCost(1); err != nil {
return err
}
+
b, err := vm.pop(true)
if err != nil {
return err
}
+
a, err := vm.pop(true)
if err != nil {
return err
}
+
min, max := len(a), len(b)
if min > max {
min, max = max, min
}
- err = vm.applyCost(int64(min))
- if err != nil {
+
+ if err = vm.applyCost(int64(min)); err != nil {
return err
}
+
res := make([]byte, 0, min)
for i := 0; i < min; i++ {
res = append(res, a[i]&b[i])
}
func doOr(vm *virtualMachine, xor bool) error {
- err := vm.applyCost(1)
- if err != nil {
+ if err := vm.applyCost(1); err != nil {
return err
}
+
b, err := vm.pop(true)
if err != nil {
return err
}
+
a, err := vm.pop(true)
if err != nil {
return err
}
+
min, max := len(a), len(b)
if min > max {
min, max = max, min
}
- err = vm.applyCost(int64(max))
- if err != nil {
+
+ if err = vm.applyCost(int64(max)); err != nil {
return err
}
+
res := make([]byte, 0, max)
for i := 0; i < max; i++ {
var aByte, bByte, resByte byte
if err != nil {
return err
}
+
return vm.pushBool(res, true)
}
if err != nil {
return err
}
+
if res {
return nil
}
}
func doEqual(vm *virtualMachine) (bool, error) {
- err := vm.applyCost(1)
- if err != nil {
+ if err := vm.applyCost(1); err != nil {
return false, err
}
+
b, err := vm.pop(true)
if err != nil {
return false, err
}
+
a, err := vm.pop(true)
if err != nil {
return false, err
}
+
min, max := len(a), len(b)
if min > max {
min, max = max, min
}
- err = vm.applyCost(int64(min))
- if err != nil {
+
+ if err = vm.applyCost(int64(min)); err != nil {
return false, err
}
return bytes.Equal(a, b), nil
)
func opVerify(vm *virtualMachine) error {
- err := vm.applyCost(1)
- if err != nil {
+ if err := vm.applyCost(1); err != nil {
return err
}
+
p, err := vm.pop(true)
if err != nil {
return err
}
+
if AsBool(p) {
return nil
}
}
func opFail(vm *virtualMachine) error {
- err := vm.applyCost(1)
- if err != nil {
+ if err := vm.applyCost(1); err != nil {
return err
}
+
return ErrReturn
}
}
func opJump(vm *virtualMachine) error {
- err := vm.applyCost(1)
- if err != nil {
+ if err := vm.applyCost(1); err != nil {
return err
}
+
address := binary.LittleEndian.Uint32(vm.data)
vm.nextPC = address
return nil
}
func opJumpIf(vm *virtualMachine) error {
- err := vm.applyCost(1)
- if err != nil {
+ if err := vm.applyCost(1); err != nil {
return err
}
+
p, err := vm.pop(true)
if err != nil {
return err
}
+
if AsBool(p) {
address := binary.LittleEndian.Uint32(vm.data)
vm.nextPC = address
if err != nil {
return err
}
+
cost := int64(len(x))
if cost < 64 {
cost = 64
}
- err = vm.applyCost(cost)
- if err != nil {
+
+ if err = vm.applyCost(cost); err != nil {
return err
}
+
h := hashFactory()
- _, err = h.Write(x)
- if err != nil {
+ if _, err = h.Write(x); err != nil {
return err
}
return vm.pushDataStack(h.Sum(nil), false)
}
func opCheckSig(vm *virtualMachine) error {
- err := vm.applyCost(1024)
- if err != nil {
+ if err := vm.applyCost(1024); err != nil {
return err
}
+
pubkeyBytes, err := vm.pop(true)
if err != nil {
return err
}
+
msg, err := vm.pop(true)
if err != nil {
return err
}
+
sig, err := vm.pop(true)
if err != nil {
return err
}
+
if len(msg) != 32 {
return ErrBadValue
}
+
if len(pubkeyBytes) != ed25519.PublicKeySize {
return vm.pushBool(false, true)
}
if numSigs < 0 || numSigs > numPubkeys || (numPubkeys > 0 && numSigs == 0) {
return ErrBadValue
}
+
pubkeyByteses := make([][]byte, 0, numPubkeys)
for i := int64(0); i < numPubkeys; i++ {
pubkeyBytes, err := vm.pop(true)
}
pubkeyByteses = append(pubkeyByteses, pubkeyBytes)
}
+
msg, err := vm.pop(true)
if err != nil {
return err
}
+
if len(msg) != 32 {
return ErrBadValue
}
+
sigs := make([][]byte, 0, numSigs)
for i := int64(0); i < numSigs; i++ {
sig, err := vm.pop(true)
}
pubkeys = pubkeys[1:]
}
+
return vm.pushBool(len(sigs) == 0, true)
}
func opTxSigHash(vm *virtualMachine) error {
- err := vm.applyCost(256)
- if err != nil {
+ if err := vm.applyCost(256); err != nil {
return err
}
+
if vm.context.TxSigHash == nil {
return ErrContext
}
+
return vm.pushDataStack(vm.context.TxSigHash(), false)
}
if err != nil {
return err
}
+
amountInt, err := vm.popBigInt(true)
if err != nil {
return err
}
func opAsset(vm *virtualMachine) error {
- err := vm.applyCost(1)
- if err != nil {
+ if err := vm.applyCost(1); err != nil {
return err
}
}
func opAmount(vm *virtualMachine) error {
- err := vm.applyCost(1)
- if err != nil {
+ if err := vm.applyCost(1); err != nil {
return err
}
}
func opProgram(vm *virtualMachine) error {
- err := vm.applyCost(1)
- if err != nil {
+ if err := vm.applyCost(1); err != nil {
return err
}
}
func opEntryID(vm *virtualMachine) error {
- err := vm.applyCost(1)
- if err != nil {
+ if err := vm.applyCost(1); err != nil {
return err
}
return vm.pushDataStack(vm.context.EntryID, true)
}
func opOutputID(vm *virtualMachine) error {
- err := vm.applyCost(1)
- if err != nil {
+ if err := vm.applyCost(1); err != nil {
return err
}
}
func opBlockHeight(vm *virtualMachine) error {
- err := vm.applyCost(1)
- if err != nil {
+ if err := vm.applyCost(1); err != nil {
return err
}
import (
"github.com/holiman/uint256"
-
- "github.com/bytom/bytom/math/checked"
)
func op1Add(vm *virtualMachine) error {
- err := vm.applyCost(2)
- if err != nil {
+ if err := vm.applyCost(2); err != nil {
return err
}
return err
}
- num, ok := checked.NewUInt256("1")
- if !ok {
- return ErrBadValue
- }
-
+ num := uint256.NewInt().SetUint64(1)
if num.Add(n, num); num.Sign() < 0 {
return ErrRange
}
}
func op1Sub(vm *virtualMachine) error {
- err := vm.applyCost(2)
- if err != nil {
+ if err := vm.applyCost(2); err != nil {
return err
}
return err
}
- num, ok := checked.NewUInt256("1")
- if !ok {
- return ErrBadValue
- }
-
+ num := uint256.NewInt().SetUint64(1)
if num.Sub(n, num); num.Sign() < 0 {
return ErrRange
}
}
func op2Mul(vm *virtualMachine) error {
- err := vm.applyCost(2)
- if err != nil {
+ if err := vm.applyCost(2); err != nil {
return err
}
return err
}
- num, ok := checked.NewUInt256("2")
- if !ok {
- return ErrBadValue
- }
-
+ num := uint256.NewInt().SetUint64(2)
if num.Mul(n, num); num.Sign() < 0 {
return ErrRange
}
}
func opNot(vm *virtualMachine) error {
- err := vm.applyCost(2)
- if err != nil {
+ if err := vm.applyCost(2); err != nil {
return err
}
}
func op0NotEqual(vm *virtualMachine) error {
- err := vm.applyCost(2)
- if err != nil {
+ if err := vm.applyCost(2); err != nil {
return err
}
}
func opAdd(vm *virtualMachine) error {
- err := vm.applyCost(2)
- if err != nil {
+ if err := vm.applyCost(2); err != nil {
return err
}
}
func opSub(vm *virtualMachine) error {
- err := vm.applyCost(2)
- if err != nil {
+ if err := vm.applyCost(2); err != nil {
return err
}
}
func opMul(vm *virtualMachine) error {
- err := vm.applyCost(8)
- if err != nil {
+ if err := vm.applyCost(8); err != nil {
return err
}
}
func opDiv(vm *virtualMachine) error {
- err := vm.applyCost(8)
- if err != nil {
+ if err := vm.applyCost(8); err != nil {
return err
}
}
func opMod(vm *virtualMachine) error {
- err := vm.applyCost(8)
- if err != nil {
+ if err := vm.applyCost(8); err != nil {
return err
}
}
func opLshift(vm *virtualMachine) error {
- err := vm.applyCost(8)
- if err != nil {
+ if err := vm.applyCost(8); err != nil {
return err
}
}
func opRshift(vm *virtualMachine) error {
- err := vm.applyCost(8)
- if err != nil {
+ if err := vm.applyCost(8); err != nil {
return err
}
}
func opBoolAnd(vm *virtualMachine) error {
- err := vm.applyCost(2)
- if err != nil {
+ if err := vm.applyCost(2); err != nil {
return err
}
+
b, err := vm.pop(true)
if err != nil {
return err
}
+
a, err := vm.pop(true)
if err != nil {
return err
}
func opBoolOr(vm *virtualMachine) error {
- err := vm.applyCost(2)
- if err != nil {
+ if err := vm.applyCost(2); err != nil {
return err
}
+
b, err := vm.pop(true)
if err != nil {
return err
}
+
a, err := vm.pop(true)
if err != nil {
return err
}
func opNumEqualVerify(vm *virtualMachine) error {
- err := vm.applyCost(2)
- if err != nil {
+ if err := vm.applyCost(2); err != nil {
return err
}
}
func doNumCompare(vm *virtualMachine, op int) error {
- err := vm.applyCost(2)
- if err != nil {
+ if err := vm.applyCost(2); err != nil {
return err
}
+
y, err := vm.popBigInt(true)
if err != nil {
return err
}
+
x, err := vm.popBigInt(true)
if err != nil {
return err
}
+
var res bool
switch op {
case cmpLess:
}
func opMin(vm *virtualMachine) error {
- err := vm.applyCost(2)
- if err != nil {
+ if err := vm.applyCost(2); err != nil {
return err
}
}
func opMax(vm *virtualMachine) error {
- err := vm.applyCost(2)
- if err != nil {
+ if err := vm.applyCost(2); err != nil {
return err
}
}
func opWithin(vm *virtualMachine) error {
- err := vm.applyCost(4)
- if err != nil {
+ if err := vm.applyCost(4); err != nil {
return err
}
+
max, err := vm.popBigInt(true)
if err != nil {
return err
OP_PUSHDATA1 Op = 0x4c
OP_PUSHDATA2 Op = 0x4d
OP_PUSHDATA4 Op = 0x4e
- OP_1NEGATE Op = 0x4f
OP_NOP Op = 0x61
OP_JUMP Op = 0x63
// ParseOp parses the op at position pc in prog, returning the parsed
// instruction (opcode plus any associated data).
func ParseOp(prog []byte, pc uint32) (inst Instruction, err error) {
- if len(prog) > math.MaxInt32 {
- err = ErrLongProgram
- }
l := uint32(len(prog))
+ if l > math.MaxInt32 {
+ return inst, ErrLongProgram
+ }
+
if pc >= l {
- err = ErrShortProgram
- return
+ return inst, ErrShortProgram
}
+
opcode := Op(prog[pc])
inst.Op = opcode
inst.Len = 1
inst.Data = []byte{uint8(opcode-OP_1) + 1}
return
}
+
if opcode >= OP_DATA_1 && opcode <= OP_DATA_75 {
inst.Len += uint32(opcode - OP_DATA_1 + 1)
end, ok := checked.AddUint32(pc, inst.Len)
if !ok {
- err = errors.WithDetail(checked.ErrOverflow, "data length exceeds max program size")
- return
+ return inst, errors.WithDetail(checked.ErrOverflow, "data length exceeds max program size")
}
+
if end > l {
- err = ErrShortProgram
- return
+ return inst, ErrShortProgram
}
+
inst.Data = prog[pc+1 : end]
return
}
+
if opcode == OP_PUSHDATA1 {
if pc == l-1 {
- err = ErrShortProgram
- return
+ return inst, ErrShortProgram
}
+
n := prog[pc+1]
inst.Len += uint32(n) + 1
end, ok := checked.AddUint32(pc, inst.Len)
if !ok {
- err = errors.WithDetail(checked.ErrOverflow, "data length exceeds max program size")
+ return inst, errors.WithDetail(checked.ErrOverflow, "data length exceeds max program size")
}
+
if end > l {
- err = ErrShortProgram
- return
+ return inst, ErrShortProgram
}
+
inst.Data = prog[pc+2 : end]
return
}
+
if opcode == OP_PUSHDATA2 {
if len(prog) < 3 || pc > l-3 {
- err = ErrShortProgram
- return
+ return inst, ErrShortProgram
}
+
n := binary.LittleEndian.Uint16(prog[pc+1 : pc+3])
inst.Len += uint32(n) + 2
end, ok := checked.AddUint32(pc, inst.Len)
if !ok {
- err = errors.WithDetail(checked.ErrOverflow, "data length exceeds max program size")
- return
+ return inst, errors.WithDetail(checked.ErrOverflow, "data length exceeds max program size")
}
+
if end > l {
- err = ErrShortProgram
- return
+ return inst, ErrShortProgram
}
+
inst.Data = prog[pc+3 : end]
return
}
+
if opcode == OP_PUSHDATA4 {
if len(prog) < 5 || pc > l-5 {
- err = ErrShortProgram
- return
+ return inst, ErrShortProgram
}
- inst.Len += 4
+ inst.Len += 4
n := binary.LittleEndian.Uint32(prog[pc+1 : pc+5])
var ok bool
inst.Len, ok = checked.AddUint32(inst.Len, n)
if !ok {
- err = errors.WithDetail(checked.ErrOverflow, "data length exceeds max program size")
- return
+ return inst, errors.WithDetail(checked.ErrOverflow, "data length exceeds max program size")
}
+
end, ok := checked.AddUint32(pc, inst.Len)
if !ok {
- err = errors.WithDetail(checked.ErrOverflow, "data length exceeds max program size")
- return
+ return inst, errors.WithDetail(checked.ErrOverflow, "data length exceeds max program size")
}
+
if end > l {
- err = ErrShortProgram
- return
+ return inst, ErrShortProgram
}
+
inst.Data = prog[pc+5 : end]
return
}
+
if opcode == OP_JUMP || opcode == OP_JUMPIF {
inst.Len += 4
end, ok := checked.AddUint32(pc, inst.Len)
if !ok {
- err = errors.WithDetail(checked.ErrOverflow, "jump target exceeds max program size")
- return
+ return inst, errors.WithDetail(checked.ErrOverflow, "jump target exceeds max program size")
}
+
if end > l {
- err = ErrShortProgram
- return
+ return inst, ErrShortProgram
}
+
inst.Data = prog[pc+1 : end]
return
}
if err != nil {
return nil, err
}
+
result = append(result, inst)
var ok bool
pc, ok = checked.AddUint32(pc, inst.Len)
// IsPushdata judge instruction whether is a pushdata operation(include opFalse operation)
func (inst *Instruction) IsPushdata() bool {
- if reflect.ValueOf(ops[inst.Op].fn) == reflect.ValueOf(ops[OP_1].fn) ||
- reflect.ValueOf(ops[inst.Op].fn) == reflect.ValueOf(ops[OP_0].fn) {
- return true
- }
-
- return false
+ return reflect.ValueOf(ops[inst.Op].fn) == reflect.ValueOf(ops[OP_1].fn) || reflect.ValueOf(ops[inst.Op].fn) == reflect.ValueOf(ops[OP_0].fn)
}
})
}
- pushops := append(pushdataops, OP_FALSE, OP_1NEGATE, OP_NOP)
+ pushops := append(pushdataops, OP_FALSE, OP_NOP)
for _, op := range pushops {
cases = append(cases, testStruct{
op: op,
builder.AddOp(vm.OP_BLOCKHEIGHT)
builder.AddOp(vm.OP_GREATERTHAN)
builder.AddOp(vm.OP_VERIFY)
- } else if blockHeight < 0 {
- return nil, errors.WithDetail(ErrBadValue, "negative blockHeight")
}
+
if err := builder.addP2SPMultiSig(pubkeys, nrequired); err != nil {
return nil, err
}