From db494170dc819b1eb0d267b6e1ab36c6cfb63569 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 18 Dec 2014 15:18:13 +0100 Subject: Created generic message (easy for testing) --- core/block_manager.go | 4 +- core/state_transition.go | 98 +++++++++++++++++++++++++++++++---------------- core/transaction_pool.go | 17 ++++---- core/types/transaction.go | 88 +++++++++++++++++++++++++++--------------- core/vm_env.go | 10 ++--- 5 files changed, 137 insertions(+), 80 deletions(-) (limited to 'core') diff --git a/core/block_manager.go b/core/block_manager.go index 794c87f52..aa845a007 100644 --- a/core/block_manager.go +++ b/core/block_manager.go @@ -111,7 +111,7 @@ done: // If we are mining this block and validating we want to set the logs back to 0 state.EmptyLogs() - txGas := new(big.Int).Set(tx.Gas) + txGas := new(big.Int).Set(tx.Gas()) cb := state.GetStateObject(coinbase.Address()) st := NewStateTransition(cb, tx, state, block) @@ -134,7 +134,7 @@ done: } txGas.Sub(txGas, st.gas) - cumulativeSum.Add(cumulativeSum, new(big.Int).Mul(txGas, tx.GasPrice)) + cumulativeSum.Add(cumulativeSum, new(big.Int).Mul(txGas, tx.GasPrice())) // Update the state with pending changes state.Update(txGas) diff --git a/core/state_transition.go b/core/state_transition.go index 820ba66e6..a6b654842 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -5,6 +5,8 @@ import ( "math/big" "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/ethutil" "github.com/ethereum/go-ethereum/state" "github.com/ethereum/go-ethereum/vm" ) @@ -27,7 +29,7 @@ import ( */ type StateTransition struct { coinbase, receiver []byte - tx *types.Transaction + msg Message gas, gasPrice *big.Int value *big.Int data []byte @@ -35,10 +37,42 @@ type StateTransition struct { block *types.Block cb, rec, sen *state.StateObject + + Env vm.Environment +} + +type Message interface { + Hash() []byte + + CreatesContract() bool + + From() []byte + To() []byte + + GasValue() *big.Int + GasPrice() *big.Int + Gas() *big.Int + Value() *big.Int + + Nonce() uint64 + Data() []byte } -func NewStateTransition(coinbase *state.StateObject, tx *types.Transaction, state *state.StateDB, block *types.Block) *StateTransition { - return &StateTransition{coinbase.Address(), tx.Recipient, tx, new(big.Int), new(big.Int).Set(tx.GasPrice), tx.Value, tx.Data, state, block, coinbase, nil, nil} +func AddressFromMessage(msg Message) []byte { + // Generate a new address + return crypto.Sha3(ethutil.NewValue([]interface{}{msg.From(), msg.Nonce()}).Encode())[12:] +} + +func NewStateTransition(coinbase *state.StateObject, msg Message, state *state.StateDB, block *types.Block) *StateTransition { + return &StateTransition{coinbase.Address(), msg.To(), msg, new(big.Int), new(big.Int).Set(msg.GasPrice()), msg.Value(), msg.Data(), state, block, coinbase, nil, nil, nil} +} + +func (self *StateTransition) VmEnv() vm.Environment { + if self.Env == nil { + self.Env = NewEnv(self.state, self.msg, self.block) + } + + return self.Env } func (self *StateTransition) Coinbase() *state.StateObject { @@ -49,17 +83,17 @@ func (self *StateTransition) Coinbase() *state.StateObject { self.cb = self.state.GetOrNewStateObject(self.coinbase) return self.cb } -func (self *StateTransition) Sender() *state.StateObject { +func (self *StateTransition) From() *state.StateObject { if self.sen != nil { return self.sen } - self.sen = self.state.GetOrNewStateObject(self.tx.Sender()) + self.sen = self.state.GetOrNewStateObject(self.msg.From()) return self.sen } -func (self *StateTransition) Receiver() *state.StateObject { - if self.tx != nil && self.tx.CreatesContract() { +func (self *StateTransition) To() *state.StateObject { + if self.msg != nil && self.msg.CreatesContract() { return nil } @@ -67,7 +101,7 @@ func (self *StateTransition) Receiver() *state.StateObject { return self.rec } - self.rec = self.state.GetOrNewStateObject(self.tx.Recipient) + self.rec = self.state.GetOrNewStateObject(self.msg.To()) return self.rec } @@ -87,41 +121,41 @@ func (self *StateTransition) AddGas(amount *big.Int) { func (self *StateTransition) BuyGas() error { var err error - sender := self.Sender() - if sender.Balance().Cmp(self.tx.GasValue()) < 0 { - return fmt.Errorf("Insufficient funds to pre-pay gas. Req %v, has %v", self.tx.GasValue(), sender.Balance()) + sender := self.From() + if sender.Balance().Cmp(self.msg.GasValue()) < 0 { + return fmt.Errorf("Insufficient funds to pre-pay gas. Req %v, has %v", self.msg.GasValue(), sender.Balance()) } coinbase := self.Coinbase() - err = coinbase.BuyGas(self.tx.Gas, self.tx.GasPrice) + err = coinbase.BuyGas(self.msg.Gas(), self.msg.GasPrice()) if err != nil { return err } - self.AddGas(self.tx.Gas) - sender.SubAmount(self.tx.GasValue()) + self.AddGas(self.msg.Gas()) + sender.SubAmount(self.msg.GasValue()) return nil } func (self *StateTransition) RefundGas() { - coinbase, sender := self.Coinbase(), self.Sender() - coinbase.RefundGas(self.gas, self.tx.GasPrice) + coinbase, sender := self.Coinbase(), self.From() + coinbase.RefundGas(self.gas, self.msg.GasPrice()) // Return remaining gas - remaining := new(big.Int).Mul(self.gas, self.tx.GasPrice) + remaining := new(big.Int).Mul(self.gas, self.msg.GasPrice()) sender.AddAmount(remaining) } func (self *StateTransition) preCheck() (err error) { var ( - tx = self.tx - sender = self.Sender() + msg = self.msg + sender = self.From() ) // Make sure this transaction's nonce is correct - if sender.Nonce != tx.Nonce { - return NonceError(tx.Nonce, sender.Nonce) + if sender.Nonce != msg.Nonce() { + return NonceError(msg.Nonce(), sender.Nonce) } // Pre-pay gas / Buy gas of the coinbase account @@ -133,7 +167,7 @@ func (self *StateTransition) preCheck() (err error) { } func (self *StateTransition) TransitionState() (err error) { - statelogger.Debugf("(~) %x\n", self.tx.Hash()) + statelogger.Debugf("(~) %x\n", self.msg.Hash()) // XXX Transactions after this point are considered valid. if err = self.preCheck(); err != nil { @@ -141,8 +175,8 @@ func (self *StateTransition) TransitionState() (err error) { } var ( - tx = self.tx - sender = self.Sender() + msg = self.msg + sender = self.From() ) defer self.RefundGas() @@ -169,15 +203,15 @@ func (self *StateTransition) TransitionState() (err error) { } var ret []byte - vmenv := NewEnv(self.state, self.tx, self.block) + vmenv := self.VmEnv() var ref vm.ClosureRef - if tx.CreatesContract() { - self.rec = MakeContract(tx, self.state) + if msg.CreatesContract() { + self.rec = MakeContract(msg, self.state) - ret, err, ref = vmenv.Create(sender, self.rec.Address(), self.tx.Data, self.gas, self.gasPrice, self.value) + ret, err, ref = vmenv.Create(sender, self.rec.Address(), self.msg.Data(), self.gas, self.gasPrice, self.value) ref.SetCode(ret) } else { - ret, err = vmenv.Call(self.Sender(), self.Receiver().Address(), self.tx.Data, self.gas, self.gasPrice, self.value) + ret, err = vmenv.Call(self.From(), self.To().Address(), self.msg.Data(), self.gas, self.gasPrice, self.value) } if err != nil { statelogger.Debugln(err) @@ -187,11 +221,11 @@ func (self *StateTransition) TransitionState() (err error) { } // Converts an transaction in to a state object -func MakeContract(tx *types.Transaction, state *state.StateDB) *state.StateObject { - addr := tx.CreationAddress(state) +func MakeContract(msg Message, state *state.StateDB) *state.StateObject { + addr := AddressFromMessage(msg) contract := state.GetOrNewStateObject(addr) - contract.InitCode = tx.Data + contract.InitCode = msg.Data() return contract } diff --git a/core/transaction_pool.go b/core/transaction_pool.go index 36b0beb28..da91ec568 100644 --- a/core/transaction_pool.go +++ b/core/transaction_pool.go @@ -112,8 +112,8 @@ func (pool *TxPool) ValidateTransaction(tx *types.Transaction) error { return fmt.Errorf("No last block on the block chain") } - if len(tx.Recipient) != 0 && len(tx.Recipient) != 20 { - return fmt.Errorf("Invalid recipient. len = %d", len(tx.Recipient)) + if len(tx.To()) != 0 && len(tx.To()) != 20 { + return fmt.Errorf("Invalid recipient. len = %d", len(tx.To())) } v, _, _ := tx.Curve() @@ -124,15 +124,15 @@ func (pool *TxPool) ValidateTransaction(tx *types.Transaction) error { // Get the sender sender := pool.chainManager.State().GetAccount(tx.Sender()) - totAmount := new(big.Int).Set(tx.Value) + totAmount := new(big.Int).Set(tx.Value()) // Make sure there's enough in the sender's account. Having insufficient // funds won't invalidate this transaction but simple ignores it. if sender.Balance().Cmp(totAmount) < 0 { - return fmt.Errorf("Insufficient amount in sender's (%x) account", tx.Sender()) + return fmt.Errorf("Insufficient amount in sender's (%x) account", tx.From()) } if tx.IsContract() { - if tx.GasPrice.Cmp(big.NewInt(minGasPrice)) < 0 { + if tx.GasPrice().Cmp(big.NewInt(minGasPrice)) < 0 { return fmt.Errorf("Gasprice too low, %s given should be at least %d.", tx.GasPrice, minGasPrice) } } @@ -160,10 +160,7 @@ func (self *TxPool) Add(tx *types.Transaction) error { self.addTransaction(tx) - tmp := make([]byte, 4) - copy(tmp, tx.Recipient) - - txplogger.Debugf("(t) %x => %x (%v) %x\n", tx.Sender()[:4], tmp, tx.Value, tx.Hash()) + txplogger.Debugf("(t) %x => %x (%v) %x\n", tx.From()[:4], tx.To()[:4], tx.Value, tx.Hash()) // Notify the subscribers go self.eventMux.Post(TxPreEvent{tx}) @@ -200,7 +197,7 @@ func (pool *TxPool) RemoveInvalid(state *state.StateDB) { tx := e.Value.(*types.Transaction) sender := state.GetAccount(tx.Sender()) err := pool.ValidateTransaction(tx) - if err != nil || sender.Nonce >= tx.Nonce { + if err != nil || sender.Nonce >= tx.Nonce() { pool.pool.Remove(e) } } diff --git a/core/types/transaction.go b/core/types/transaction.go index 63edef756..4b75d3abd 100644 --- a/core/types/transaction.go +++ b/core/types/transaction.go @@ -6,7 +6,6 @@ import ( "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/ethutil" - "github.com/ethereum/go-ethereum/state" "github.com/obscuren/secp256k1-go" ) @@ -18,12 +17,12 @@ func IsContractAddr(addr []byte) bool { } type Transaction struct { - Nonce uint64 - Recipient []byte - Value *big.Int - Gas *big.Int - GasPrice *big.Int - Data []byte + nonce uint64 + recipient []byte + value *big.Int + gas *big.Int + gasPrice *big.Int + data []byte v byte r, s []byte @@ -32,11 +31,11 @@ type Transaction struct { } func NewContractCreationTx(value, gas, gasPrice *big.Int, script []byte) *Transaction { - return &Transaction{Recipient: nil, Value: value, Gas: gas, GasPrice: gasPrice, Data: script, contractCreation: true} + return &Transaction{recipient: nil, value: value, gas: gas, gasPrice: gasPrice, data: script, contractCreation: true} } func NewTransactionMessage(to []byte, value, gas, gasPrice *big.Int, data []byte) *Transaction { - return &Transaction{Recipient: to, Value: value, GasPrice: gasPrice, Gas: gas, Data: data, contractCreation: IsContractAddr(to)} + return &Transaction{recipient: to, value: value, gasPrice: gasPrice, gas: gas, data: data, contractCreation: IsContractAddr(to)} } func NewTransactionFromBytes(data []byte) *Transaction { @@ -54,20 +53,52 @@ func NewTransactionFromValue(val *ethutil.Value) *Transaction { } func (self *Transaction) GasValue() *big.Int { - return new(big.Int).Mul(self.Gas, self.GasPrice) + return new(big.Int).Mul(self.gas, self.gasPrice) } func (self *Transaction) TotalValue() *big.Int { v := self.GasValue() - return v.Add(v, self.Value) + return v.Add(v, self.value) } func (tx *Transaction) Hash() []byte { - data := []interface{}{tx.Nonce, tx.GasPrice, tx.Gas, tx.Recipient, tx.Value, tx.Data} + data := []interface{}{tx.Nonce, tx.gasPrice, tx.gas, tx.recipient, tx.Value, tx.Data} return crypto.Sha3(ethutil.NewValue(data).Encode()) } +func (self *Transaction) Data() []byte { + return self.data +} + +func (self *Transaction) Gas() *big.Int { + return self.gas +} + +func (self *Transaction) GasPrice() *big.Int { + return self.gasPrice +} + +func (self *Transaction) Value() *big.Int { + return self.value +} + +func (self *Transaction) Nonce() uint64 { + return self.nonce +} + +func (self *Transaction) SetNonce(nonce uint64) { + self.nonce = nonce +} + +func (self *Transaction) From() []byte { + return self.Sender() +} + +func (self *Transaction) To() []byte { + return self.recipient +} + func (tx *Transaction) CreatesContract() bool { return tx.contractCreation } @@ -77,11 +108,6 @@ func (tx *Transaction) IsContract() bool { return tx.CreatesContract() } -func (tx *Transaction) CreationAddress(state *state.StateDB) []byte { - // Generate a new address - return crypto.Sha3(ethutil.NewValue([]interface{}{tx.Sender(), tx.Nonce}).Encode())[12:] -} - func (tx *Transaction) Curve() (v byte, r []byte, s []byte) { v = tx.v r = ethutil.LeftPadBytes(tx.r, 32) @@ -136,7 +162,7 @@ func (tx *Transaction) Sign(privk []byte) error { } func (tx *Transaction) RlpData() interface{} { - data := []interface{}{tx.Nonce, tx.GasPrice, tx.Gas, tx.Recipient, tx.Value, tx.Data} + data := []interface{}{tx.Nonce, tx.GasPrice, tx.Gas, tx.recipient, tx.Value, tx.Data} // TODO Remove prefixing zero's @@ -156,18 +182,18 @@ func (tx *Transaction) RlpDecode(data []byte) { } func (tx *Transaction) RlpValueDecode(decoder *ethutil.Value) { - tx.Nonce = decoder.Get(0).Uint() - tx.GasPrice = decoder.Get(1).BigInt() - tx.Gas = decoder.Get(2).BigInt() - tx.Recipient = decoder.Get(3).Bytes() - tx.Value = decoder.Get(4).BigInt() - tx.Data = decoder.Get(5).Bytes() + tx.nonce = decoder.Get(0).Uint() + tx.gasPrice = decoder.Get(1).BigInt() + tx.gas = decoder.Get(2).BigInt() + tx.recipient = decoder.Get(3).Bytes() + tx.value = decoder.Get(4).BigInt() + tx.data = decoder.Get(5).Bytes() tx.v = byte(decoder.Get(6).Uint()) tx.r = decoder.Get(7).Bytes() tx.s = decoder.Get(8).Bytes() - if IsContractAddr(tx.Recipient) { + if IsContractAddr(tx.recipient) { tx.contractCreation = true } } @@ -188,12 +214,12 @@ func (tx *Transaction) String() string { S: 0x%x `, tx.Hash(), - len(tx.Recipient) == 0, + len(tx.recipient) == 0, tx.Sender(), - tx.Recipient, - tx.Nonce, - tx.GasPrice, - tx.Gas, + tx.recipient, + tx.nonce, + tx.gasPrice, + tx.gas, tx.Value, tx.Data, tx.v, @@ -221,5 +247,5 @@ func (s Transactions) GetRlp(i int) []byte { return ethutil.Rlp(s[i]) } type TxByNonce struct{ Transactions } func (s TxByNonce) Less(i, j int) bool { - return s.Transactions[i].Nonce < s.Transactions[j].Nonce + return s.Transactions[i].nonce < s.Transactions[j].nonce } diff --git a/core/vm_env.go b/core/vm_env.go index 9e1815188..0b6744972 100644 --- a/core/vm_env.go +++ b/core/vm_env.go @@ -11,26 +11,26 @@ import ( type VMEnv struct { state *state.StateDB block *types.Block - tx *types.Transaction + msg Message depth int } -func NewEnv(state *state.StateDB, tx *types.Transaction, block *types.Block) *VMEnv { +func NewEnv(state *state.StateDB, msg Message, block *types.Block) *VMEnv { return &VMEnv{ state: state, block: block, - tx: tx, + msg: msg, } } -func (self *VMEnv) Origin() []byte { return self.tx.Sender() } +func (self *VMEnv) Origin() []byte { return self.msg.From() } func (self *VMEnv) BlockNumber() *big.Int { return self.block.Number } func (self *VMEnv) PrevHash() []byte { return self.block.PrevHash } func (self *VMEnv) Coinbase() []byte { return self.block.Coinbase } func (self *VMEnv) Time() int64 { return self.block.Time } func (self *VMEnv) Difficulty() *big.Int { return self.block.Difficulty } func (self *VMEnv) BlockHash() []byte { return self.block.Hash() } -func (self *VMEnv) Value() *big.Int { return self.tx.Value } +func (self *VMEnv) Value() *big.Int { return self.msg.Value() } func (self *VMEnv) State() *state.StateDB { return self.state } func (self *VMEnv) GasLimit() *big.Int { return self.block.GasLimit } func (self *VMEnv) Depth() int { return self.depth } -- cgit v1.2.3