|
|
|
@ -1,12 +1,12 @@ |
|
|
|
|
package ethchain |
|
|
|
|
|
|
|
|
|
import ( |
|
|
|
|
"bytes" |
|
|
|
|
"fmt" |
|
|
|
|
_ "bytes" |
|
|
|
|
_ "fmt" |
|
|
|
|
"github.com/ethereum/eth-go/ethutil" |
|
|
|
|
"github.com/obscuren/secp256k1-go" |
|
|
|
|
_ "github.com/obscuren/secp256k1-go" |
|
|
|
|
"log" |
|
|
|
|
"math" |
|
|
|
|
_ "math" |
|
|
|
|
"math/big" |
|
|
|
|
) |
|
|
|
|
|
|
|
|
@ -18,122 +18,102 @@ type Vm struct { |
|
|
|
|
mem map[string]*big.Int |
|
|
|
|
|
|
|
|
|
vars RuntimeVars |
|
|
|
|
|
|
|
|
|
state *State |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
type RuntimeVars struct { |
|
|
|
|
address []byte |
|
|
|
|
origin []byte |
|
|
|
|
blockNumber uint64 |
|
|
|
|
sender []byte |
|
|
|
|
prevHash []byte |
|
|
|
|
coinbase []byte |
|
|
|
|
time int64 |
|
|
|
|
diff *big.Int |
|
|
|
|
txValue *big.Int |
|
|
|
|
txData []string |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (vm *Vm) Process(contract *Contract, state *State, vars RuntimeVars) { |
|
|
|
|
vm.mem = make(map[string]*big.Int) |
|
|
|
|
vm.stack = NewStack() |
|
|
|
|
func NewVm(state *State, vars RuntimeVars) *Vm { |
|
|
|
|
return &Vm{vars: vars, state: state} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
addr := vars.address // tx.Hash()[12:]
|
|
|
|
|
// Instruction pointer
|
|
|
|
|
pc := 0 |
|
|
|
|
var Pow256 = ethutil.BigPow(2, 256) |
|
|
|
|
|
|
|
|
|
if contract == nil { |
|
|
|
|
fmt.Println("Contract not found") |
|
|
|
|
return |
|
|
|
|
func (vm *Vm) RunClosure(closure *Closure) []byte { |
|
|
|
|
// If the amount of gas supplied is less equal to 0
|
|
|
|
|
if closure.Gas.Cmp(big.NewInt(0)) <= 0 { |
|
|
|
|
// TODO Do something
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
Pow256 := ethutil.BigPow(2, 256) |
|
|
|
|
// Memory for the current closure
|
|
|
|
|
mem := &Memory{} |
|
|
|
|
// New stack (should this be shared?)
|
|
|
|
|
stack := NewStack() |
|
|
|
|
// Instruction pointer
|
|
|
|
|
pc := big.NewInt(0) |
|
|
|
|
// Current step count
|
|
|
|
|
step := 0 |
|
|
|
|
// The base for all big integer arithmetic
|
|
|
|
|
base := new(big.Int) |
|
|
|
|
|
|
|
|
|
if ethutil.Config.Debug { |
|
|
|
|
ethutil.Config.Log.Debugf("# op\n") |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
stepcount := 0 |
|
|
|
|
totalFee := new(big.Int) |
|
|
|
|
|
|
|
|
|
out: |
|
|
|
|
for { |
|
|
|
|
stepcount++ |
|
|
|
|
// The base big int for all calculations. Use this for any results.
|
|
|
|
|
base := new(big.Int) |
|
|
|
|
val := contract.GetMem(pc) |
|
|
|
|
//fmt.Printf("%x = %d, %v %x\n", r, len(r), v, nb)
|
|
|
|
|
step++ |
|
|
|
|
// Get the memory location of pc
|
|
|
|
|
val := closure.GetMem(pc) |
|
|
|
|
// Get the opcode (it must be an opcode!)
|
|
|
|
|
op := OpCode(val.Uint()) |
|
|
|
|
|
|
|
|
|
var fee *big.Int = new(big.Int) |
|
|
|
|
var fee2 *big.Int = new(big.Int) |
|
|
|
|
if stepcount > 16 { |
|
|
|
|
fee.Add(fee, StepFee) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Calculate the fees
|
|
|
|
|
switch op { |
|
|
|
|
case oSSTORE: |
|
|
|
|
y, x := vm.stack.Peekn() |
|
|
|
|
val := contract.Addr(ethutil.BigToBytes(x, 256)) |
|
|
|
|
if val.IsEmpty() && len(y.Bytes()) > 0 { |
|
|
|
|
fee2.Add(DataFee, StoreFee) |
|
|
|
|
} else { |
|
|
|
|
fee2.Sub(DataFee, StoreFee) |
|
|
|
|
} |
|
|
|
|
case oSLOAD: |
|
|
|
|
fee.Add(fee, StoreFee) |
|
|
|
|
case oEXTRO, oBALANCE: |
|
|
|
|
fee.Add(fee, ExtroFee) |
|
|
|
|
case oSHA256, oRIPEMD160, oECMUL, oECADD, oECSIGN, oECRECOVER, oECVALID: |
|
|
|
|
fee.Add(fee, CryptoFee) |
|
|
|
|
case oMKTX: |
|
|
|
|
fee.Add(fee, ContractFee) |
|
|
|
|
if ethutil.Config.Debug { |
|
|
|
|
ethutil.Config.Log.Debugf("%-3d %-4s", pc, op.String()) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
tf := new(big.Int).Add(fee, fee2) |
|
|
|
|
if contract.Amount.Cmp(tf) < 0 { |
|
|
|
|
fmt.Println("Insufficient fees to continue running the contract", tf, contract.Amount) |
|
|
|
|
break |
|
|
|
|
} |
|
|
|
|
// Add the fee to the total fee. It's subtracted when we're done looping
|
|
|
|
|
totalFee.Add(totalFee, tf) |
|
|
|
|
// TODO Get each instruction cost properly
|
|
|
|
|
fee := new(big.Int) |
|
|
|
|
fee.Add(fee, big.NewInt(1000)) |
|
|
|
|
|
|
|
|
|
if ethutil.Config.Debug { |
|
|
|
|
ethutil.Config.Log.Debugf("%-3d %-4s", pc, op.String()) |
|
|
|
|
if closure.Gas.Cmp(fee) < 0 { |
|
|
|
|
return closure.Return(nil) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
switch op { |
|
|
|
|
case oSTOP: |
|
|
|
|
fmt.Println("") |
|
|
|
|
break out |
|
|
|
|
case oLOG: |
|
|
|
|
stack.Print() |
|
|
|
|
mem.Print() |
|
|
|
|
case oSTOP: // Stop the closure
|
|
|
|
|
return closure.Return(nil) |
|
|
|
|
|
|
|
|
|
// 0x20 range
|
|
|
|
|
case oADD: |
|
|
|
|
x, y := vm.stack.Popn() |
|
|
|
|
x, y := stack.Popn() |
|
|
|
|
// (x + y) % 2 ** 256
|
|
|
|
|
base.Add(x, y) |
|
|
|
|
base.Mod(base, Pow256) |
|
|
|
|
// Pop result back on the stack
|
|
|
|
|
vm.stack.Push(base) |
|
|
|
|
stack.Push(base) |
|
|
|
|
case oSUB: |
|
|
|
|
x, y := vm.stack.Popn() |
|
|
|
|
x, y := stack.Popn() |
|
|
|
|
// (x - y) % 2 ** 256
|
|
|
|
|
base.Sub(x, y) |
|
|
|
|
base.Mod(base, Pow256) |
|
|
|
|
// Pop result back on the stack
|
|
|
|
|
vm.stack.Push(base) |
|
|
|
|
stack.Push(base) |
|
|
|
|
case oMUL: |
|
|
|
|
x, y := vm.stack.Popn() |
|
|
|
|
x, y := stack.Popn() |
|
|
|
|
// (x * y) % 2 ** 256
|
|
|
|
|
base.Mul(x, y) |
|
|
|
|
base.Mod(base, Pow256) |
|
|
|
|
// Pop result back on the stack
|
|
|
|
|
vm.stack.Push(base) |
|
|
|
|
stack.Push(base) |
|
|
|
|
case oDIV: |
|
|
|
|
x, y := vm.stack.Popn() |
|
|
|
|
x, y := stack.Popn() |
|
|
|
|
// floor(x / y)
|
|
|
|
|
base.Div(x, y) |
|
|
|
|
// Pop result back on the stack
|
|
|
|
|
vm.stack.Push(base) |
|
|
|
|
stack.Push(base) |
|
|
|
|
case oSDIV: |
|
|
|
|
x, y := vm.stack.Popn() |
|
|
|
|
x, y := stack.Popn() |
|
|
|
|
// n > 2**255
|
|
|
|
|
if x.Cmp(Pow256) > 0 { |
|
|
|
|
x.Sub(Pow256, x) |
|
|
|
@ -147,13 +127,13 @@ out: |
|
|
|
|
z.Sub(Pow256, z) |
|
|
|
|
} |
|
|
|
|
// Push result on to the stack
|
|
|
|
|
vm.stack.Push(z) |
|
|
|
|
stack.Push(z) |
|
|
|
|
case oMOD: |
|
|
|
|
x, y := vm.stack.Popn() |
|
|
|
|
x, y := stack.Popn() |
|
|
|
|
base.Mod(x, y) |
|
|
|
|
vm.stack.Push(base) |
|
|
|
|
stack.Push(base) |
|
|
|
|
case oSMOD: |
|
|
|
|
x, y := vm.stack.Popn() |
|
|
|
|
x, y := stack.Popn() |
|
|
|
|
// n > 2**255
|
|
|
|
|
if x.Cmp(Pow256) > 0 { |
|
|
|
|
x.Sub(Pow256, x) |
|
|
|
@ -167,250 +147,189 @@ out: |
|
|
|
|
z.Sub(Pow256, z) |
|
|
|
|
} |
|
|
|
|
// Push result on to the stack
|
|
|
|
|
vm.stack.Push(z) |
|
|
|
|
stack.Push(z) |
|
|
|
|
case oEXP: |
|
|
|
|
x, y := vm.stack.Popn() |
|
|
|
|
x, y := stack.Popn() |
|
|
|
|
base.Exp(x, y, Pow256) |
|
|
|
|
|
|
|
|
|
vm.stack.Push(base) |
|
|
|
|
stack.Push(base) |
|
|
|
|
case oNEG: |
|
|
|
|
base.Sub(Pow256, vm.stack.Pop()) |
|
|
|
|
vm.stack.Push(base) |
|
|
|
|
base.Sub(Pow256, stack.Pop()) |
|
|
|
|
stack.Push(base) |
|
|
|
|
case oLT: |
|
|
|
|
x, y := vm.stack.Popn() |
|
|
|
|
x, y := stack.Popn() |
|
|
|
|
// x < y
|
|
|
|
|
if x.Cmp(y) < 0 { |
|
|
|
|
vm.stack.Push(ethutil.BigTrue) |
|
|
|
|
} else { |
|
|
|
|
vm.stack.Push(ethutil.BigFalse) |
|
|
|
|
} |
|
|
|
|
case oLE: |
|
|
|
|
x, y := vm.stack.Popn() |
|
|
|
|
// x <= y
|
|
|
|
|
if x.Cmp(y) < 1 { |
|
|
|
|
vm.stack.Push(ethutil.BigTrue) |
|
|
|
|
stack.Push(ethutil.BigTrue) |
|
|
|
|
} else { |
|
|
|
|
vm.stack.Push(ethutil.BigFalse) |
|
|
|
|
stack.Push(ethutil.BigFalse) |
|
|
|
|
} |
|
|
|
|
case oGT: |
|
|
|
|
x, y := vm.stack.Popn() |
|
|
|
|
x, y := stack.Popn() |
|
|
|
|
// x > y
|
|
|
|
|
if x.Cmp(y) > 0 { |
|
|
|
|
vm.stack.Push(ethutil.BigTrue) |
|
|
|
|
} else { |
|
|
|
|
vm.stack.Push(ethutil.BigFalse) |
|
|
|
|
} |
|
|
|
|
case oGE: |
|
|
|
|
x, y := vm.stack.Popn() |
|
|
|
|
// x >= y
|
|
|
|
|
if x.Cmp(y) > -1 { |
|
|
|
|
vm.stack.Push(ethutil.BigTrue) |
|
|
|
|
stack.Push(ethutil.BigTrue) |
|
|
|
|
} else { |
|
|
|
|
vm.stack.Push(ethutil.BigFalse) |
|
|
|
|
stack.Push(ethutil.BigFalse) |
|
|
|
|
} |
|
|
|
|
case oNOT: |
|
|
|
|
x, y := vm.stack.Popn() |
|
|
|
|
x, y := stack.Popn() |
|
|
|
|
// x != y
|
|
|
|
|
if x.Cmp(y) != 0 { |
|
|
|
|
vm.stack.Push(ethutil.BigTrue) |
|
|
|
|
stack.Push(ethutil.BigTrue) |
|
|
|
|
} else { |
|
|
|
|
vm.stack.Push(ethutil.BigFalse) |
|
|
|
|
stack.Push(ethutil.BigFalse) |
|
|
|
|
} |
|
|
|
|
case oMYADDRESS: |
|
|
|
|
vm.stack.Push(ethutil.BigD(addr)) |
|
|
|
|
case oTXSENDER: |
|
|
|
|
vm.stack.Push(ethutil.BigD(vars.sender)) |
|
|
|
|
case oTXVALUE: |
|
|
|
|
vm.stack.Push(vars.txValue) |
|
|
|
|
case oTXDATAN: |
|
|
|
|
vm.stack.Push(big.NewInt(int64(len(vars.txData)))) |
|
|
|
|
case oTXDATA: |
|
|
|
|
v := vm.stack.Pop() |
|
|
|
|
// v >= len(data)
|
|
|
|
|
if v.Cmp(big.NewInt(int64(len(vars.txData)))) >= 0 { |
|
|
|
|
vm.stack.Push(ethutil.Big("0")) |
|
|
|
|
} else { |
|
|
|
|
vm.stack.Push(ethutil.Big(vars.txData[v.Uint64()])) |
|
|
|
|
} |
|
|
|
|
case oBLK_PREVHASH: |
|
|
|
|
vm.stack.Push(ethutil.BigD(vars.prevHash)) |
|
|
|
|
case oBLK_COINBASE: |
|
|
|
|
vm.stack.Push(ethutil.BigD(vars.coinbase)) |
|
|
|
|
case oBLK_TIMESTAMP: |
|
|
|
|
vm.stack.Push(big.NewInt(vars.time)) |
|
|
|
|
case oBLK_NUMBER: |
|
|
|
|
vm.stack.Push(big.NewInt(int64(vars.blockNumber))) |
|
|
|
|
case oBLK_DIFFICULTY: |
|
|
|
|
vm.stack.Push(vars.diff) |
|
|
|
|
case oBASEFEE: |
|
|
|
|
// e = 10^21
|
|
|
|
|
e := big.NewInt(0).Exp(big.NewInt(10), big.NewInt(21), big.NewInt(0)) |
|
|
|
|
d := new(big.Rat) |
|
|
|
|
d.SetInt(vars.diff) |
|
|
|
|
c := new(big.Rat) |
|
|
|
|
c.SetFloat64(0.5) |
|
|
|
|
// d = diff / 0.5
|
|
|
|
|
d.Quo(d, c) |
|
|
|
|
// base = floor(d)
|
|
|
|
|
base.Div(d.Num(), d.Denom()) |
|
|
|
|
|
|
|
|
|
x := new(big.Int) |
|
|
|
|
x.Div(e, base) |
|
|
|
|
// 0x10 range
|
|
|
|
|
case oAND: |
|
|
|
|
case oOR: |
|
|
|
|
case oXOR: |
|
|
|
|
case oBYTE: |
|
|
|
|
|
|
|
|
|
// x = floor(10^21 / floor(diff^0.5))
|
|
|
|
|
vm.stack.Push(x) |
|
|
|
|
case oSHA256, oSHA3, oRIPEMD160: |
|
|
|
|
// This is probably save
|
|
|
|
|
// ceil(pop / 32)
|
|
|
|
|
length := int(math.Ceil(float64(vm.stack.Pop().Uint64()) / 32.0)) |
|
|
|
|
// New buffer which will contain the concatenated popped items
|
|
|
|
|
data := new(bytes.Buffer) |
|
|
|
|
for i := 0; i < length; i++ { |
|
|
|
|
// Encode the number to bytes and have it 32bytes long
|
|
|
|
|
num := ethutil.NumberToBytes(vm.stack.Pop().Bytes(), 256) |
|
|
|
|
data.WriteString(string(num)) |
|
|
|
|
} |
|
|
|
|
// 0x20 range
|
|
|
|
|
case oSHA3: |
|
|
|
|
|
|
|
|
|
if op == oSHA256 { |
|
|
|
|
vm.stack.Push(base.SetBytes(ethutil.Sha256Bin(data.Bytes()))) |
|
|
|
|
} else if op == oSHA3 { |
|
|
|
|
vm.stack.Push(base.SetBytes(ethutil.Sha3Bin(data.Bytes()))) |
|
|
|
|
} else { |
|
|
|
|
vm.stack.Push(base.SetBytes(ethutil.Ripemd160(data.Bytes()))) |
|
|
|
|
} |
|
|
|
|
case oECMUL: |
|
|
|
|
y := vm.stack.Pop() |
|
|
|
|
x := vm.stack.Pop() |
|
|
|
|
//n := vm.stack.Pop()
|
|
|
|
|
// 0x30 range
|
|
|
|
|
case oADDRESS: |
|
|
|
|
stack.Push(ethutil.BigD(closure.Object().Address())) |
|
|
|
|
case oBALANCE: |
|
|
|
|
stack.Push(closure.Value) |
|
|
|
|
case oORIGIN: |
|
|
|
|
stack.Push(ethutil.BigD(vm.vars.origin)) |
|
|
|
|
case oCALLER: |
|
|
|
|
stack.Push(ethutil.BigD(closure.Callee().Address())) |
|
|
|
|
case oCALLVALUE: |
|
|
|
|
// FIXME: Original value of the call, not the current value
|
|
|
|
|
stack.Push(closure.Value) |
|
|
|
|
case oCALLDATA: |
|
|
|
|
offset := stack.Pop() |
|
|
|
|
mem.Set(offset.Int64(), int64(len(closure.Args)), closure.Args) |
|
|
|
|
case oCALLDATASIZE: |
|
|
|
|
stack.Push(big.NewInt(int64(len(closure.Args)))) |
|
|
|
|
case oGASPRICE: |
|
|
|
|
// TODO
|
|
|
|
|
|
|
|
|
|
//if ethutil.Big(x).Cmp(ethutil.Big(y)) {
|
|
|
|
|
data := new(bytes.Buffer) |
|
|
|
|
data.WriteString(x.String()) |
|
|
|
|
data.WriteString(y.String()) |
|
|
|
|
if secp256k1.VerifyPubkeyValidity(data.Bytes()) == 1 { |
|
|
|
|
// TODO
|
|
|
|
|
} else { |
|
|
|
|
// Invalid, push infinity
|
|
|
|
|
vm.stack.Push(ethutil.Big("0")) |
|
|
|
|
vm.stack.Push(ethutil.Big("0")) |
|
|
|
|
} |
|
|
|
|
//} else {
|
|
|
|
|
// // Invalid, push infinity
|
|
|
|
|
// vm.stack.Push("0")
|
|
|
|
|
// vm.stack.Push("0")
|
|
|
|
|
//}
|
|
|
|
|
// 0x40 range
|
|
|
|
|
case oPREVHASH: |
|
|
|
|
stack.Push(ethutil.BigD(vm.vars.prevHash)) |
|
|
|
|
case oCOINBASE: |
|
|
|
|
stack.Push(ethutil.BigD(vm.vars.coinbase)) |
|
|
|
|
case oTIMESTAMP: |
|
|
|
|
stack.Push(big.NewInt(vm.vars.time)) |
|
|
|
|
case oNUMBER: |
|
|
|
|
stack.Push(big.NewInt(int64(vm.vars.blockNumber))) |
|
|
|
|
case oDIFFICULTY: |
|
|
|
|
stack.Push(vm.vars.diff) |
|
|
|
|
case oGASLIMIT: |
|
|
|
|
// TODO
|
|
|
|
|
|
|
|
|
|
case oECADD: |
|
|
|
|
case oECSIGN: |
|
|
|
|
case oECRECOVER: |
|
|
|
|
case oECVALID: |
|
|
|
|
case oPUSH: |
|
|
|
|
pc++ |
|
|
|
|
vm.stack.Push(contract.GetMem(pc).BigInt()) |
|
|
|
|
// 0x50 range
|
|
|
|
|
case oPUSH: // Push PC+1 on to the stack
|
|
|
|
|
pc.Add(pc, ethutil.Big1) |
|
|
|
|
|
|
|
|
|
val := closure.GetMem(pc).BigInt() |
|
|
|
|
stack.Push(val) |
|
|
|
|
case oPOP: |
|
|
|
|
// Pop current value of the stack
|
|
|
|
|
vm.stack.Pop() |
|
|
|
|
stack.Pop() |
|
|
|
|
case oDUP: |
|
|
|
|
// Dup top stack
|
|
|
|
|
x := vm.stack.Pop() |
|
|
|
|
vm.stack.Push(x) |
|
|
|
|
vm.stack.Push(x) |
|
|
|
|
stack.Push(stack.Peek()) |
|
|
|
|
case oSWAP: |
|
|
|
|
// Swap two top most values
|
|
|
|
|
x, y := vm.stack.Popn() |
|
|
|
|
vm.stack.Push(y) |
|
|
|
|
vm.stack.Push(x) |
|
|
|
|
x, y := stack.Popn() |
|
|
|
|
stack.Push(y) |
|
|
|
|
stack.Push(x) |
|
|
|
|
case oMLOAD: |
|
|
|
|
x := vm.stack.Pop() |
|
|
|
|
vm.stack.Push(vm.mem[x.String()]) |
|
|
|
|
case oMSTORE: |
|
|
|
|
x, y := vm.stack.Popn() |
|
|
|
|
vm.mem[x.String()] = y |
|
|
|
|
offset := stack.Pop() |
|
|
|
|
stack.Push(ethutil.BigD(mem.Get(offset.Int64(), 32))) |
|
|
|
|
case oMSTORE: // Store the value at stack top-1 in to memory at location stack top
|
|
|
|
|
// Pop value of the stack
|
|
|
|
|
val, mStart := stack.Popn() |
|
|
|
|
mem.Set(mStart.Int64(), 32, ethutil.BigToBytes(val, 256)) |
|
|
|
|
case oMSTORE8: |
|
|
|
|
val, mStart := stack.Popn() |
|
|
|
|
base.And(val, new(big.Int).SetInt64(0xff)) |
|
|
|
|
mem.Set(mStart.Int64(), 32, ethutil.BigToBytes(base, 256)) |
|
|
|
|
case oSLOAD: |
|
|
|
|
// Load the value in storage and push it on the stack
|
|
|
|
|
x := vm.stack.Pop() |
|
|
|
|
// decode the object as a big integer
|
|
|
|
|
decoder := contract.Addr(x.Bytes()) |
|
|
|
|
if !decoder.IsNil() { |
|
|
|
|
vm.stack.Push(decoder.BigInt()) |
|
|
|
|
} else { |
|
|
|
|
vm.stack.Push(ethutil.BigFalse) |
|
|
|
|
} |
|
|
|
|
loc := stack.Pop() |
|
|
|
|
val := closure.GetMem(loc) |
|
|
|
|
stack.Push(val.BigInt()) |
|
|
|
|
case oSSTORE: |
|
|
|
|
// Store Y at index X
|
|
|
|
|
y, x := vm.stack.Popn() |
|
|
|
|
addr := ethutil.BigToBytes(x, 256) |
|
|
|
|
fmt.Printf(" => %x (%v) @ %v", y.Bytes(), y, ethutil.BigD(addr)) |
|
|
|
|
contract.SetAddr(addr, y) |
|
|
|
|
//contract.State().Update(string(idx), string(y))
|
|
|
|
|
case oJMP: |
|
|
|
|
x := int(vm.stack.Pop().Uint64()) |
|
|
|
|
// Set pc to x - 1 (minus one so the incrementing at the end won't effect it)
|
|
|
|
|
pc = x |
|
|
|
|
pc-- |
|
|
|
|
case oJMPI: |
|
|
|
|
x := vm.stack.Pop() |
|
|
|
|
// Set pc to x if it's non zero
|
|
|
|
|
if x.Cmp(ethutil.BigFalse) != 0 { |
|
|
|
|
pc = int(x.Uint64()) |
|
|
|
|
pc-- |
|
|
|
|
val, loc := stack.Popn() |
|
|
|
|
closure.SetMem(loc, ethutil.NewValue(val)) |
|
|
|
|
case oJUMP: |
|
|
|
|
pc = stack.Pop() |
|
|
|
|
case oJUMPI: |
|
|
|
|
pos, cond := stack.Popn() |
|
|
|
|
if cond.Cmp(big.NewInt(0)) > 0 { |
|
|
|
|
pc = pos |
|
|
|
|
} |
|
|
|
|
case oIND: |
|
|
|
|
vm.stack.Push(big.NewInt(int64(pc))) |
|
|
|
|
case oEXTRO: |
|
|
|
|
memAddr := vm.stack.Pop() |
|
|
|
|
contractAddr := vm.stack.Pop().Bytes() |
|
|
|
|
case oPC: |
|
|
|
|
stack.Push(pc) |
|
|
|
|
case oMSIZE: |
|
|
|
|
stack.Push(big.NewInt(int64(mem.Len()))) |
|
|
|
|
// 0x60 range
|
|
|
|
|
case oCALL: |
|
|
|
|
// Pop return size and offset
|
|
|
|
|
retSize, retOffset := stack.Popn() |
|
|
|
|
// Pop input size and offset
|
|
|
|
|
inSize, inOffset := stack.Popn() |
|
|
|
|
// Get the arguments from the memory
|
|
|
|
|
args := mem.Get(inOffset.Int64(), inSize.Int64()) |
|
|
|
|
// Pop gas and value of the stack.
|
|
|
|
|
gas, value := stack.Popn() |
|
|
|
|
// Closure addr
|
|
|
|
|
addr := stack.Pop() |
|
|
|
|
// Fetch the contract which will serve as the closure body
|
|
|
|
|
contract := vm.state.GetContract(addr.Bytes()) |
|
|
|
|
// Create a new callable closure
|
|
|
|
|
closure := NewClosure(closure, contract, vm.state, gas, value) |
|
|
|
|
// Executer the closure and get the return value (if any)
|
|
|
|
|
ret := closure.Call(vm, args) |
|
|
|
|
|
|
|
|
|
// Push the contract's memory on to the stack
|
|
|
|
|
vm.stack.Push(contractMemory(state, contractAddr, memAddr)) |
|
|
|
|
case oBALANCE: |
|
|
|
|
// Pushes the balance of the popped value on to the stack
|
|
|
|
|
account := state.GetAccount(vm.stack.Pop().Bytes()) |
|
|
|
|
vm.stack.Push(account.Amount) |
|
|
|
|
case oMKTX: |
|
|
|
|
addr, value := vm.stack.Popn() |
|
|
|
|
from, length := vm.stack.Popn() |
|
|
|
|
mem.Set(retOffset.Int64(), retSize.Int64(), ret) |
|
|
|
|
case oRETURN: |
|
|
|
|
size, offset := stack.Popn() |
|
|
|
|
ret := mem.Get(offset.Int64(), size.Int64()) |
|
|
|
|
|
|
|
|
|
makeInlineTx(addr.Bytes(), value, from, length, contract, state) |
|
|
|
|
return closure.Return(ret) |
|
|
|
|
case oSUICIDE: |
|
|
|
|
recAddr := vm.stack.Pop().Bytes() |
|
|
|
|
// Purge all memory
|
|
|
|
|
deletedMemory := contract.state.Purge() |
|
|
|
|
// Add refunds to the pop'ed address
|
|
|
|
|
refund := new(big.Int).Mul(StoreFee, big.NewInt(int64(deletedMemory))) |
|
|
|
|
account := state.GetAccount(recAddr) |
|
|
|
|
account.Amount.Add(account.Amount, refund) |
|
|
|
|
// Update the refunding address
|
|
|
|
|
state.UpdateAccount(recAddr, account) |
|
|
|
|
// Delete the contract
|
|
|
|
|
state.trie.Update(string(addr), "") |
|
|
|
|
/* |
|
|
|
|
recAddr := stack.Pop().Bytes() |
|
|
|
|
// Purge all memory
|
|
|
|
|
deletedMemory := contract.state.Purge() |
|
|
|
|
// Add refunds to the pop'ed address
|
|
|
|
|
refund := new(big.Int).Mul(StoreFee, big.NewInt(int64(deletedMemory))) |
|
|
|
|
account := state.GetAccount(recAddr) |
|
|
|
|
account.Amount.Add(account.Amount, refund) |
|
|
|
|
// Update the refunding address
|
|
|
|
|
state.UpdateAccount(recAddr, account) |
|
|
|
|
// Delete the contract
|
|
|
|
|
state.trie.Update(string(addr), "") |
|
|
|
|
|
|
|
|
|
ethutil.Config.Log.Debugf("(%d) => %x\n", deletedMemory, recAddr) |
|
|
|
|
break out |
|
|
|
|
ethutil.Config.Log.Debugf("(%d) => %x\n", deletedMemory, recAddr) |
|
|
|
|
break out |
|
|
|
|
*/ |
|
|
|
|
default: |
|
|
|
|
fmt.Printf("Invalid OPCODE: %x\n", op) |
|
|
|
|
ethutil.Config.Log.Debugln("Invalid opcode", op) |
|
|
|
|
} |
|
|
|
|
ethutil.Config.Log.Debugln("") |
|
|
|
|
//vm.stack.Print()
|
|
|
|
|
pc++ |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
state.UpdateContract(addr, contract) |
|
|
|
|
pc.Add(pc, ethutil.Big1) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func makeInlineTx(addr []byte, value, from, length *big.Int, contract *Contract, state *State) { |
|
|
|
|
ethutil.Config.Log.Debugf(" => creating inline tx %x %v %v %v", addr, value, from, length) |
|
|
|
|
j := 0 |
|
|
|
|
j := int64(0) |
|
|
|
|
dataItems := make([]string, int(length.Uint64())) |
|
|
|
|
for i := from.Uint64(); i < length.Uint64(); i++ { |
|
|
|
|
dataItems[j] = contract.GetMem(j).Str() |
|
|
|
|
for i := from.Int64(); i < length.Int64(); i++ { |
|
|
|
|
dataItems[j] = contract.GetMem(big.NewInt(j)).Str() |
|
|
|
|
j++ |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
tx := NewTransaction(addr, value, dataItems) |
|
|
|
|
if tx.IsContract() { |
|
|
|
|
contract := MakeContract(tx, state) |
|
|
|
|
state.UpdateContract(tx.Hash()[12:], contract) |
|
|
|
|
state.UpdateContract(contract) |
|
|
|
|
} else { |
|
|
|
|
account := state.GetAccount(tx.Recipient) |
|
|
|
|
account.Amount.Add(account.Amount, tx.Value) |
|
|
|
|