From 272d58662c885ab1cef8930e96fb832ae5377d96 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 27 Oct 2014 11:44:16 +0100 Subject: [PATCH] Implemented LOG. Closes #159 --- ethchain/state_transition.go | 6 ++++++ ethchain/transaction.go | 7 +++++++ ethchain/types.go | 4 ++-- ethchain/vm_env.go | 3 +++ ethpipe/vm_env.go | 1 + ethutil/common.go | 1 + tests/helper/vm.go | 1 + utils/vm_env.go | 1 + vm/common.go | 1 + vm/environment.go | 1 + vm/log.go | 9 +++++++++ vm/stack.go | 12 ++++++++++++ vm/types.go | 10 ++++++++-- vm/vm.go | 2 +- vm/vm_debug.go | 33 +++++++++++++++++++++++++++------ 15 files changed, 81 insertions(+), 11 deletions(-) create mode 100644 vm/log.go diff --git a/ethchain/state_transition.go b/ethchain/state_transition.go index 1274915d5..542b7be13 100644 --- a/ethchain/state_transition.go +++ b/ethchain/state_transition.go @@ -237,6 +237,12 @@ func (self *StateTransition) TransitionState() (err error) { } msg.Output = ret + } else { + // Add default LOG + // PUSH1 1 CALLER ADD LOG1 + addr := ethutil.BigD(sender.Address()) + addr.Add(addr, ethutil.Big1) + tx.addLog(vm.Log{sender.Address(), []*big.Int{addr}, nil}) } } diff --git a/ethchain/transaction.go b/ethchain/transaction.go index c78c27ed6..b0743097d 100644 --- a/ethchain/transaction.go +++ b/ethchain/transaction.go @@ -8,6 +8,7 @@ import ( "github.com/ethereum/go-ethereum/ethcrypto" "github.com/ethereum/go-ethereum/ethstate" "github.com/ethereum/go-ethereum/ethutil" + "github.com/ethereum/go-ethereum/vm" "github.com/obscuren/secp256k1-go" ) @@ -28,6 +29,8 @@ type Transaction struct { v byte r, s []byte + logs []vm.Log + // Indicates whether this tx is a contract creation transaction contractCreation bool } @@ -54,6 +57,10 @@ func NewTransactionFromValue(val *ethutil.Value) *Transaction { return tx } +func (self *Transaction) addLog(log vm.Log) { + self.logs = append(self.logs, log) +} + func (self *Transaction) GasValue() *big.Int { return new(big.Int).Mul(self.Gas, self.GasPrice) } diff --git a/ethchain/types.go b/ethchain/types.go index 29084c749..d0e7fcfb0 100644 --- a/ethchain/types.go +++ b/ethchain/types.go @@ -18,7 +18,7 @@ const ( MOD = 0x06 SMOD = 0x07 EXP = 0x08 - NEG = 0x09 + BNOT = 0x09 LT = 0x0a GT = 0x0b SLT = 0x0c @@ -166,7 +166,7 @@ var opCodeToString = map[OpCode]string{ MOD: "MOD", SMOD: "SMOD", EXP: "EXP", - NEG: "NEG", + BNOT: "BNOT", LT: "LT", GT: "GT", SLT: "SLT", diff --git a/ethchain/vm_env.go b/ethchain/vm_env.go index 6dda27c6f..4dc96e8b1 100644 --- a/ethchain/vm_env.go +++ b/ethchain/vm_env.go @@ -31,6 +31,9 @@ func (self *VMEnv) BlockHash() []byte { return self.block.Hash() } func (self *VMEnv) Value() *big.Int { return self.tx.Value } func (self *VMEnv) State() *ethstate.State { return self.state } func (self *VMEnv) GasLimit() *big.Int { return self.block.GasLimit } +func (self *VMEnv) AddLog(log vm.Log) { + self.tx.addLog(log) +} func (self *VMEnv) Transfer(from, to vm.Account, amount *big.Int) error { return vm.Transfer(from, to, amount) } diff --git a/ethpipe/vm_env.go b/ethpipe/vm_env.go index 140726bfe..9d11ecf34 100644 --- a/ethpipe/vm_env.go +++ b/ethpipe/vm_env.go @@ -34,6 +34,7 @@ func (self *VMEnv) BlockHash() []byte { return self.block.Hash() } func (self *VMEnv) Value() *big.Int { return self.value } func (self *VMEnv) State() *ethstate.State { return self.state } func (self *VMEnv) GasLimit() *big.Int { return self.block.GasLimit } +func (self *VMEnv) AddLog(vm.Log) {} func (self *VMEnv) Transfer(from, to vm.Account, amount *big.Int) error { return vm.Transfer(from, to, amount) } diff --git a/ethutil/common.go b/ethutil/common.go index 8532d80f2..e60f237cf 100644 --- a/ethutil/common.go +++ b/ethutil/common.go @@ -77,6 +77,7 @@ func CurrencyToString(num *big.Int) string { var ( Big1 = big.NewInt(1) Big2 = big.NewInt(2) + Big3 = big.NewInt(3) Big0 = big.NewInt(0) BigTrue = Big1 BigFalse = Big0 diff --git a/tests/helper/vm.go b/tests/helper/vm.go index 5660caf64..c56c5bae7 100644 --- a/tests/helper/vm.go +++ b/tests/helper/vm.go @@ -50,6 +50,7 @@ func (self *Env) Difficulty() *big.Int { return self.difficulty } func (self *Env) BlockHash() []byte { return nil } func (self *Env) State() *ethstate.State { return self.state } func (self *Env) GasLimit() *big.Int { return self.gasLimit } +func (self *Env) AddLog(vm.Log) {} func (self *Env) Transfer(from, to vm.Account, amount *big.Int) error { return vm.Transfer(from, to, amount) } diff --git a/utils/vm_env.go b/utils/vm_env.go index 1946b6fac..034d4a16e 100644 --- a/utils/vm_env.go +++ b/utils/vm_env.go @@ -35,6 +35,7 @@ func (self *VMEnv) BlockHash() []byte { return self.block.Hash() } func (self *VMEnv) Value() *big.Int { return self.value } func (self *VMEnv) State() *ethstate.State { return self.state } func (self *VMEnv) GasLimit() *big.Int { return self.block.GasLimit } +func (self *VMEnv) AddLog(vm.Log) {} func (self *VMEnv) Transfer(from, to vm.Account, amount *big.Int) error { return vm.Transfer(from, to, amount) } diff --git a/vm/common.go b/vm/common.go index 3b0d735ba..c73744506 100644 --- a/vm/common.go +++ b/vm/common.go @@ -29,6 +29,7 @@ var ( GasMemory = big.NewInt(1) GasData = big.NewInt(5) GasTx = big.NewInt(500) + GasLog = big.NewInt(32) Pow256 = ethutil.BigPow(2, 256) diff --git a/vm/environment.go b/vm/environment.go index af67c4179..b8013856e 100644 --- a/vm/environment.go +++ b/vm/environment.go @@ -20,6 +20,7 @@ type Environment interface { BlockHash() []byte GasLimit() *big.Int Transfer(from, to Account, amount *big.Int) error + AddLog(Log) } type Object interface { diff --git a/vm/log.go b/vm/log.go new file mode 100644 index 000000000..954d2ec91 --- /dev/null +++ b/vm/log.go @@ -0,0 +1,9 @@ +package vm + +import "math/big" + +type Log struct { + Address []byte + Topics []*big.Int + Data []byte +} diff --git a/vm/stack.go b/vm/stack.go index 55fdb6d15..69ded6562 100644 --- a/vm/stack.go +++ b/vm/stack.go @@ -139,6 +139,18 @@ func (m *Memory) Get(offset, size int64) []byte { return nil } +func (self *Memory) Geti(offset, size int64) (cpy []byte) { + if len(self.store) > int(offset) { + s := int64(math.Min(float64(len(self.store)), float64(offset+size))) + cpy = make([]byte, size) + copy(cpy, self.store[offset:offset+s]) + + return + } + + return +} + func (m *Memory) Len() int { return len(m.store) } diff --git a/vm/types.go b/vm/types.go index 6fb9a5c95..53178fa43 100644 --- a/vm/types.go +++ b/vm/types.go @@ -18,7 +18,7 @@ const ( MOD = 0x06 SMOD = 0x07 EXP = 0x08 - NEG = 0x09 + BNOT = 0x09 LT = 0x0a GT = 0x0b SLT = 0x0c @@ -144,6 +144,12 @@ const ( SWAP15 = 0x9e SWAP16 = 0x9f + LOG0 = 0xa0 + LOG1 = 0xa1 + LOG2 = 0xa2 + LOG3 = 0xa3 + LOG4 = 0xa4 + // 0xf0 range - closures CREATE = 0xf0 CALL = 0xf1 @@ -166,7 +172,7 @@ var opCodeToString = map[OpCode]string{ MOD: "MOD", SMOD: "SMOD", EXP: "EXP", - NEG: "NEG", + BNOT: "BNOT", LT: "LT", GT: "GT", SLT: "SLT", diff --git a/vm/vm.go b/vm/vm.go index 291f1cda4..599c8ca41 100644 --- a/vm/vm.go +++ b/vm/vm.go @@ -268,7 +268,7 @@ func (self *Vm) RunClosure(closure *Closure) (ret []byte, err error) { U256(base) stack.Push(base) - case NEG: + case BNOT: require(1) base.Sub(Pow256, stack.Pop()) diff --git a/vm/vm_debug.go b/vm/vm_debug.go index a30339e2b..13446d6c0 100644 --- a/vm/vm_debug.go +++ b/vm/vm_debug.go @@ -141,7 +141,7 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { // Stack Check, memory resize & gas phase switch op { // Stack checks only - case NOT, CALLDATALOAD, POP, JUMP, NEG: // 1 + case NOT, CALLDATALOAD, POP, JUMP, BNOT: // 1 require(1) case ADD, SUB, DIV, SDIV, MOD, SMOD, EXP, LT, GT, SLT, SGT, EQ, AND, OR, XOR, BYTE: // 2 require(2) @@ -153,6 +153,14 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { case DUP1, DUP2, DUP3, DUP4, DUP5, DUP6, DUP7, DUP8, DUP9, DUP10, DUP11, DUP12, DUP13, DUP14, DUP15, DUP16: n := int(op - DUP1 + 1) require(n) + case LOG0, LOG1, LOG2, LOG3, LOG4: + n := int(op - LOG0) + require(n + 2) + + mSize, mStart := stack.Peekn() + gas.Set(GasLog) + addStepGasUsage(new(big.Int).Mul(big.NewInt(int64(n)), GasLog)) + addStepGasUsage(new(big.Int).Add(mSize, mStart)) // Gas only case STOP: gas.Set(ethutil.Big0) @@ -168,13 +176,16 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { y, x := stack.Peekn() val := closure.GetStorage(x) if val.BigInt().Cmp(ethutil.Big0) == 0 && len(y.Bytes()) > 0 { - mult = ethutil.Big2 + // 0 => non 0 + mult = ethutil.Big3 } else if val.BigInt().Cmp(ethutil.Big0) != 0 && len(y.Bytes()) == 0 { + //state.AddBalance(closure.caller.Address(), new(big.Int).Mul(big.NewInt(100), closure.Price)) mult = ethutil.Big0 } else { + // non 0 => non 0 mult = ethutil.Big1 } - gas = new(big.Int).Mul(mult, GasSStore) + gas.Set(new(big.Int).Mul(mult, GasSStore)) case BALANCE: require(1) gas.Set(GasBalance) @@ -375,10 +386,11 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { self.Printf(" = %v", base) stack.Push(base) - case NEG: - base.Sub(Pow256, stack.Pop()) + case BNOT: + base.Sub(Pow256, stack.Pop()).Sub(base, ethutil.Big1) - base = U256(base) + // Not needed + //base = U256(base) stack.Push(base) case LT: @@ -685,6 +697,15 @@ func (self *DebugVm) RunClosure(closure *Closure) (ret []byte, err error) { x, y := stack.Swapn(n) self.Printf(" => [%d] %x [0] %x", n, x.Bytes(), y.Bytes()) + case LOG0, LOG1, LOG2, LOG3, LOG4: + n := int(op - LOG0) + topics := make([]*big.Int, n) + mSize, mStart := stack.Pop().Int64(), stack.Pop().Int64() + data := mem.Geti(mStart, mSize) + for i := 0; i < n; i++ { + topics[i] = stack.Pop() + } + self.env.AddLog(Log{closure.Address(), topics, data}) case MLOAD: offset := stack.Pop() val := ethutil.BigD(mem.Get(offset.Int64(), 32))