Newer
Older
env Environment
logTy byte
logStr string
err error
BreakPoints []int64
Stepping bool
Fn string
Recoverable bool
}
return &Vm{debug: Debug, env: env, logTy: lt, Recoverable: true}
func (self *Vm) Run(context *Context, callData []byte) (ret []byte, err error) {
var (
caller = context.caller
code = context.Code
value = context.value
price = context.Price
)
self.Printf("(%d) (%x) %x (code=%d) gas: %v (d) %x", self.env.Depth(), caller.Address().Bytes()[:4], context.Address(), len(code), context.Gas, callData).Endl()
if self.Recoverable {
// Recover from any require exception
defer func() {
if r := recover(); r != nil {
self.Printf(" %v", r).Endl()
context.UseGas(context.Gas)
ret = context.Return(nil)
err = fmt.Errorf("%v", r)
}
}()
}
if context.CodeAddr != nil {
if p := Precompiled[context.CodeAddr.Str()]; p != nil {
return self.RunPrecompiled(p, callData, context)
}
}
var (
op OpCode
destinations = analyseJumpDests(context.Code)
mem = NewMemory()
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
pc uint64 = 0
step = 0
statedb = self.env.State()
jump = func(from uint64, to *big.Int) {
p := to.Uint64()
nop := context.GetOp(p)
if !destinations.Has(p) {
panic(fmt.Sprintf("invalid jump destination (%v) %v", nop, p))
}
self.Printf(" ~> %v", to)
pc = to.Uint64()
self.Endl()
}
)
// Don't bother with the execution if there's no code.
if len(code) == 0 {
return context.Return(nil), nil
}
for {
// The base for all big integer arithmetic
base := new(big.Int)
step++
// Get the memory location of pc
op = context.GetOp(pc)
self.Printf("(pc) %-3d -o- %-14s (m) %-4d (s) %-4d ", pc, op.String(), mem.Len(), stack.len())
newMemSize, gas := self.calculateGasAndSize(context, caller, op, statedb, mem, stack)
self.Printf("(g) %-3v (%v)", gas, context.Gas)
if !context.UseGas(gas) {
self.Endl()
tmp := new(big.Int).Set(context.Gas)
context.UseGas(context.Gas)
return context.Return(nil), OOG(gas, tmp)
}
mem.Resize(newMemSize.Uint64())
switch op {
// 0x20 range
case ADD:
base.Div(x, y)
}
U256(base)
self.Printf(" = %v", base)
if y.Cmp(common.Big0) == 0 {
base.Set(common.Big0)
if new(big.Int).Mul(x, y).Cmp(common.Big0) < 0 {
n.SetInt64(-1)
} else {
n.SetInt64(1)
}
base.Div(x.Abs(x), y.Abs(y)).Mul(base, n)
U256(base)
}
self.Printf(" = %v", base)
if y.Cmp(common.Big0) == 0 {
base.Set(common.Big0)
} else {
base.Mod(x, y)
}
U256(base)
self.Printf(" = %v", base)
if y.Cmp(common.Big0) == 0 {
base.Set(common.Big0)
n.SetInt64(-1)
} else {
n.SetInt64(1)
}
base.Mod(x.Abs(x), y.Abs(y)).Mul(base, n)
U256(base)
}
self.Printf(" = %v", base)
back := stack.pop()
if back.Cmp(big.NewInt(31)) < 0 {
bit := uint(back.Uint64()*8 + 7)
mask := new(big.Int).Lsh(common.Big1, bit)
mask.Sub(mask, common.Big1)
if common.BitTest(num, int(bit)) {
num.Or(num, mask.Not(mask))
} else {
num.And(num, mask)
}
num = U256(num)
self.Printf(" = %v", num)
//base.Sub(Pow256, stack.pop()).Sub(base, common.Big1)
x, y := stack.pop(), stack.pop()
self.Printf(" %v < %v", x, y)
x, y := stack.pop(), stack.pop()
self.Printf(" %v > %v", x, y)
x, y := S256(stack.pop()), S256(stack.pop())
self.Printf(" %v < %v", x, y)
x, y := S256(stack.pop()), S256(stack.pop())
self.Printf(" %v > %v", x, y)
self.Printf(" %v == %v", y, x)
// x == y
if x.Cmp(y) == 0 {
if x.Cmp(common.BigFalse) > 0 {
stack.push(common.BigFalse)
x, y := stack.pop(), stack.pop()
self.Printf(" %v | %v", x, y)
x, y := stack.pop(), stack.pop()
self.Printf(" %v ^ %v", x, y)
byt := big.NewInt(int64(common.LeftPadBytes(val.Bytes(), 32)[th.Int64()]))
x := stack.pop()
y := stack.pop()
z := stack.pop()
}
self.Printf(" %v + %v %% %v = %v", x, y, z, base)
x := stack.pop()
y := stack.pop()
z := stack.pop()
if z.Cmp(Zero) > 0 {
mul := new(big.Int).Mul(x, y)
base.Mod(mul, z)
U256(base)
}
self.Printf(" %v + %v %% %v = %v", x, y, z, base)
offset, size := stack.pop(), stack.pop()
data := crypto.Sha3(mem.Get(offset.Int64(), size.Int64()))
self.Printf(" => %x", context.Address())
case BALANCE:
balance := statedb.GetBalance(addr)
self.Printf(" => %v (%x)", balance, addr)
case ORIGIN:
origin := self.env.Origin()
self.Printf(" => %x", origin)
case CALLER:
caller := context.caller.Address()
self.Printf(" => %v", value)
case CALLDATALOAD:
var (
data = make([]byte, 32)
lenData = big.NewInt(int64(len(callData)))
)
if lenData.Cmp(offset) >= 0 {
length := new(big.Int).Add(offset, common.Big32)
length = common.BigMin(length, lenData)
copy(data, callData[offset.Int64():length.Int64()])
}
self.Printf(" => 0x%x", data)
self.Printf(" => %d", l)
case CALLDATACOPY:
var (
mOff = stack.pop()
cOff = stack.pop()
l = stack.pop()
case CODESIZE, EXTCODESIZE:
var code []byte
if op == EXTCODESIZE {
code = statedb.GetCode(addr)
} else {
code = context.Code
}
l := big.NewInt(int64(len(code)))
self.Printf(" => %d", l)
case CODECOPY, EXTCODECOPY:
var code []byte
if op == EXTCODECOPY {
addr := common.BigToAddress(stack.pop())
code = statedb.GetCode(addr)
mOff = stack.pop()
cOff = stack.pop()
l = stack.pop()
self.Printf(" => [%v, %v, %v] %x", mOff, cOff, l, codeCopy)
case GASPRICE:
n := new(big.Int).Sub(self.env.BlockNumber(), common.Big257)
if num.Cmp(n) > 0 && num.Cmp(self.env.BlockNumber()) < 0 {
case COINBASE:
coinbase := self.env.Coinbase()
self.Printf(" => 0x%x", coinbase)
case TIMESTAMP:
time := self.env.Time()
self.Printf(" => 0x%x", time)
case NUMBER:
number := self.env.BlockNumber()
self.Printf(" => 0x%x", number.Bytes())
case DIFFICULTY:
difficulty := self.env.Difficulty()
self.Printf(" => 0x%x", difficulty.Bytes())
case GASLIMIT:
self.Printf(" => %v", self.env.GasLimit())
// 0x50 range
case PUSH1, PUSH2, PUSH3, PUSH4, PUSH5, PUSH6, PUSH7, PUSH8, PUSH9, PUSH10, PUSH11, PUSH12, PUSH13, PUSH14, PUSH15, PUSH16, PUSH17, PUSH18, PUSH19, PUSH20, PUSH21, PUSH22, PUSH23, PUSH24, PUSH25, PUSH26, PUSH27, PUSH28, PUSH29, PUSH30, PUSH31, PUSH32:
a := uint64(op - PUSH1 + 1)
byts := context.GetRangeValue(pc+1, a)
pc += a
step += int(op) - int(PUSH1) + 1
self.Printf(" => 0x%x", byts)
case POP:
case DUP1, DUP2, DUP3, DUP4, DUP5, DUP6, DUP7, DUP8, DUP9, DUP10, DUP11, DUP12, DUP13, DUP14, DUP15, DUP16:
n := int(op - DUP1 + 1)
case SWAP1, SWAP2, SWAP3, SWAP4, SWAP5, SWAP6, SWAP7, SWAP8, SWAP9, SWAP10, SWAP11, SWAP12, SWAP13, SWAP14, SWAP15, SWAP16:
n := int(op - SWAP1 + 2)
case LOG0, LOG1, LOG2, LOG3, LOG4:
n := int(op - LOG0)
topics[i] = common.BigToHash(stack.pop()) //common.LeftPadBytes(stack.pop().Bytes(), 32)
}
data := mem.Get(mStart.Int64(), mSize.Int64())
log := &Log{context.Address(), topics, data, self.env.BlockNumber().Uint64()}
self.env.AddLog(log)
self.Printf(" => %v", log)
case MLOAD:
val := common.BigD(mem.Get(offset.Int64(), 32))
self.Printf(" => 0x%x", val.Bytes())
case MSTORE: // Store the value at stack top-1 in to memory at location stack top
// pop value of the stack
mStart, val := stack.pop(), stack.pop()
mem.Set(mStart.Uint64(), 32, common.BigToBytes(val, 256))
off, val := stack.pop().Int64(), stack.pop().Int64()
loc := common.BigToHash(stack.pop())
val := common.Bytes2Big(statedb.GetState(context.Address(), loc))
loc := common.BigToHash(stack.pop())
val := stack.pop()
statedb.SetState(context.Address(), loc, val)
self.Printf(" ~> false")
value = stack.pop()
offset, size = stack.pop(), stack.pop()
input = mem.Get(offset.Int64(), size.Int64())
gas = new(big.Int).Set(context.Gas)
ret, suberr, ref := self.env.Create(context, nil, input, gas, price, value)
self.Printf(" (*) 0x0 %v", suberr)
} else {
// gas < len(ret) * CreateDataGas == NO_CODE
dataGas := big.NewInt(int64(len(ret)))
dataGas.Mul(dataGas, GasCreateByte)
if context.UseGas(dataGas) {
ref.SetCode(ret)
}
addr = ref.Address()
gas := stack.pop()
// pop gas and value of the stack.
addr, value := stack.pop(), stack.pop()
// pop input size and offset
inOffset, inSize := stack.pop(), stack.pop()
// pop return size and offset
retOffset, retSize := stack.pop(), stack.pop()
self.Printf(" => %x", address).Endl()
// Get the arguments from the memory
args := mem.Get(inOffset.Int64(), inSize.Int64())
if len(value.Bytes()) > 0 {
gas.Add(gas, GasStipend)
}
var (
ret []byte
err error
)
if op == CALLCODE {
ret, err = self.env.CallCode(context, address, args, gas, price, value)
ret, err = self.env.Call(context, address, args, gas, price, value)
mem.Set(retOffset.Uint64(), retSize.Uint64(), ret)
}
self.Printf("resume %x (%v)", context.Address(), context.Gas)
case RETURN:
ret := mem.Get(offset.Int64(), size.Int64())
self.Printf(" => [%v, %v] (%d) 0x%x", offset, size, len(ret), ret).Endl()
return context.Return(ret), nil
case SUICIDE:
receiver := statedb.GetOrNewStateObject(common.BigToAddress(stack.pop()))
self.Printf(" => (%x) %v", receiver.Address().Bytes()[:4], balance)
statedb.Delete(context.Address())
fallthrough
case STOP: // Stop the context
self.Endl()
return context.Return(nil), nil
default:
self.Printf("(pc) %-3v Invalid opcode %x\n", pc, op).Endl()
panic(fmt.Errorf("Invalid opcode %x", op))
}
pc++
self.Endl()
}
func (self *Vm) calculateGasAndSize(context *Context, caller ContextRef, op OpCode, statedb *state.StateDB, mem *Memory, stack *stack) (*big.Int, *big.Int) {
var (
gas = new(big.Int)
newMemSize *big.Int = new(big.Int)
)
baseCheck(op, stack, gas)
case PUSH1, PUSH2, PUSH3, PUSH4, PUSH5, PUSH6, PUSH7, PUSH8, PUSH9, PUSH10, PUSH11, PUSH12, PUSH13, PUSH14, PUSH15, PUSH16, PUSH17, PUSH18, PUSH19, PUSH20, PUSH21, PUSH22, PUSH23, PUSH24, PUSH25, PUSH26, PUSH27, PUSH28, PUSH29, PUSH30, PUSH31, PUSH32:
gas.Set(GasFastestStep)
case SWAP1, SWAP2, SWAP3, SWAP4, SWAP5, SWAP6, SWAP7, SWAP8, SWAP9, SWAP10, SWAP11, SWAP12, SWAP13, SWAP14, SWAP15, SWAP16:
n := int(op - SWAP1 + 2)
stack.require(n)
case DUP1, DUP2, DUP3, DUP4, DUP5, DUP6, DUP7, DUP8, DUP9, DUP10, DUP11, DUP12, DUP13, DUP14, DUP15, DUP16:
n := int(op - DUP1 + 1)
stack.require(n)
case LOG0, LOG1, LOG2, LOG3, LOG4:
n := int(op - LOG0)
stack.require(n + 2)
mSize, mStart := stack.data[stack.len()-2], stack.data[stack.len()-1]
gas.Add(gas, GasLogBase)
gas.Add(gas, new(big.Int).Mul(big.NewInt(int64(n)), GasLogTopic))
newMemSize = calcMemSize(mStart, mSize)
case EXP:
gas.Add(gas, new(big.Int).Mul(big.NewInt(int64(len(stack.data[stack.len()-2].Bytes()))), GasExpByte))
y, x := stack.data[stack.len()-2], stack.data[stack.len()-1]
val := statedb.GetState(context.Address(), common.BigToHash(x))
if len(val) == 0 && len(y.Bytes()) > 0 {
// 0 => non 0
case SUICIDE:
if !statedb.IsDeleted(context.Address()) {
statedb.Refund(self.env.Origin(), RefundSuicide)
}
newMemSize = calcMemSize(stack.peek(), stack.data[stack.len()-2])
newMemSize = calcMemSize(stack.peek(), stack.data[stack.len()-2])
gas.Add(gas, words.Mul(words, GasSha3Word))
case CALLDATACOPY:
newMemSize = calcMemSize(stack.peek(), stack.data[stack.len()-3])
gas.Add(gas, words.Mul(words, GasCopyWord))
case CODECOPY:
newMemSize = calcMemSize(stack.peek(), stack.data[stack.len()-3])
gas.Add(gas, words.Mul(words, GasCopyWord))
case EXTCODECOPY:
newMemSize = calcMemSize(stack.data[stack.len()-2], stack.data[stack.len()-4])
newMemSize = calcMemSize(stack.data[stack.len()-2], stack.data[stack.len()-3])
if self.env.State().GetStateObject(common.BigToAddress(stack.data[stack.len()-2])) == nil {
x := calcMemSize(stack.data[stack.len()-6], stack.data[stack.len()-7])
y := calcMemSize(stack.data[stack.len()-4], stack.data[stack.len()-5])
newMemSizeWords := toWordSize(newMemSize)
newMemSize.Mul(newMemSizeWords, u256(32))
pow := new(big.Int).Exp(oldSize, common.Big2, Zero)
linCoef := new(big.Int).Mul(oldSize, GasMemWord)
quadCoef := new(big.Int).Div(pow, GasQuadCoeffDenom)
oldTotalFee := new(big.Int).Add(linCoef, quadCoef)
linCoef = new(big.Int).Mul(newMemSizeWords, GasMemWord)
quadCoef = new(big.Int).Div(pow, GasQuadCoeffDenom)
newTotalFee := new(big.Int).Add(linCoef, quadCoef)
gas.Add(gas, new(big.Int).Sub(newTotalFee, oldTotalFee))
func (self *Vm) RunPrecompiled(p *PrecompiledAccount, callData []byte, context *Context) (ret []byte, err error) {
gas := p.Gas(len(callData))
if context.UseGas(gas) {
ret = p.Call(callData)
self.Printf("NATIVE_FUNC => %x", ret)
self.Endl()
return context.Return(ret), nil
} else {
self.Printf("NATIVE_FUNC => failed").Endl()
tmp := new(big.Int).Set(context.Gas)
panic(OOG(gas, tmp).Error())
}
func (self *Vm) Printf(format string, v ...interface{}) VirtualMachine {
if self.debug {
if self.logTy == LogTyPretty {
self.logStr += fmt.Sprintf(format, v...)
}
if self.debug {
if self.logTy == LogTyPretty {
func (self *Vm) Env() Environment {
return self.env
}