From 2995d6c281b83f5bb055a22093b2b94e64c477d3 Mon Sep 17 00:00:00 2001 From: Maran Date: Tue, 10 Jun 2014 15:02:41 +0200 Subject: Validate minimum gasPrice and reject if not met --- ethchain/transaction_pool.go | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'ethchain') diff --git a/ethchain/transaction_pool.go b/ethchain/transaction_pool.go index ba2ffcef5..d4175d973 100644 --- a/ethchain/transaction_pool.go +++ b/ethchain/transaction_pool.go @@ -22,6 +22,7 @@ type TxMsgTy byte const ( TxPre = iota TxPost + minGasPrice = 1000000 ) type TxMsg struct { @@ -172,6 +173,12 @@ func (pool *TxPool) ValidateTransaction(tx *Transaction) error { return fmt.Errorf("[TXPL] Insufficient amount in sender's (%x) account", tx.Sender()) } + if tx.IsContract() { + if tx.GasPrice.Cmp(big.NewInt(minGasPrice)) < 0 { + return fmt.Errorf("[TXPL] Gasprice to low, %s given should be at least %d.", tx.GasPrice, minGasPrice) + } + } + // Increment the nonce making each tx valid only once to prevent replay // attacks -- cgit v1.2.3 From 753f749423df7d5fba55a4080383d215db8e0fc7 Mon Sep 17 00:00:00 2001 From: Maran Date: Tue, 10 Jun 2014 17:22:06 +0200 Subject: Implement CalcGasPrice for ethereum/go-ethereum#77 --- ethchain/block.go | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) (limited to 'ethchain') diff --git a/ethchain/block.go b/ethchain/block.go index 73e29f878..780c60869 100644 --- a/ethchain/block.go +++ b/ethchain/block.go @@ -154,6 +154,35 @@ func (block *Block) PayFee(addr []byte, fee *big.Int) bool { return true } +func (block *Block) CalcGasLimit(parent *Block) *big.Int { + if block.Number == big.NewInt(0) { + return ethutil.BigPow(10, 6) + } + previous := new(big.Int).Mul(big.NewInt(1023), parent.GasLimit) + current := new(big.Rat).Mul(new(big.Rat).SetInt(block.GasUsed), big.NewRat(6, 5)) + curInt := new(big.Int).Div(current.Num(), current.Denom()) + + result := new(big.Int).Add(previous, curInt) + result.Div(result, big.NewInt(1024)) + + min := ethutil.BigPow(10, 4) + + return ethutil.BigMax(min, result) + /* + base := new(big.Int) + base2 := new(big.Int) + parentGL := bc.CurrentBlock.GasLimit + parentUsed := bc.CurrentBlock.GasUsed + + base.Mul(parentGL, big.NewInt(1024-1)) + base2.Mul(parentUsed, big.NewInt(6)) + base2.Div(base2, big.NewInt(5)) + base.Add(base, base2) + base.Div(base, big.NewInt(1024)) + */ + +} + func (block *Block) BlockInfo() BlockInfo { bi := BlockInfo{} data, _ := ethutil.Config.Db.Get(append(block.Hash(), []byte("Info")...)) -- cgit v1.2.3 From 69044fe5774840a49de3f881a490db52e907affb Mon Sep 17 00:00:00 2001 From: Maran Date: Tue, 10 Jun 2014 17:22:43 +0200 Subject: Refactor to use new method --- ethchain/block_chain.go | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) (limited to 'ethchain') diff --git a/ethchain/block_chain.go b/ethchain/block_chain.go index b45d254b5..5e6ce46e1 100644 --- a/ethchain/block_chain.go +++ b/ethchain/block_chain.go @@ -72,19 +72,7 @@ func (bc *BlockChain) NewBlock(coinbase []byte) *Block { block.Number = new(big.Int).Add(bc.CurrentBlock.Number, ethutil.Big1) - // max(10000, (parent gas limit * (1024 - 1) + (parent gas used * 6 / 5)) / 1024) - base := new(big.Int) - base2 := new(big.Int) - parentGL := bc.CurrentBlock.GasLimit - parentUsed := bc.CurrentBlock.GasUsed - - base.Mul(parentGL, big.NewInt(1024-1)) - base2.Mul(parentUsed, big.NewInt(6)) - base2.Div(base2, big.NewInt(5)) - base.Add(base, base2) - base.Div(base, big.NewInt(1024)) - - block.GasLimit = ethutil.BigMax(big.NewInt(10000), base) + block.GasLimit = block.CalcGasLimit(bc.CurrentBlock) } return block -- cgit v1.2.3 From bdc206885a1d9c730464f60ec65557403720be1e Mon Sep 17 00:00:00 2001 From: Maran Date: Tue, 10 Jun 2014 17:23:32 +0200 Subject: Don't mine transactions if they would go over the GasLimit implements ethereum/go-ethereum#77 further. --- ethchain/error.go | 18 ++++++++++++++++++ ethchain/state_manager.go | 17 +++++++++++++++++ 2 files changed, 35 insertions(+) (limited to 'ethchain') diff --git a/ethchain/error.go b/ethchain/error.go index 8d37b0208..29896bc59 100644 --- a/ethchain/error.go +++ b/ethchain/error.go @@ -2,6 +2,7 @@ package ethchain import ( "fmt" + "math/big" ) // Parent error. In case a parent is unknown this error will be thrown @@ -43,6 +44,23 @@ func IsValidationErr(err error) bool { return ok } +type GasLimitErr struct { + Message string + Is, Max *big.Int +} + +func IsGasLimitErr(err error) bool { + _, ok := err.(*GasLimitErr) + + return ok +} +func (err *GasLimitErr) Error() string { + return err.Message +} +func GasLimitError(is, max *big.Int) *GasLimitErr { + return &GasLimitErr{Message: fmt.Sprintf("GasLimit error. Max %s, transaction would take it to %s", max, is), Is: is, Max: max} +} + type NonceErr struct { Message string Is, Exp uint64 diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index f1c09b819..aea5433ff 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -114,6 +114,8 @@ func (sm *StateManager) ApplyTransactions(state *State, block *Block, txs []*Tra // Process each transaction/contract var receipts []*Receipt var validTxs []*Transaction + var ignoredTxs []*Transaction // Transactions which go over the gasLimit + totalUsedGas := big.NewInt(0) for _, tx := range txs { usedGas, err := sm.ApplyTransaction(state, block, tx) @@ -121,6 +123,12 @@ func (sm *StateManager) ApplyTransactions(state *State, block *Block, txs []*Tra if IsNonceErr(err) { continue } + if IsGasLimitErr(err) { + ignoredTxs = append(ignoredTxs, tx) + // We need to figure out if we want to do something with thse txes + ethutil.Config.Log.Debugln("Gastlimit:", err) + continue + } ethutil.Config.Log.Infoln(err) } @@ -151,6 +159,7 @@ func (sm *StateManager) ApplyTransaction(state *State, block *Block, tx *Transac script []byte ) totalGasUsed = big.NewInt(0) + snapshot := state.Snapshot() // Apply the transaction to the current state gas, err = sm.Ethereum.TxPool().ProcessTransaction(tx, state, false) @@ -190,6 +199,14 @@ func (sm *StateManager) ApplyTransaction(state *State, block *Block, tx *Transac } } + parent := sm.bc.GetBlock(block.PrevHash) + total := new(big.Int).Add(block.GasUsed, totalGasUsed) + limit := block.CalcGasLimit(parent) + if total.Cmp(limit) > 0 { + state.Revert(snapshot) + err = GasLimitError(total, limit) + } + return } -- cgit v1.2.3 From e090d131c38bef3c5f2d0f5e9fa28f5d0ed06659 Mon Sep 17 00:00:00 2001 From: Maran Date: Wed, 11 Jun 2014 11:40:40 +0200 Subject: Implemented counting of usedGas --- ethchain/state_manager.go | 3 +++ 1 file changed, 3 insertions(+) (limited to 'ethchain') diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index aea5433ff..6fb664e3d 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -140,6 +140,9 @@ func (sm *StateManager) ApplyTransactions(state *State, block *Block, txs []*Tra validTxs = append(validTxs, tx) } + // Update the total gas used for the block (to be mined) + block.GasUsed = totalUsedGas + return receipts, validTxs } -- cgit v1.2.3 From 1938bfcddfd2722880a692c59cad344b611711c8 Mon Sep 17 00:00:00 2001 From: Maran Date: Wed, 11 Jun 2014 16:16:57 +0200 Subject: Fix compare --- ethchain/block.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'ethchain') diff --git a/ethchain/block.go b/ethchain/block.go index 780c60869..fee4a2d59 100644 --- a/ethchain/block.go +++ b/ethchain/block.go @@ -155,9 +155,10 @@ func (block *Block) PayFee(addr []byte, fee *big.Int) bool { } func (block *Block) CalcGasLimit(parent *Block) *big.Int { - if block.Number == big.NewInt(0) { + if block.Number.Cmp(big.NewInt(0)) == 0 { return ethutil.BigPow(10, 6) } + previous := new(big.Int).Mul(big.NewInt(1023), parent.GasLimit) current := new(big.Rat).Mul(new(big.Rat).SetInt(block.GasUsed), big.NewRat(6, 5)) curInt := new(big.Int).Div(current.Num(), current.Denom()) -- cgit v1.2.3 From 4d3209ad1d6ea6f7e4fc311c387392f23ebc7dde Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 11 Jun 2014 21:55:23 +0200 Subject: Moved process transaction to state manager * Buy gas of the coinbase address --- ethchain/state_manager.go | 93 ++++++++++++++++++++++++++++++++++++++------ ethchain/transaction_pool.go | 29 +++++++++----- 2 files changed, 100 insertions(+), 22 deletions(-) (limited to 'ethchain') diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index f1c09b819..e783ffdd8 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -108,15 +108,90 @@ func (sm *StateManager) MakeStateObject(state *State, tx *Transaction) *StateObj return nil } +func (self *StateManager) ProcessTransaction(tx *Transaction, coinbase *StateObject, state *State, toContract bool) (gas *big.Int, err error) { + fmt.Printf("state root before update %x\n", state.Root()) + defer func() { + if r := recover(); r != nil { + ethutil.Config.Log.Infoln(r) + err = fmt.Errorf("%v", r) + } + }() + + gas = new(big.Int) + addGas := func(g *big.Int) { gas.Add(gas, g) } + addGas(GasTx) + + // Get the sender + sender := state.GetAccount(tx.Sender()) + + if sender.Nonce != tx.Nonce { + err = NonceError(tx.Nonce, sender.Nonce) + return + } + + sender.Nonce += 1 + defer func() { + //state.UpdateStateObject(sender) + // Notify all subscribers + self.Ethereum.Reactor().Post("newTx:post", tx) + }() + + txTotalBytes := big.NewInt(int64(len(tx.Data))) + txTotalBytes.Div(txTotalBytes, ethutil.Big32) + addGas(new(big.Int).Mul(txTotalBytes, GasSStore)) + + rGas := new(big.Int).Set(gas) + rGas.Mul(gas, tx.GasPrice) + + // Make sure there's enough in the sender's account. Having insufficient + // funds won't invalidate this transaction but simple ignores it. + totAmount := new(big.Int).Add(tx.Value, rGas) + if sender.Amount.Cmp(totAmount) < 0 { + state.UpdateStateObject(sender) + err = fmt.Errorf("[TXPL] Insufficient amount in sender's (%x) account", tx.Sender()) + return + } + + coinbase.BuyGas(gas, tx.GasPrice) + state.UpdateStateObject(coinbase) + + // Get the receiver + receiver := state.GetAccount(tx.Recipient) + + // Send Tx to self + if bytes.Compare(tx.Recipient, tx.Sender()) == 0 { + // Subtract the fee + sender.SubAmount(rGas) + } else { + // Subtract the amount from the senders account + sender.SubAmount(totAmount) + + fmt.Printf("state root after sender update %x\n", state.Root()) + + // Add the amount to receivers account which should conclude this transaction + receiver.AddAmount(tx.Value) + state.UpdateStateObject(receiver) + + fmt.Printf("state root after receiver update %x\n", state.Root()) + } + + state.UpdateStateObject(sender) + + ethutil.Config.Log.Infof("[TXPL] Processed Tx %x\n", tx.Hash()) + + return +} + // Apply transactions uses the transaction passed to it and applies them onto // the current processing state. -func (sm *StateManager) ApplyTransactions(state *State, block *Block, txs []*Transaction) ([]*Receipt, []*Transaction) { +func (sm *StateManager) ApplyTransactions(coinbase []byte, state *State, block *Block, txs []*Transaction) ([]*Receipt, []*Transaction) { // Process each transaction/contract var receipts []*Receipt var validTxs []*Transaction totalUsedGas := big.NewInt(0) + for _, tx := range txs { - usedGas, err := sm.ApplyTransaction(state, block, tx) + usedGas, err := sm.ApplyTransaction(coinbase, state, block, tx) if err != nil { if IsNonceErr(err) { continue @@ -135,7 +210,7 @@ func (sm *StateManager) ApplyTransactions(state *State, block *Block, txs []*Tra return receipts, validTxs } -func (sm *StateManager) ApplyTransaction(state *State, block *Block, tx *Transaction) (totalGasUsed *big.Int, err error) { +func (sm *StateManager) ApplyTransaction(coinbase []byte, state *State, block *Block, tx *Transaction) (totalGasUsed *big.Int, err error) { /* Applies transactions to the given state and creates new state objects where needed. @@ -152,8 +227,9 @@ func (sm *StateManager) ApplyTransaction(state *State, block *Block, tx *Transac ) totalGasUsed = big.NewInt(0) + ca := state.GetAccount(coinbase) // Apply the transaction to the current state - gas, err = sm.Ethereum.TxPool().ProcessTransaction(tx, state, false) + gas, err = sm.ProcessTransaction(tx, ca, state, false) addTotalGas(gas) if tx.CreatesContract() { @@ -229,7 +305,7 @@ func (sm *StateManager) ProcessBlock(state *State, parent, block *Block, dontRea } // Process the transactions on to current block - sm.ApplyTransactions(state, parent, block.Transactions()) + sm.ApplyTransactions(block.Coinbase, state, parent, block.Transactions()) // Block validation if err := sm.ValidateBlock(block); err != nil { @@ -337,13 +413,6 @@ func CalculateBlockReward(block *Block, uncleLength int) *big.Int { base.Add(base, UncleInclusionReward) } - lastCumulGasUsed := big.NewInt(0) - for _, r := range block.Receipts() { - usedGas := new(big.Int).Sub(r.CumulativeGasUsed, lastCumulGasUsed) - usedGas.Add(usedGas, r.Tx.GasPrice) - base.Add(base, usedGas) - } - return base.Add(base, BlockReward) } diff --git a/ethchain/transaction_pool.go b/ethchain/transaction_pool.go index ba2ffcef5..bc7bde797 100644 --- a/ethchain/transaction_pool.go +++ b/ethchain/transaction_pool.go @@ -89,9 +89,11 @@ func (pool *TxPool) addTransaction(tx *Transaction) { pool.Ethereum.Broadcast(ethwire.MsgTxTy, []interface{}{tx.RlpData()}) } +/* // Process transaction validates the Tx and processes funds from the // sender to the recipient. func (pool *TxPool) ProcessTransaction(tx *Transaction, state *State, toContract bool) (gas *big.Int, err error) { + fmt.Printf("state root before update %x\n", state.Root()) defer func() { if r := recover(); r != nil { ethutil.Config.Log.Infoln(r) @@ -101,6 +103,7 @@ func (pool *TxPool) ProcessTransaction(tx *Transaction, state *State, toContract gas = new(big.Int) addGas := func(g *big.Int) { gas.Add(gas, g) } + addGas(GasTx) // Get the sender sender := state.GetAccount(tx.Sender()) @@ -110,28 +113,37 @@ func (pool *TxPool) ProcessTransaction(tx *Transaction, state *State, toContract return } + sender.Nonce += 1 + defer func() { + //state.UpdateStateObject(sender) + // Notify all subscribers + pool.Ethereum.Reactor().Post("newTx:post", tx) + }() + txTotalBytes := big.NewInt(int64(len(tx.Data))) txTotalBytes.Div(txTotalBytes, ethutil.Big32) addGas(new(big.Int).Mul(txTotalBytes, GasSStore)) + rGas := new(big.Int).Set(gas) + rGas.Mul(gas, tx.GasPrice) + // Make sure there's enough in the sender's account. Having insufficient // funds won't invalidate this transaction but simple ignores it. - //totAmount := new(big.Int).Add(tx.Value, new(big.Int).Mul(TxFee, TxFeeRat)) - totAmount := new(big.Int).Add(tx.Value, new(big.Int).Mul(tx.Gas, tx.GasPrice)) + totAmount := new(big.Int).Add(tx.Value, rGas) if sender.Amount.Cmp(totAmount) < 0 { err = fmt.Errorf("[TXPL] Insufficient amount in sender's (%x) account", tx.Sender()) return } + state.UpdateStateObject(sender) + fmt.Printf("state root after sender update %x\n", state.Root()) // Get the receiver receiver := state.GetAccount(tx.Recipient) - sender.Nonce += 1 // Send Tx to self if bytes.Compare(tx.Recipient, tx.Sender()) == 0 { - addGas(GasTx) // Subtract the fee - sender.SubAmount(new(big.Int).Mul(GasTx, tx.GasPrice)) + sender.SubAmount(rGas) } else { // Subtract the amount from the senders account sender.SubAmount(totAmount) @@ -140,17 +152,14 @@ func (pool *TxPool) ProcessTransaction(tx *Transaction, state *State, toContract receiver.AddAmount(tx.Value) state.UpdateStateObject(receiver) + fmt.Printf("state root after receiver update %x\n", state.Root()) } - state.UpdateStateObject(sender) - ethutil.Config.Log.Infof("[TXPL] Processed Tx %x\n", tx.Hash()) - // Notify all subscribers - pool.Ethereum.Reactor().Post("newTx:post", tx) - return } +*/ func (pool *TxPool) ValidateTransaction(tx *Transaction) error { // Get the last block so we can retrieve the sender and receiver from -- cgit v1.2.3 From 1bf6f8b4a6936d8ad14b345b2cfa4dc9d1f8a360 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 11 Jun 2014 21:55:34 +0200 Subject: Added a buy gas method --- ethchain/state_object.go | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) (limited to 'ethchain') diff --git a/ethchain/state_object.go b/ethchain/state_object.go index 3e9c6df40..a1dd531de 100644 --- a/ethchain/state_object.go +++ b/ethchain/state_object.go @@ -108,10 +108,14 @@ func (c *StateObject) ReturnGas(gas, price *big.Int, state *State) { func (c *StateObject) AddAmount(amount *big.Int) { c.SetAmount(new(big.Int).Add(c.Amount, amount)) + + ethutil.Config.Log.Debugf("%x: #%d %v (+ %v)", c.Address(), c.Nonce, c.Amount, amount) } func (c *StateObject) SubAmount(amount *big.Int) { c.SetAmount(new(big.Int).Sub(c.Amount, amount)) + + ethutil.Config.Log.Debugf("%x: #%d %v (- %v)", c.Address(), c.Nonce, c.Amount, amount) } func (c *StateObject) SetAmount(amount *big.Int) { @@ -129,6 +133,17 @@ func (c *StateObject) ConvertGas(gas, price *big.Int) error { return nil } +func (self *StateObject) BuyGas(gas, price *big.Int) error { + rGas := new(big.Int).Set(gas) + rGas.Mul(gas, price) + + self.AddAmount(rGas) + + // TODO Do sub from TotalGasPool + // and check if enough left + return nil +} + // Returns the address of the contract/account func (c *StateObject) Address() []byte { return c.address @@ -153,14 +168,14 @@ func (c *StateObject) RlpEncode() []byte { root = "" } - return ethutil.Encode([]interface{}{c.Amount, c.Nonce, root, ethutil.Sha3Bin(c.script)}) + return ethutil.Encode([]interface{}{c.Nonce, c.Amount, root, ethutil.Sha3Bin(c.script)}) } func (c *StateObject) RlpDecode(data []byte) { decoder := ethutil.NewValueFromBytes(data) - c.Amount = decoder.Get(0).BigInt() - c.Nonce = decoder.Get(1).Uint() + c.Nonce = decoder.Get(0).Uint() + c.Amount = decoder.Get(1).BigInt() c.state = NewState(ethutil.NewTrie(ethutil.Config.Db, decoder.Get(2).Interface())) c.ScriptHash = decoder.Get(3).Bytes() -- cgit v1.2.3 From 9ee6295c752a518603de01e4feaec787c61a5dcf Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 11 Jun 2014 21:55:45 +0200 Subject: Minor changes --- ethchain/block_chain.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'ethchain') diff --git a/ethchain/block_chain.go b/ethchain/block_chain.go index b45d254b5..68ef9d47e 100644 --- a/ethchain/block_chain.go +++ b/ethchain/block_chain.go @@ -271,7 +271,7 @@ func (bc *BlockChain) GetChain(hash []byte, amount int) []*Block { func AddTestNetFunds(block *Block) { for _, addr := range []string{ - "8a40bfaa73256b60764c1bf40675a99083efb075", + "51ba59315b3a95761d0863b05ccc7a7f54703d99", "e4157b34ea9615cfbde6b4fda419828124b70c78", "1e12515ce3e0f817a4ddef9ca55788a1d66bd2df", "6c386a4b26f73c802f34673f7248bb118f97424a", @@ -285,7 +285,6 @@ func AddTestNetFunds(block *Block) { account.Amount = ethutil.Big("1606938044258990275541962092341162602522202993782792835301376") //ethutil.BigPow(2, 200) block.state.UpdateStateObject(account) } - log.Printf("%x\n", block.RlpEncode()) } func (bc *BlockChain) setLastBlock() { -- cgit v1.2.3 From 3a9d7d318abb3cd01ecd012ae85da5e586436d65 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 12 Jun 2014 10:07:27 +0200 Subject: log changes --- ethchain/transaction_pool.go | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'ethchain') diff --git a/ethchain/transaction_pool.go b/ethchain/transaction_pool.go index d4175d973..103c305fe 100644 --- a/ethchain/transaction_pool.go +++ b/ethchain/transaction_pool.go @@ -162,6 +162,10 @@ func (pool *TxPool) ValidateTransaction(tx *Transaction) error { return errors.New("[TXPL] No last block on the block chain") } + if len(tx.Recipient) != 20 { + return fmt.Errorf("[TXPL] Invalid recipient. len = %d", len(tx.Recipient)) + } + // Get the sender //sender := pool.Ethereum.StateManager().procState.GetAccount(tx.Sender()) sender := pool.Ethereum.StateManager().CurrentState().GetAccount(tx.Sender()) @@ -207,6 +211,8 @@ out: // Call blocking version. pool.addTransaction(tx) + ethutil.Config.Log.Debugf("%x => %x (%v) %x\n", tx.Sender()[:4], tx.Recipient[:4], tx.Value, tx.Hash()) + // Notify the subscribers pool.Ethereum.Reactor().Post("newTx:pre", tx) } -- cgit v1.2.3 From b855e5f7df194c84651d7cc7ee32d307a2fa0a2e Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 12 Jun 2014 11:19:32 +0200 Subject: Changed opcode numbers and added missing opcodes --- ethchain/state_manager.go | 8 ++++---- ethchain/transaction.go | 4 +++- ethchain/types.go | 45 +++++++++++++++++++++++++++++++-------------- ethchain/vm.go | 5 +++++ 4 files changed, 43 insertions(+), 19 deletions(-) (limited to 'ethchain') diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 9631b55fe..7b44ba3b8 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -166,13 +166,9 @@ func (self *StateManager) ProcessTransaction(tx *Transaction, coinbase *StateObj // Subtract the amount from the senders account sender.SubAmount(totAmount) - fmt.Printf("state root after sender update %x\n", state.Root()) - // Add the amount to receivers account which should conclude this transaction receiver.AddAmount(tx.Value) state.UpdateStateObject(receiver) - - fmt.Printf("state root after receiver update %x\n", state.Root()) } state.UpdateStateObject(sender) @@ -215,6 +211,8 @@ func (sm *StateManager) ApplyTransactions(coinbase []byte, state *State, block * validTxs = append(validTxs, tx) } + fmt.Println("################# MADE\n", receipts, "\n############################") + // Update the total gas used for the block (to be mined) block.GasUsed = totalUsedGas @@ -250,6 +248,7 @@ func (sm *StateManager) ApplyTransaction(coinbase []byte, state *State, block *B // as it's data provider. contract := sm.MakeStateObject(state, tx) if contract != nil { + fmt.Println(Disassemble(contract.Init())) // Evaluate the initialization script // and use the return value as the // script section for the state object. @@ -323,6 +322,7 @@ func (sm *StateManager) ProcessBlock(state *State, parent, block *Block, dontRea if !sm.bc.HasBlock(block.PrevHash) && sm.bc.CurrentBlock != nil { return ParentError(block.PrevHash) } + fmt.Println(block.Receipts()) // Process the transactions on to current block sm.ApplyTransactions(block.Coinbase, state, parent, block.Transactions()) diff --git a/ethchain/transaction.go b/ethchain/transaction.go index 2cb946b3b..32dbd8388 100644 --- a/ethchain/transaction.go +++ b/ethchain/transaction.go @@ -1,6 +1,7 @@ package ethchain import ( + "bytes" "fmt" "github.com/ethereum/eth-go/ethutil" "github.com/obscuren/secp256k1-go" @@ -144,7 +145,8 @@ func (tx *Transaction) RlpValueDecode(decoder *ethutil.Value) { tx.v = byte(decoder.Get(6).Uint()) tx.r = decoder.Get(7).Bytes() tx.s = decoder.Get(8).Bytes() - if len(tx.Recipient) == 0 { + + if bytes.Compare(tx.Recipient, ContractAddr) == 0 { tx.contractCreation = true } } diff --git a/ethchain/types.go b/ethchain/types.go index 293871143..fdfd5792b 100644 --- a/ethchain/types.go +++ b/ethchain/types.go @@ -1,5 +1,9 @@ package ethchain +import ( + "fmt" +) + type OpCode int // Op codes @@ -37,7 +41,10 @@ const ( CALLVALUE = 0x34 CALLDATALOAD = 0x35 CALLDATASIZE = 0x36 - GASPRICE = 0x37 + CALLDATACOPY = 0x37 + CODESIZE = 0x38 + CODECOPY = 0x39 + GASPRICE = 0x3a // 0x40 range - block operations PREVHASH = 0x40 @@ -48,18 +55,19 @@ const ( GASLIMIT = 0x45 // 0x50 range - 'storage' and execution - POP = 0x51 - DUP = 0x52 - SWAP = 0x53 - MLOAD = 0x54 - MSTORE = 0x55 - MSTORE8 = 0x56 - SLOAD = 0x57 - SSTORE = 0x58 - JUMP = 0x59 - JUMPI = 0x5a - PC = 0x5b - MSIZE = 0x5c + POP = 0x50 + DUP = 0x51 + SWAP = 0x52 + MLOAD = 0x53 + MSTORE = 0x54 + MSTORE8 = 0x55 + SLOAD = 0x56 + SSTORE = 0x57 + JUMP = 0x58 + JUMPI = 0x59 + PC = 0x5a + MSIZE = 0x5b + GAS = 0x5c // 0x60 range PUSH1 = 0x60 @@ -140,6 +148,9 @@ var opCodeToString = map[OpCode]string{ CALLVALUE: "CALLVALUE", CALLDATALOAD: "CALLDATALOAD", CALLDATASIZE: "CALLDATASIZE", + CALLDATACOPY: "CALLDATACOPY", + CODESIZE: "CODESIZE", + CODECOPY: "CODECOPY", GASPRICE: "TXGASPRICE", // 0x40 range - block operations @@ -162,6 +173,7 @@ var opCodeToString = map[OpCode]string{ JUMPI: "JUMPI", PC: "PC", MSIZE: "MSIZE", + GAS: "GAS", // 0x60 range - push PUSH1: "PUSH1", @@ -208,7 +220,12 @@ var opCodeToString = map[OpCode]string{ } func (o OpCode) String() string { - return opCodeToString[o] + str := opCodeToString[o] + if len(str) == 0 { + return fmt.Sprintf("Missing opcode 0x%x", int(o)) + } + + return str } // Op codes for assembling diff --git a/ethchain/vm.go b/ethchain/vm.go index 955be847f..ebdc58659 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -337,6 +337,9 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro stack.Push(ethutil.BigD(data)) case CALLDATASIZE: stack.Push(big.NewInt(int64(len(closure.Args)))) + case CALLDATACOPY: + case CODESIZE: + case CODECOPY: case GASPRICE: stack.Push(closure.Price) @@ -423,6 +426,8 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro stack.Push(pc) case MSIZE: stack.Push(big.NewInt(int64(mem.Len()))) + case GAS: + stack.Push(closure.Gas) // 0x60 range case CREATE: require(3) -- cgit v1.2.3 From d078e9b8c92fb3bd5789a8e39c169b19864e0a04 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 13 Jun 2014 12:45:11 +0200 Subject: Refactoring state transitioning --- ethchain/asm.go | 12 +- ethchain/deprecated.go | 225 +++++++++++++++++++++++++++++ ethchain/error.go | 17 +++ ethchain/stack.go | 6 + ethchain/state_manager.go | 335 +++++++++++++++++++++++-------------------- ethchain/state_object.go | 2 +- ethchain/transaction.go | 16 ++- ethchain/transaction_pool.go | 2 +- ethchain/types.go | 8 +- ethchain/vm.go | 77 ++++++++-- 10 files changed, 509 insertions(+), 191 deletions(-) create mode 100644 ethchain/deprecated.go (limited to 'ethchain') diff --git a/ethchain/asm.go b/ethchain/asm.go index 430a89450..277326ff9 100644 --- a/ethchain/asm.go +++ b/ethchain/asm.go @@ -25,16 +25,10 @@ func Disassemble(script []byte) (asm []string) { pc.Add(pc, ethutil.Big1) a := int64(op) - int64(PUSH1) + 1 data := script[pc.Int64() : pc.Int64()+a] - val := ethutil.BigD(data) - - var b []byte - if val.Int64() == 0 { - b = []byte{0} - } else { - b = val.Bytes() + if len(data) == 0 { + data = []byte{0} } - - asm = append(asm, fmt.Sprintf("0x%x", b)) + asm = append(asm, fmt.Sprintf("0x%x", data)) pc.Add(pc, big.NewInt(a-1)) } diff --git a/ethchain/deprecated.go b/ethchain/deprecated.go new file mode 100644 index 000000000..ed2697e2a --- /dev/null +++ b/ethchain/deprecated.go @@ -0,0 +1,225 @@ +package ethchain + +import ( + "bytes" + "fmt" + "github.com/ethereum/eth-go/ethutil" + "math/big" +) + +func (sm *StateManager) EvalScript(state *State, script []byte, object *StateObject, tx *Transaction, block *Block) (ret []byte, gas *big.Int, err error) { + account := state.GetAccount(tx.Sender()) + + err = account.ConvertGas(tx.Gas, tx.GasPrice) + if err != nil { + ethutil.Config.Log.Debugln(err) + return + } + + closure := NewClosure(account, object, script, state, tx.Gas, tx.GasPrice) + vm := NewVm(state, sm, RuntimeVars{ + Origin: account.Address(), + BlockNumber: block.BlockInfo().Number, + PrevHash: block.PrevHash, + Coinbase: block.Coinbase, + Time: block.Time, + Diff: block.Difficulty, + Value: tx.Value, + //Price: tx.GasPrice, + }) + ret, gas, err = closure.Call(vm, tx.Data, nil) + + // Update the account (refunds) + state.UpdateStateObject(account) + state.UpdateStateObject(object) + + return +} + +func (self *StateManager) ProcessTransaction(tx *Transaction, coinbase *StateObject, state *State, toContract bool) (gas *big.Int, err error) { + fmt.Printf("state root before update %x\n", state.Root()) + defer func() { + if r := recover(); r != nil { + ethutil.Config.Log.Infoln(r) + err = fmt.Errorf("%v", r) + } + }() + + gas = new(big.Int) + addGas := func(g *big.Int) { gas.Add(gas, g) } + addGas(GasTx) + + // Get the sender + sender := state.GetAccount(tx.Sender()) + + if sender.Nonce != tx.Nonce { + err = NonceError(tx.Nonce, sender.Nonce) + return + } + + sender.Nonce += 1 + defer func() { + //state.UpdateStateObject(sender) + // Notify all subscribers + self.Ethereum.Reactor().Post("newTx:post", tx) + }() + + txTotalBytes := big.NewInt(int64(len(tx.Data))) + //fmt.Println("txTotalBytes", txTotalBytes) + //txTotalBytes.Div(txTotalBytes, ethutil.Big32) + addGas(new(big.Int).Mul(txTotalBytes, GasData)) + + rGas := new(big.Int).Set(gas) + rGas.Mul(gas, tx.GasPrice) + + // Make sure there's enough in the sender's account. Having insufficient + // funds won't invalidate this transaction but simple ignores it. + totAmount := new(big.Int).Add(tx.Value, rGas) + if sender.Amount.Cmp(totAmount) < 0 { + state.UpdateStateObject(sender) + err = fmt.Errorf("[TXPL] Insufficient amount in sender's (%x) account", tx.Sender()) + return + } + + coinbase.BuyGas(gas, tx.GasPrice) + state.UpdateStateObject(coinbase) + fmt.Printf("1. root %x\n", state.Root()) + + // Get the receiver + receiver := state.GetAccount(tx.Recipient) + + // Send Tx to self + if bytes.Compare(tx.Recipient, tx.Sender()) == 0 { + // Subtract the fee + sender.SubAmount(rGas) + } else { + // Subtract the amount from the senders account + sender.SubAmount(totAmount) + state.UpdateStateObject(sender) + fmt.Printf("3. root %x\n", state.Root()) + + // Add the amount to receivers account which should conclude this transaction + receiver.AddAmount(tx.Value) + state.UpdateStateObject(receiver) + fmt.Printf("2. root %x\n", state.Root()) + } + + ethutil.Config.Log.Infof("[TXPL] Processed Tx %x\n", tx.Hash()) + + return +} + +func (sm *StateManager) ApplyTransaction(coinbase []byte, state *State, block *Block, tx *Transaction) (totalGasUsed *big.Int, err error) { + /* + Applies transactions to the given state and creates new + state objects where needed. + + If said objects needs to be created + run the initialization script provided by the transaction and + assume there's a return value. The return value will be set to + the script section of the state object. + */ + var ( + addTotalGas = func(gas *big.Int) { totalGasUsed.Add(totalGasUsed, gas) } + gas = new(big.Int) + script []byte + ) + totalGasUsed = big.NewInt(0) + snapshot := state.Snapshot() + + ca := state.GetAccount(coinbase) + // Apply the transaction to the current state + gas, err = sm.ProcessTransaction(tx, ca, state, false) + addTotalGas(gas) + fmt.Println("gas used by tx", gas) + + if tx.CreatesContract() { + if err == nil { + // Create a new state object and the transaction + // as it's data provider. + contract := sm.MakeStateObject(state, tx) + if contract != nil { + fmt.Println(Disassemble(contract.Init())) + // Evaluate the initialization script + // and use the return value as the + // script section for the state object. + script, gas, err = sm.EvalScript(state, contract.Init(), contract, tx, block) + fmt.Println("gas used by eval", gas) + addTotalGas(gas) + fmt.Println("total =", totalGasUsed) + + fmt.Println("script len =", len(script)) + + if err != nil { + err = fmt.Errorf("[STATE] Error during init script run %v", err) + return + } + contract.script = script + state.UpdateStateObject(contract) + } else { + err = fmt.Errorf("[STATE] Unable to create contract") + } + } else { + err = fmt.Errorf("[STATE] contract creation tx: %v for sender %x", err, tx.Sender()) + } + } else { + // Find the state object at the "recipient" address. If + // there's an object attempt to run the script. + stateObject := state.GetStateObject(tx.Recipient) + if err == nil && stateObject != nil && len(stateObject.Script()) > 0 { + _, gas, err = sm.EvalScript(state, stateObject.Script(), stateObject, tx, block) + addTotalGas(gas) + } + } + + parent := sm.bc.GetBlock(block.PrevHash) + total := new(big.Int).Add(block.GasUsed, totalGasUsed) + limit := block.CalcGasLimit(parent) + if total.Cmp(limit) > 0 { + state.Revert(snapshot) + err = GasLimitError(total, limit) + } + + return +} + +// Apply transactions uses the transaction passed to it and applies them onto +// the current processing state. +func (sm *StateManager) ApplyTransactions(coinbase []byte, state *State, block *Block, txs []*Transaction) ([]*Receipt, []*Transaction) { + // Process each transaction/contract + var receipts []*Receipt + var validTxs []*Transaction + var ignoredTxs []*Transaction // Transactions which go over the gasLimit + + totalUsedGas := big.NewInt(0) + + for _, tx := range txs { + usedGas, err := sm.ApplyTransaction(coinbase, state, block, tx) + if err != nil { + if IsNonceErr(err) { + continue + } + if IsGasLimitErr(err) { + ignoredTxs = append(ignoredTxs, tx) + // We need to figure out if we want to do something with thse txes + ethutil.Config.Log.Debugln("Gastlimit:", err) + continue + } + + ethutil.Config.Log.Infoln(err) + } + + accumelative := new(big.Int).Set(totalUsedGas.Add(totalUsedGas, usedGas)) + receipt := &Receipt{tx, ethutil.CopyBytes(state.Root().([]byte)), accumelative} + + receipts = append(receipts, receipt) + validTxs = append(validTxs, tx) + } + + fmt.Println("################# MADE\n", receipts, "\n############################") + + // Update the total gas used for the block (to be mined) + block.GasUsed = totalUsedGas + + return receipts, validTxs +} diff --git a/ethchain/error.go b/ethchain/error.go index 29896bc59..2cf09a1ec 100644 --- a/ethchain/error.go +++ b/ethchain/error.go @@ -79,3 +79,20 @@ func IsNonceErr(err error) bool { return ok } + +type OutOfGasErr struct { + Message string +} + +func OutOfGasError() *OutOfGasErr { + return &OutOfGasErr{Message: "Out of gas"} +} +func (self *OutOfGasErr) Error() string { + return self.Message +} + +func IsOutOfGasErr(err error) bool { + _, ok := err.(*OutOfGasErr) + + return ok +} diff --git a/ethchain/stack.go b/ethchain/stack.go index bf34e6ea9..37d1f84b9 100644 --- a/ethchain/stack.go +++ b/ethchain/stack.go @@ -111,6 +111,12 @@ func (m *Memory) Set(offset, size int64, value []byte) { copy(m.store[offset:offset+size], value) } +func (m *Memory) Resize(size uint64) { + if uint64(m.Len()) < size { + m.store = append(m.store, make([]byte, size-uint64(m.Len()))...) + } +} + func (m *Memory) Get(offset, size int64) []byte { return m.store[offset : offset+size] } diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 7b44ba3b8..f44afecac 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -108,8 +108,86 @@ func (sm *StateManager) MakeStateObject(state *State, tx *Transaction) *StateObj return nil } -func (self *StateManager) ProcessTransaction(tx *Transaction, coinbase *StateObject, state *State, toContract bool) (gas *big.Int, err error) { - fmt.Printf("state root before update %x\n", state.Root()) +type StateTransition struct { + coinbase []byte + tx *Transaction + gas *big.Int + state *State + block *Block + + cb, rec, sen *StateObject +} + +func NewStateTransition(coinbase []byte, gas *big.Int, tx *Transaction, state *State, block *Block) *StateTransition { + return &StateTransition{coinbase, tx, new(big.Int), state, block, nil, nil, nil} +} + +func (self *StateTransition) Coinbase() *StateObject { + if self.cb != nil { + return self.cb + } + + self.cb = self.state.GetAccount(self.coinbase) + return self.cb +} +func (self *StateTransition) Sender() *StateObject { + if self.sen != nil { + return self.sen + } + + self.sen = self.state.GetAccount(self.tx.Sender()) + return self.sen +} +func (self *StateTransition) Receiver() *StateObject { + if self.tx.CreatesContract() { + return nil + } + + if self.rec != nil { + return self.rec + } + + self.rec = self.state.GetAccount(self.tx.Recipient) + return self.rec +} + +func (self *StateTransition) UseGas(amount *big.Int) error { + if self.gas.Cmp(amount) < 0 { + return OutOfGasError() + } + self.gas.Sub(self.gas, amount) + + return nil +} + +func (self *StateTransition) AddGas(amount *big.Int) { + self.gas.Add(self.gas, amount) +} + +func (self *StateTransition) BuyGas() error { + var err error + + sender := self.Sender() + if sender.Amount.Cmp(self.tx.GasValue()) < 0 { + return fmt.Errorf("Insufficient funds to pre-pay gas. Req %v, has %v", self.tx.GasValue(), self.tx.Value) + } + + coinbase := self.Coinbase() + err = coinbase.BuyGas(self.tx.Gas, self.tx.GasPrice) + if err != nil { + return err + } + self.state.UpdateStateObject(coinbase) + + self.AddGas(self.tx.Gas) + sender.SubAmount(self.tx.GasValue()) + + return nil +} + +func (self *StateManager) TransitionState(st *StateTransition) (err error) { + //snapshot := st.state.Snapshot() + defer func() { if r := recover(); r != nil { ethutil.Config.Log.Infoln(r) @@ -117,173 +195,144 @@ func (self *StateManager) ProcessTransaction(tx *Transaction, coinbase *StateObj } }() - gas = new(big.Int) - addGas := func(g *big.Int) { gas.Add(gas, g) } - addGas(GasTx) - - // Get the sender - sender := state.GetAccount(tx.Sender()) + var ( + tx = st.tx + sender = st.Sender() + receiver *StateObject + ) if sender.Nonce != tx.Nonce { - err = NonceError(tx.Nonce, sender.Nonce) - return + return NonceError(tx.Nonce, sender.Nonce) } sender.Nonce += 1 defer func() { - //state.UpdateStateObject(sender) // Notify all subscribers self.Ethereum.Reactor().Post("newTx:post", tx) }() - txTotalBytes := big.NewInt(int64(len(tx.Data))) - txTotalBytes.Div(txTotalBytes, ethutil.Big32) - addGas(new(big.Int).Mul(txTotalBytes, GasSStore)) + if err = st.BuyGas(); err != nil { + return err + } - rGas := new(big.Int).Set(gas) - rGas.Mul(gas, tx.GasPrice) + receiver = st.Receiver() - // Make sure there's enough in the sender's account. Having insufficient - // funds won't invalidate this transaction but simple ignores it. - totAmount := new(big.Int).Add(tx.Value, rGas) - if sender.Amount.Cmp(totAmount) < 0 { - state.UpdateStateObject(sender) - err = fmt.Errorf("[TXPL] Insufficient amount in sender's (%x) account", tx.Sender()) - return + if err = st.UseGas(GasTx); err != nil { + return err } - coinbase.BuyGas(gas, tx.GasPrice) - state.UpdateStateObject(coinbase) - - // Get the receiver - receiver := state.GetAccount(tx.Recipient) + dataPrice := big.NewInt(int64(len(tx.Data))) + dataPrice.Mul(dataPrice, GasData) + if err = st.UseGas(dataPrice); err != nil { + return err + } - // Send Tx to self - if bytes.Compare(tx.Recipient, tx.Sender()) == 0 { - // Subtract the fee - sender.SubAmount(rGas) - } else { - // Subtract the amount from the senders account - sender.SubAmount(totAmount) + if receiver == nil { // Contract + receiver = self.MakeStateObject(st.state, tx) + if receiver == nil { + return fmt.Errorf("ERR. Unable to create contract with transaction %v", tx) + } + } - // Add the amount to receivers account which should conclude this transaction - receiver.AddAmount(tx.Value) - state.UpdateStateObject(receiver) + if err = self.transferValue(st, sender, receiver); err != nil { + return err } - state.UpdateStateObject(sender) + if tx.CreatesContract() { + fmt.Println(Disassemble(receiver.Init())) + // Evaluate the initialization script + // and use the return value as the + // script section for the state object. + //script, gas, err = sm.Eval(state, contract.Init(), contract, tx, block) + code, err := self.Eval(st, receiver.Init(), receiver) + if err != nil { + return fmt.Errorf("Error during init script run %v", err) + } - ethutil.Config.Log.Infof("[TXPL] Processed Tx %x\n", tx.Hash()) + receiver.script = code + } - return + st.state.UpdateStateObject(sender) + st.state.UpdateStateObject(receiver) + + return nil } -// Apply transactions uses the transaction passed to it and applies them onto -// the current processing state. -func (sm *StateManager) ApplyTransactions(coinbase []byte, state *State, block *Block, txs []*Transaction) ([]*Receipt, []*Transaction) { - // Process each transaction/contract - var receipts []*Receipt - var validTxs []*Transaction - var ignoredTxs []*Transaction // Transactions which go over the gasLimit +func (self *StateManager) transferValue(st *StateTransition, sender, receiver *StateObject) error { + if sender.Amount.Cmp(st.tx.Value) < 0 { + return fmt.Errorf("Insufficient funds to transfer value. Req %v, has %v", st.tx.Value, sender.Amount) + } + + // Subtract the amount from the senders account + sender.SubAmount(st.tx.Value) + // Add the amount to receivers account which should conclude this transaction + receiver.AddAmount(st.tx.Value) - totalUsedGas := big.NewInt(0) + ethutil.Config.Log.Debugf("%x => %x (%v) %x\n", sender.Address()[:4], receiver.Address()[:4], st.tx.Value, st.tx.Hash()) - for _, tx := range txs { - usedGas, err := sm.ApplyTransaction(coinbase, state, block, tx) + return nil +} + +func (self *StateManager) ProcessTransactions(coinbase []byte, state *State, block, parent *Block, txs Transactions) (Receipts, Transactions, Transactions, error) { + var ( + receipts Receipts + handled, unhandled Transactions + totalUsedGas = big.NewInt(0) + err error + ) + +done: + for i, tx := range txs { + txGas := new(big.Int).Set(tx.Gas) + st := NewStateTransition(coinbase, tx.Gas, tx, state, block) + err = self.TransitionState(st) if err != nil { - if IsNonceErr(err) { - continue - } - if IsGasLimitErr(err) { - ignoredTxs = append(ignoredTxs, tx) - // We need to figure out if we want to do something with thse txes - ethutil.Config.Log.Debugln("Gastlimit:", err) + switch { + case IsNonceErr(err): + err = nil // ignore error continue - } + case IsGasLimitErr(err): + unhandled = txs[i:] - ethutil.Config.Log.Infoln(err) + break done + default: + ethutil.Config.Log.Infoln(err) + } } - accumelative := new(big.Int).Set(totalUsedGas.Add(totalUsedGas, usedGas)) + txGas.Sub(txGas, st.gas) + accumelative := new(big.Int).Set(totalUsedGas.Add(totalUsedGas, txGas)) receipt := &Receipt{tx, ethutil.CopyBytes(state.Root().([]byte)), accumelative} receipts = append(receipts, receipt) - validTxs = append(validTxs, tx) + handled = append(handled, tx) } fmt.Println("################# MADE\n", receipts, "\n############################") - // Update the total gas used for the block (to be mined) - block.GasUsed = totalUsedGas + parent.GasUsed = totalUsedGas - return receipts, validTxs + return receipts, handled, unhandled, err } -func (sm *StateManager) ApplyTransaction(coinbase []byte, state *State, block *Block, tx *Transaction) (totalGasUsed *big.Int, err error) { - /* - Applies transactions to the given state and creates new - state objects where needed. - - If said objects needs to be created - run the initialization script provided by the transaction and - assume there's a return value. The return value will be set to - the script section of the state object. - */ +func (self *StateManager) Eval(st *StateTransition, script []byte, context *StateObject) (ret []byte, err error) { var ( - addTotalGas = func(gas *big.Int) { totalGasUsed.Add(totalGasUsed, gas) } - gas = new(big.Int) - script []byte + tx = st.tx + block = st.block + initiator = st.Sender() ) - totalGasUsed = big.NewInt(0) - snapshot := state.Snapshot() - ca := state.GetAccount(coinbase) - // Apply the transaction to the current state - gas, err = sm.ProcessTransaction(tx, ca, state, false) - addTotalGas(gas) - - if tx.CreatesContract() { - if err == nil { - // Create a new state object and the transaction - // as it's data provider. - contract := sm.MakeStateObject(state, tx) - if contract != nil { - fmt.Println(Disassemble(contract.Init())) - // Evaluate the initialization script - // and use the return value as the - // script section for the state object. - script, gas, err = sm.EvalScript(state, contract.Init(), contract, tx, block) - addTotalGas(gas) - - if err != nil { - err = fmt.Errorf("[STATE] Error during init script run %v", err) - return - } - contract.script = script - state.UpdateStateObject(contract) - } else { - err = fmt.Errorf("[STATE] Unable to create contract") - } - } else { - err = fmt.Errorf("[STATE] contract creation tx: %v for sender %x", err, tx.Sender()) - } - } else { - // Find the state object at the "recipient" address. If - // there's an object attempt to run the script. - stateObject := state.GetStateObject(tx.Recipient) - if err == nil && stateObject != nil && len(stateObject.Script()) > 0 { - _, gas, err = sm.EvalScript(state, stateObject.Script(), stateObject, tx, block) - addTotalGas(gas) - } - } - - parent := sm.bc.GetBlock(block.PrevHash) - total := new(big.Int).Add(block.GasUsed, totalGasUsed) - limit := block.CalcGasLimit(parent) - if total.Cmp(limit) > 0 { - state.Revert(snapshot) - err = GasLimitError(total, limit) - } + closure := NewClosure(initiator, context, script, st.state, st.gas, tx.GasPrice) + vm := NewVm(st.state, self, RuntimeVars{ + Origin: initiator.Address(), + BlockNumber: block.BlockInfo().Number, + PrevHash: block.PrevHash, + Coinbase: block.Coinbase, + Time: block.Time, + Diff: block.Difficulty, + Value: tx.Value, + }) + ret, _, err = closure.Call(vm, tx.Data, nil) return } @@ -325,7 +374,8 @@ func (sm *StateManager) ProcessBlock(state *State, parent, block *Block, dontRea fmt.Println(block.Receipts()) // Process the transactions on to current block - sm.ApplyTransactions(block.Coinbase, state, parent, block.Transactions()) + //sm.ApplyTransactions(block.Coinbase, state, parent, block.Transactions()) + sm.ProcessTransactions(block.Coinbase, state, block, parent, block.Transactions()) // Block validation if err := sm.ValidateBlock(block); err != nil { @@ -464,35 +514,6 @@ func (sm *StateManager) Stop() { sm.bc.Stop() } -func (sm *StateManager) EvalScript(state *State, script []byte, object *StateObject, tx *Transaction, block *Block) (ret []byte, gas *big.Int, err error) { - account := state.GetAccount(tx.Sender()) - - err = account.ConvertGas(tx.Gas, tx.GasPrice) - if err != nil { - ethutil.Config.Log.Debugln(err) - return - } - - closure := NewClosure(account, object, script, state, tx.Gas, tx.GasPrice) - vm := NewVm(state, sm, RuntimeVars{ - Origin: account.Address(), - BlockNumber: block.BlockInfo().Number, - PrevHash: block.PrevHash, - Coinbase: block.Coinbase, - Time: block.Time, - Diff: block.Difficulty, - Value: tx.Value, - //Price: tx.GasPrice, - }) - ret, gas, err = closure.Call(vm, tx.Data, nil) - - // Update the account (refunds) - state.UpdateStateObject(account) - state.UpdateStateObject(object) - - return -} - func (sm *StateManager) notifyChanges(state *State) { for addr, stateObject := range state.manifest.objectChanges { sm.Ethereum.Reactor().Post("object:"+addr, stateObject) diff --git a/ethchain/state_object.go b/ethchain/state_object.go index a1dd531de..b92374882 100644 --- a/ethchain/state_object.go +++ b/ethchain/state_object.go @@ -135,7 +135,7 @@ func (c *StateObject) ConvertGas(gas, price *big.Int) error { func (self *StateObject) BuyGas(gas, price *big.Int) error { rGas := new(big.Int).Set(gas) - rGas.Mul(gas, price) + rGas.Mul(rGas, price) self.AddAmount(rGas) diff --git a/ethchain/transaction.go b/ethchain/transaction.go index 32dbd8388..7aaab2fd1 100644 --- a/ethchain/transaction.go +++ b/ethchain/transaction.go @@ -46,15 +46,18 @@ func NewTransactionFromValue(val *ethutil.Value) *Transaction { return tx } +func (self *Transaction) GasValue() *big.Int { + return new(big.Int).Mul(self.Gas, self.GasPrice) +} + +func (self *Transaction) TotalValue() *big.Int { + v := self.GasValue() + 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} - /* - if tx.contractCreation { - data = append(data, tx.Init) - } - */ - return ethutil.Sha3Bin(ethutil.NewValue(data).Encode()) } @@ -185,6 +188,7 @@ type Receipt struct { PostState []byte CumulativeGasUsed *big.Int } +type Receipts []*Receipt func NewRecieptFromValue(val *ethutil.Value) *Receipt { r := &Receipt{} diff --git a/ethchain/transaction_pool.go b/ethchain/transaction_pool.go index 52c850ba3..6538b0029 100644 --- a/ethchain/transaction_pool.go +++ b/ethchain/transaction_pool.go @@ -220,7 +220,7 @@ out: // Call blocking version. pool.addTransaction(tx) - ethutil.Config.Log.Debugf("%x => %x (%v) %x\n", tx.Sender()[:4], tx.Recipient[:4], tx.Value, tx.Hash()) + ethutil.Config.Log.Debugf("(t) %x => %x (%v) %x\n", tx.Sender()[:4], tx.Recipient[:4], tx.Value, tx.Hash()) // Notify the subscribers pool.Ethereum.Reactor().Post("newTx:pre", tx) diff --git a/ethchain/types.go b/ethchain/types.go index fdfd5792b..ee70a8d28 100644 --- a/ethchain/types.go +++ b/ethchain/types.go @@ -21,8 +21,10 @@ const ( NEG = 0x09 LT = 0x0a GT = 0x0b - EQ = 0x0c - NOT = 0x0d + SLT = 0x0c + SGT = 0x0d + EQ = 0x0e + NOT = 0x0f // 0x10 range - bit ops AND = 0x10 @@ -128,6 +130,8 @@ var opCodeToString = map[OpCode]string{ NEG: "NEG", LT: "LT", GT: "GT", + SLT: "SLT", + SGT: "SGT", EQ: "EQ", NOT: "NOT", diff --git a/ethchain/vm.go b/ethchain/vm.go index ebdc58659..e17264697 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -5,6 +5,7 @@ import ( "fmt" "github.com/ethereum/eth-go/ethutil" _ "github.com/obscuren/secp256k1-go" + "math" _ "math" "math/big" ) @@ -18,6 +19,7 @@ var ( GasCreate = big.NewInt(100) GasCall = big.NewInt(20) GasMemory = big.NewInt(1) + GasData = big.NewInt(5) GasTx = big.NewInt(500) ) @@ -116,9 +118,8 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro gas.Add(gas, amount) } + var newMemSize uint64 = 0 switch op { - case SHA3: - setStepGasUsage(GasSha) case SLOAD: setStepGasUsage(GasSLoad) case SSTORE: @@ -135,27 +136,61 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro setStepGasUsage(new(big.Int).Mul(mult, GasSStore)) case BALANCE: setStepGasUsage(GasBalance) - case CREATE: + case MSTORE: + require(2) + newMemSize = stack.Peek().Uint64() + 32 + case MSTORE8: + require(2) + newMemSize = stack.Peek().Uint64() + 1 + case RETURN: + require(2) + + newMemSize = stack.Peek().Uint64() + stack.data[stack.Len()-2].Uint64() + case SHA3: + require(2) + + setStepGasUsage(GasSha) + + newMemSize = stack.Peek().Uint64() + stack.data[stack.Len()-2].Uint64() + case CALLDATACOPY: require(3) - args := stack.Get(big.NewInt(3)) - initSize := new(big.Int).Add(args[1], args[0]) + newMemSize = stack.Peek().Uint64() + stack.data[stack.Len()-3].Uint64() + case CODECOPY: + require(3) - setStepGasUsage(CalculateTxGas(initSize)) + newMemSize = stack.Peek().Uint64() + stack.data[stack.Len()-3].Uint64() case CALL: + require(7) setStepGasUsage(GasCall) - case MLOAD, MSIZE, MSTORE8, MSTORE: - setStepGasUsage(GasMemory) + + x := stack.data[stack.Len()-6].Uint64() + stack.data[stack.Len()-7].Uint64() + y := stack.data[stack.Len()-4].Uint64() + stack.data[stack.Len()-5].Uint64() + + newMemSize = uint64(math.Max(float64(x), float64(y))) + case CREATE: + require(3) + setStepGasUsage(GasCreate) + + newMemSize = stack.data[stack.Len()-2].Uint64() + stack.data[stack.Len()-3].Uint64() default: setStepGasUsage(GasStep) } + newMemSize = (newMemSize + 31) / 32 * 32 + if newMemSize > uint64(mem.Len()) { + m := GasMemory.Uint64() * (newMemSize - uint64(mem.Len())) / 32 + setStepGasUsage(big.NewInt(int64(m))) + } + if !closure.UseGas(gas) { ethutil.Config.Log.Debugln("Insufficient gas", closure.Gas, gas) return closure.Return(nil), fmt.Errorf("insufficient gas %v %v", closure.Gas, gas) } + mem.Resize(newMemSize) + switch op { case LOG: stack.Print() @@ -340,6 +375,23 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro case CALLDATACOPY: case CODESIZE: case CODECOPY: + var ( + size = int64(len(closure.Script)) + mOff = stack.Pop().Int64() + cOff = stack.Pop().Int64() + l = stack.Pop().Int64() + ) + + if cOff > size { + cOff = 0 + l = 0 + } else if cOff+l > size { + l = 0 + } + + code := closure.Script[cOff : cOff+l] + + mem.Set(mOff, l, code) case GASPRICE: stack.Push(closure.Price) @@ -448,7 +500,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro // Transfer all remaining gas to the new // contract so it may run the init script gas := new(big.Int).Set(closure.Gas) - closure.UseGas(gas) + //closure.UseGas(gas) // Create the closure c := NewClosure(closure.callee, @@ -498,12 +550,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro if contract != nil { // Prepay for the gas - // If gas is set to 0 use all remaining gas for the next call - if gas.Cmp(big.NewInt(0)) == 0 { - // Copy - gas = new(big.Int).Set(closure.Gas) - } - closure.UseGas(gas) + //closure.UseGas(gas) // Add the value to the state object contract.AddAmount(value) -- cgit v1.2.3 From 5e2bf12a31e3e3a026d0f8d28c2d5bba919fc224 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 13 Jun 2014 12:57:52 +0200 Subject: Refactored state transitioning to its own model --- ethchain/deprecated.go | 11 +++ ethchain/state_manager.go | 202 +--------------------------------------------- 2 files changed, 13 insertions(+), 200 deletions(-) (limited to 'ethchain') diff --git a/ethchain/deprecated.go b/ethchain/deprecated.go index ed2697e2a..0985fa25d 100644 --- a/ethchain/deprecated.go +++ b/ethchain/deprecated.go @@ -7,6 +7,17 @@ import ( "math/big" ) +func (sm *StateManager) MakeStateObject(state *State, tx *Transaction) *StateObject { + contract := MakeContract(tx, state) + if contract != nil { + state.states[string(tx.CreationAddress())] = contract.state + + return contract + } + + return nil +} + func (sm *StateManager) EvalScript(state *State, script []byte, object *StateObject, tx *Transaction, block *Block) (ret []byte, gas *big.Int, err error) { account := state.GetAccount(tx.Sender()) diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index f44afecac..576afa8d3 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -97,182 +97,6 @@ func (sm *StateManager) BlockChain() *BlockChain { return sm.bc } -func (sm *StateManager) MakeStateObject(state *State, tx *Transaction) *StateObject { - contract := MakeContract(tx, state) - if contract != nil { - state.states[string(tx.CreationAddress())] = contract.state - - return contract - } - - return nil -} - -type StateTransition struct { - coinbase []byte - tx *Transaction - gas *big.Int - state *State - block *Block - - cb, rec, sen *StateObject -} - -func NewStateTransition(coinbase []byte, gas *big.Int, tx *Transaction, state *State, block *Block) *StateTransition { - return &StateTransition{coinbase, tx, new(big.Int), state, block, nil, nil, nil} -} - -func (self *StateTransition) Coinbase() *StateObject { - if self.cb != nil { - return self.cb - } - - self.cb = self.state.GetAccount(self.coinbase) - return self.cb -} -func (self *StateTransition) Sender() *StateObject { - if self.sen != nil { - return self.sen - } - - self.sen = self.state.GetAccount(self.tx.Sender()) - return self.sen -} -func (self *StateTransition) Receiver() *StateObject { - if self.tx.CreatesContract() { - return nil - } - - if self.rec != nil { - return self.rec - } - - self.rec = self.state.GetAccount(self.tx.Recipient) - return self.rec -} - -func (self *StateTransition) UseGas(amount *big.Int) error { - if self.gas.Cmp(amount) < 0 { - return OutOfGasError() - } - self.gas.Sub(self.gas, amount) - - return nil -} - -func (self *StateTransition) AddGas(amount *big.Int) { - self.gas.Add(self.gas, amount) -} - -func (self *StateTransition) BuyGas() error { - var err error - - sender := self.Sender() - if sender.Amount.Cmp(self.tx.GasValue()) < 0 { - return fmt.Errorf("Insufficient funds to pre-pay gas. Req %v, has %v", self.tx.GasValue(), self.tx.Value) - } - - coinbase := self.Coinbase() - err = coinbase.BuyGas(self.tx.Gas, self.tx.GasPrice) - if err != nil { - return err - } - self.state.UpdateStateObject(coinbase) - - self.AddGas(self.tx.Gas) - sender.SubAmount(self.tx.GasValue()) - - return nil -} - -func (self *StateManager) TransitionState(st *StateTransition) (err error) { - //snapshot := st.state.Snapshot() - - defer func() { - if r := recover(); r != nil { - ethutil.Config.Log.Infoln(r) - err = fmt.Errorf("%v", r) - } - }() - - var ( - tx = st.tx - sender = st.Sender() - receiver *StateObject - ) - - if sender.Nonce != tx.Nonce { - return NonceError(tx.Nonce, sender.Nonce) - } - - sender.Nonce += 1 - defer func() { - // Notify all subscribers - self.Ethereum.Reactor().Post("newTx:post", tx) - }() - - if err = st.BuyGas(); err != nil { - return err - } - - receiver = st.Receiver() - - if err = st.UseGas(GasTx); err != nil { - return err - } - - dataPrice := big.NewInt(int64(len(tx.Data))) - dataPrice.Mul(dataPrice, GasData) - if err = st.UseGas(dataPrice); err != nil { - return err - } - - if receiver == nil { // Contract - receiver = self.MakeStateObject(st.state, tx) - if receiver == nil { - return fmt.Errorf("ERR. Unable to create contract with transaction %v", tx) - } - } - - if err = self.transferValue(st, sender, receiver); err != nil { - return err - } - - if tx.CreatesContract() { - fmt.Println(Disassemble(receiver.Init())) - // Evaluate the initialization script - // and use the return value as the - // script section for the state object. - //script, gas, err = sm.Eval(state, contract.Init(), contract, tx, block) - code, err := self.Eval(st, receiver.Init(), receiver) - if err != nil { - return fmt.Errorf("Error during init script run %v", err) - } - - receiver.script = code - } - - st.state.UpdateStateObject(sender) - st.state.UpdateStateObject(receiver) - - return nil -} - -func (self *StateManager) transferValue(st *StateTransition, sender, receiver *StateObject) error { - if sender.Amount.Cmp(st.tx.Value) < 0 { - return fmt.Errorf("Insufficient funds to transfer value. Req %v, has %v", st.tx.Value, sender.Amount) - } - - // Subtract the amount from the senders account - sender.SubAmount(st.tx.Value) - // Add the amount to receivers account which should conclude this transaction - receiver.AddAmount(st.tx.Value) - - ethutil.Config.Log.Debugf("%x => %x (%v) %x\n", sender.Address()[:4], receiver.Address()[:4], st.tx.Value, st.tx.Hash()) - - return nil -} - func (self *StateManager) ProcessTransactions(coinbase []byte, state *State, block, parent *Block, txs Transactions) (Receipts, Transactions, Transactions, error) { var ( receipts Receipts @@ -284,8 +108,8 @@ func (self *StateManager) ProcessTransactions(coinbase []byte, state *State, blo done: for i, tx := range txs { txGas := new(big.Int).Set(tx.Gas) - st := NewStateTransition(coinbase, tx.Gas, tx, state, block) - err = self.TransitionState(st) + st := NewStateTransition(coinbase, tx, state, block) + err = st.TransitionState() if err != nil { switch { case IsNonceErr(err): @@ -315,28 +139,6 @@ done: return receipts, handled, unhandled, err } -func (self *StateManager) Eval(st *StateTransition, script []byte, context *StateObject) (ret []byte, err error) { - var ( - tx = st.tx - block = st.block - initiator = st.Sender() - ) - - closure := NewClosure(initiator, context, script, st.state, st.gas, tx.GasPrice) - vm := NewVm(st.state, self, RuntimeVars{ - Origin: initiator.Address(), - BlockNumber: block.BlockInfo().Number, - PrevHash: block.PrevHash, - Coinbase: block.Coinbase, - Time: block.Time, - Diff: block.Difficulty, - Value: tx.Value, - }) - ret, _, err = closure.Call(vm, tx.Data, nil) - - return -} - func (sm *StateManager) Process(block *Block, dontReact bool) error { if !sm.bc.HasBlock(block.PrevHash) { return ParentError(block.PrevHash) -- cgit v1.2.3 From cebf4e3697dcd20e290ff56ad6e5dfca2059c063 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 13 Jun 2014 12:58:01 +0200 Subject: Refactored state transitioning to its own model --- ethchain/state_transition.go | 206 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 206 insertions(+) create mode 100644 ethchain/state_transition.go (limited to 'ethchain') diff --git a/ethchain/state_transition.go b/ethchain/state_transition.go new file mode 100644 index 000000000..6ec9205e9 --- /dev/null +++ b/ethchain/state_transition.go @@ -0,0 +1,206 @@ +package ethchain + +import ( + "fmt" + "github.com/ethereum/eth-go/ethutil" + "math/big" +) + +type StateTransition struct { + coinbase []byte + tx *Transaction + gas *big.Int + state *State + block *Block + + cb, rec, sen *StateObject +} + +func NewStateTransition(coinbase []byte, tx *Transaction, state *State, block *Block) *StateTransition { + return &StateTransition{coinbase, tx, new(big.Int), state, block, nil, nil, nil} +} + +func (self *StateTransition) Coinbase() *StateObject { + if self.cb != nil { + return self.cb + } + + self.cb = self.state.GetAccount(self.coinbase) + return self.cb +} +func (self *StateTransition) Sender() *StateObject { + if self.sen != nil { + return self.sen + } + + self.sen = self.state.GetAccount(self.tx.Sender()) + return self.sen +} +func (self *StateTransition) Receiver() *StateObject { + if self.tx.CreatesContract() { + return nil + } + + if self.rec != nil { + return self.rec + } + + self.rec = self.state.GetAccount(self.tx.Recipient) + return self.rec +} + +func (self *StateTransition) MakeStateObject(state *State, tx *Transaction) *StateObject { + contract := MakeContract(tx, state) + if contract != nil { + state.states[string(tx.CreationAddress())] = contract.state + + return contract + } + + return nil +} + +func (self *StateTransition) UseGas(amount *big.Int) error { + if self.gas.Cmp(amount) < 0 { + return OutOfGasError() + } + self.gas.Sub(self.gas, amount) + + return nil +} + +func (self *StateTransition) AddGas(amount *big.Int) { + self.gas.Add(self.gas, amount) +} + +func (self *StateTransition) BuyGas() error { + var err error + + sender := self.Sender() + if sender.Amount.Cmp(self.tx.GasValue()) < 0 { + return fmt.Errorf("Insufficient funds to pre-pay gas. Req %v, has %v", self.tx.GasValue(), self.tx.Value) + } + + coinbase := self.Coinbase() + err = coinbase.BuyGas(self.tx.Gas, self.tx.GasPrice) + if err != nil { + return err + } + self.state.UpdateStateObject(coinbase) + + self.AddGas(self.tx.Gas) + sender.SubAmount(self.tx.GasValue()) + + return nil +} + +func (self *StateTransition) TransitionState() (err error) { + //snapshot := st.state.Snapshot() + + defer func() { + if r := recover(); r != nil { + ethutil.Config.Log.Infoln(r) + err = fmt.Errorf("%v", r) + } + }() + + var ( + tx = self.tx + sender = self.Sender() + receiver *StateObject + ) + + if sender.Nonce != tx.Nonce { + return NonceError(tx.Nonce, sender.Nonce) + } + + sender.Nonce += 1 + defer func() { + // Notify all subscribers + //self.Ethereum.Reactor().Post("newTx:post", tx) + }() + + if err = self.BuyGas(); err != nil { + return err + } + + receiver = self.Receiver() + + if err = self.UseGas(GasTx); err != nil { + return err + } + + dataPrice := big.NewInt(int64(len(tx.Data))) + dataPrice.Mul(dataPrice, GasData) + if err = self.UseGas(dataPrice); err != nil { + return err + } + + if receiver == nil { // Contract + receiver = self.MakeStateObject(self.state, tx) + if receiver == nil { + return fmt.Errorf("ERR. Unable to create contract with transaction %v", tx) + } + } + + if err = self.transferValue(sender, receiver); err != nil { + return err + } + + if tx.CreatesContract() { + fmt.Println(Disassemble(receiver.Init())) + // Evaluate the initialization script + // and use the return value as the + // script section for the state object. + //script, gas, err = sm.Eval(state, contract.Init(), contract, tx, block) + code, err := self.Eval(receiver.Init(), receiver) + if err != nil { + return fmt.Errorf("Error during init script run %v", err) + } + + receiver.script = code + } + + self.state.UpdateStateObject(sender) + self.state.UpdateStateObject(receiver) + + return nil +} + +func (self *StateTransition) transferValue(sender, receiver *StateObject) error { + if sender.Amount.Cmp(self.tx.Value) < 0 { + return fmt.Errorf("Insufficient funds to transfer value. Req %v, has %v", self.tx.Value, sender.Amount) + } + + // Subtract the amount from the senders account + sender.SubAmount(self.tx.Value) + // Add the amount to receivers account which should conclude this transaction + receiver.AddAmount(self.tx.Value) + + ethutil.Config.Log.Debugf("%x => %x (%v) %x\n", sender.Address()[:4], receiver.Address()[:4], self.tx.Value, self.tx.Hash()) + + return nil +} + +func (self *StateTransition) Eval(script []byte, context *StateObject) (ret []byte, err error) { + var ( + tx = self.tx + block = self.block + initiator = self.Sender() + state = self.state + ) + + closure := NewClosure(initiator, context, script, state, self.gas, tx.GasPrice) + vm := NewVm(state, nil, RuntimeVars{ + Origin: initiator.Address(), + BlockNumber: block.BlockInfo().Number, + PrevHash: block.PrevHash, + Coinbase: block.Coinbase, + Time: block.Time, + Diff: block.Difficulty, + Value: tx.Value, + }) + ret, _, err = closure.Call(vm, tx.Data, nil) + + return +} -- cgit v1.2.3 From c734dde982c4ce778afa074e94efb09e552dbd84 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 13 Jun 2014 13:06:27 +0200 Subject: comments & refactor --- ethchain/state_manager.go | 4 +++- ethchain/state_transition.go | 20 ++++++++++++++++---- 2 files changed, 19 insertions(+), 5 deletions(-) (limited to 'ethchain') diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 576afa8d3..c68d5e001 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -124,6 +124,9 @@ done: } } + // Notify all subscribers + self.Ethereum.Reactor().Post("newTx:post", tx) + txGas.Sub(txGas, st.gas) accumelative := new(big.Int).Set(totalUsedGas.Add(totalUsedGas, txGas)) receipt := &Receipt{tx, ethutil.CopyBytes(state.Root().([]byte)), accumelative} @@ -158,7 +161,6 @@ func (sm *StateManager) ProcessBlock(state *State, parent, block *Block, dontRea hash := block.Hash() if sm.bc.HasBlock(hash) { - //fmt.Println("[STATE] We already have this block, ignoring") return nil } diff --git a/ethchain/state_transition.go b/ethchain/state_transition.go index 6ec9205e9..1256d019c 100644 --- a/ethchain/state_transition.go +++ b/ethchain/state_transition.go @@ -6,6 +6,22 @@ import ( "math/big" ) +/* + * The State transitioning model + * + * A state transition is a change made when a transaction is applied to the current world state + * The state transitioning model does all all the necessary work to work out a valid new state root. + * 1) Nonce handling + * 2) Pre pay / buy gas of the coinbase (miner) + * 3) Create a new state object if the recipient is \0*32 + * 4) Value transfer + * == If contract creation == + * 4a) Attempt to run transaction data + * 4b) If valid, use result as code for the new state object + * == end == + * 5) Run Script section + * 6) Derive new state root + */ type StateTransition struct { coinbase []byte tx *Transaction @@ -115,10 +131,6 @@ func (self *StateTransition) TransitionState() (err error) { } sender.Nonce += 1 - defer func() { - // Notify all subscribers - //self.Ethereum.Reactor().Post("newTx:post", tx) - }() if err = self.BuyGas(); err != nil { return err -- cgit v1.2.3 From 81245473486dd680b7121d4b227ca8a57d07b4b1 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 13 Jun 2014 16:06:27 +0200 Subject: Moving a head closer to interop --- ethchain/closure.go | 26 ++++++++++++++------------ ethchain/state_object.go | 8 +++++--- ethchain/state_transition.go | 32 ++++++++++++++++++++++++-------- ethchain/vm.go | 31 ++++++++++++++++++------------- 4 files changed, 61 insertions(+), 36 deletions(-) (limited to 'ethchain') diff --git a/ethchain/closure.go b/ethchain/closure.go index 5c9c3e47c..32b297e90 100644 --- a/ethchain/closure.go +++ b/ethchain/closure.go @@ -17,7 +17,7 @@ type ClosureRef interface { // Basic inline closure object which implement the 'closure' interface type Closure struct { - callee ClosureRef + caller ClosureRef object *StateObject Script []byte State *State @@ -28,12 +28,14 @@ type Closure struct { } // Create a new closure for the given data items -func NewClosure(callee ClosureRef, object *StateObject, script []byte, state *State, gas, price *big.Int) *Closure { - c := &Closure{callee: callee, object: object, Script: script, State: state, Args: nil} +func NewClosure(caller ClosureRef, object *StateObject, script []byte, state *State, gas, price *big.Int) *Closure { + c := &Closure{caller: caller, object: object, Script: script, State: state, Args: nil} - // In most cases gas, price and value are pointers to transaction objects + // Gas should be a pointer so it can safely be reduced through the run + // This pointer will be off the state transition + c.Gas = gas //new(big.Int).Set(gas) + // In most cases price and value are pointers to transaction objects // and we don't want the transaction's values to change. - c.Gas = new(big.Int).Set(gas) c.Price = new(big.Int).Set(price) c.UsedGas = new(big.Int) @@ -83,11 +85,11 @@ func (c *Closure) Call(vm *Vm, args []byte, hook DebugHook) ([]byte, *big.Int, e } func (c *Closure) Return(ret []byte) []byte { - // Return the remaining gas to the callee - // If no callee is present return it to + // Return the remaining gas to the caller + // If no caller is present return it to // the origin (i.e. contract or tx) - if c.callee != nil { - c.callee.ReturnGas(c.Gas, c.Price, c.State) + if c.caller != nil { + c.caller.ReturnGas(c.Gas, c.Price, c.State) } else { c.object.ReturnGas(c.Gas, c.Price, c.State) } @@ -107,7 +109,7 @@ func (c *Closure) UseGas(gas *big.Int) bool { return true } -// Implement the Callee interface +// Implement the caller interface func (c *Closure) ReturnGas(gas, price *big.Int, state *State) { // Return the gas to the closure c.Gas.Add(c.Gas, gas) @@ -118,8 +120,8 @@ func (c *Closure) Object() *StateObject { return c.object } -func (c *Closure) Callee() ClosureRef { - return c.callee +func (c *Closure) Caller() ClosureRef { + return c.caller } func (c *Closure) N() *big.Int { diff --git a/ethchain/state_object.go b/ethchain/state_object.go index b92374882..12ebf8e9b 100644 --- a/ethchain/state_object.go +++ b/ethchain/state_object.go @@ -77,7 +77,7 @@ func (c *StateObject) SetAddr(addr []byte, value interface{}) { func (c *StateObject) SetStorage(num *big.Int, val *ethutil.Value) { addr := ethutil.BigToBytes(num, 256) - //fmt.Println("storing", val.BigInt(), "@", num) + //fmt.Printf("sstore %x => %v\n", addr, val) c.SetAddr(addr, val) } @@ -102,8 +102,10 @@ func (c *StateObject) GetInstr(pc *big.Int) *ethutil.Value { // Return the gas back to the origin. Used by the Virtual machine or Closures func (c *StateObject) ReturnGas(gas, price *big.Int, state *State) { - remainder := new(big.Int).Mul(gas, price) - c.AddAmount(remainder) + /* + remainder := new(big.Int).Mul(gas, price) + c.AddAmount(remainder) + */ } func (c *StateObject) AddAmount(amount *big.Int) { diff --git a/ethchain/state_transition.go b/ethchain/state_transition.go index 1256d019c..a080c5602 100644 --- a/ethchain/state_transition.go +++ b/ethchain/state_transition.go @@ -116,7 +116,7 @@ func (self *StateTransition) TransitionState() (err error) { defer func() { if r := recover(); r != nil { ethutil.Config.Log.Infoln(r) - err = fmt.Errorf("%v", r) + err = fmt.Errorf("state transition err %v", r) } }() @@ -126,41 +126,51 @@ func (self *StateTransition) TransitionState() (err error) { receiver *StateObject ) + // Make sure this transaction's nonce is correct if sender.Nonce != tx.Nonce { return NonceError(tx.Nonce, sender.Nonce) } + // Increment the nonce for the next transaction sender.Nonce += 1 + // Pre-pay gas / Buy gas of the coinbase account if err = self.BuyGas(); err != nil { return err } + // Get the receiver (TODO fix this, if coinbase is the receiver we need to save/retrieve) receiver = self.Receiver() + // Transaction gas if err = self.UseGas(GasTx); err != nil { return err } + // Pay data gas dataPrice := big.NewInt(int64(len(tx.Data))) dataPrice.Mul(dataPrice, GasData) if err = self.UseGas(dataPrice); err != nil { return err } - if receiver == nil { // Contract + // If the receiver is nil it's a contract (\0*32). + if receiver == nil { + // Create a new state object for the contract receiver = self.MakeStateObject(self.state, tx) if receiver == nil { return fmt.Errorf("ERR. Unable to create contract with transaction %v", tx) } } + // Transfer value from sender to receiver if err = self.transferValue(sender, receiver); err != nil { return err } + // Process the init code and create 'valid' contract if tx.CreatesContract() { - fmt.Println(Disassemble(receiver.Init())) + //fmt.Println(Disassemble(receiver.Init())) // Evaluate the initialization script // and use the return value as the // script section for the state object. @@ -173,6 +183,10 @@ func (self *StateTransition) TransitionState() (err error) { receiver.script = code } + // Return remaining gas + remaining := new(big.Int).Mul(self.gas, tx.GasPrice) + sender.AddAmount(remaining) + self.state.UpdateStateObject(sender) self.state.UpdateStateObject(receiver) @@ -184,12 +198,14 @@ func (self *StateTransition) transferValue(sender, receiver *StateObject) error return fmt.Errorf("Insufficient funds to transfer value. Req %v, has %v", self.tx.Value, sender.Amount) } - // Subtract the amount from the senders account - sender.SubAmount(self.tx.Value) - // Add the amount to receivers account which should conclude this transaction - receiver.AddAmount(self.tx.Value) + if self.tx.Value.Cmp(ethutil.Big0) > 0 { + // Subtract the amount from the senders account + sender.SubAmount(self.tx.Value) + // Add the amount to receivers account which should conclude this transaction + receiver.AddAmount(self.tx.Value) - ethutil.Config.Log.Debugf("%x => %x (%v) %x\n", sender.Address()[:4], receiver.Address()[:4], self.tx.Value, self.tx.Hash()) + ethutil.Config.Log.Debugf("%x => %x (%v) %x\n", sender.Address()[:4], receiver.Address()[:4], self.tx.Value, self.tx.Hash()) + } return nil } diff --git a/ethchain/vm.go b/ethchain/vm.go index e17264697..f0059f6ac 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -114,14 +114,18 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro } gas := new(big.Int) - setStepGasUsage := func(amount *big.Int) { + addStepGasUsage := func(amount *big.Int) { gas.Add(gas, amount) } + addStepGasUsage(GasStep) + var newMemSize uint64 = 0 switch op { + case STOP: + case SUICIDE: case SLOAD: - setStepGasUsage(GasSLoad) + gas.Set(GasSLoad) case SSTORE: var mult *big.Int y, x := stack.Peekn() @@ -133,12 +137,14 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro } else { mult = ethutil.Big1 } - setStepGasUsage(new(big.Int).Mul(mult, GasSStore)) + gas = new(big.Int).Mul(mult, GasSStore) case BALANCE: - setStepGasUsage(GasBalance) + gas.Set(GasBalance) case MSTORE: require(2) newMemSize = stack.Peek().Uint64() + 32 + case MLOAD: + case MSTORE8: require(2) newMemSize = stack.Peek().Uint64() + 1 @@ -149,7 +155,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro case SHA3: require(2) - setStepGasUsage(GasSha) + gas.Set(GasSha) newMemSize = stack.Peek().Uint64() + stack.data[stack.Len()-2].Uint64() case CALLDATACOPY: @@ -162,7 +168,8 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro newMemSize = stack.Peek().Uint64() + stack.data[stack.Len()-3].Uint64() case CALL: require(7) - setStepGasUsage(GasCall) + gas.Set(GasCall) + addStepGasUsage(stack.data[stack.Len()-1]) x := stack.data[stack.Len()-6].Uint64() + stack.data[stack.Len()-7].Uint64() y := stack.data[stack.Len()-4].Uint64() + stack.data[stack.Len()-5].Uint64() @@ -170,17 +177,15 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro newMemSize = uint64(math.Max(float64(x), float64(y))) case CREATE: require(3) - setStepGasUsage(GasCreate) + gas.Set(GasCreate) newMemSize = stack.data[stack.Len()-2].Uint64() + stack.data[stack.Len()-3].Uint64() - default: - setStepGasUsage(GasStep) } newMemSize = (newMemSize + 31) / 32 * 32 if newMemSize > uint64(mem.Len()) { m := GasMemory.Uint64() * (newMemSize - uint64(mem.Len())) / 32 - setStepGasUsage(big.NewInt(int64(m))) + addStepGasUsage(big.NewInt(int64(m))) } if !closure.UseGas(gas) { @@ -355,7 +360,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro case ORIGIN: stack.Push(ethutil.BigD(vm.vars.Origin)) case CALLER: - stack.Push(ethutil.BigD(closure.Callee().Address())) + stack.Push(ethutil.BigD(closure.caller.Address())) case CALLVALUE: stack.Push(vm.vars.Value) case CALLDATALOAD: @@ -492,7 +497,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro snapshot := vm.state.Snapshot() // Generate a new address - addr := ethutil.CreateAddress(closure.callee.Address(), closure.callee.N()) + addr := ethutil.CreateAddress(closure.caller.Address(), closure.caller.N()) // Create a new contract contract := NewContract(addr, value, []byte("")) // Set the init script @@ -503,7 +508,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro //closure.UseGas(gas) // Create the closure - c := NewClosure(closure.callee, + c := NewClosure(closure.caller, closure.Object(), contract.initScript, vm.state, -- cgit v1.2.3 From 63883bf27d8b87f601e1603e9024a279b91bffb7 Mon Sep 17 00:00:00 2001 From: obscuren Date: Sat, 14 Jun 2014 11:46:09 +0200 Subject: Moving closer to interop --- ethchain/asm.go | 2 +- ethchain/block_chain.go | 2 ++ ethchain/state_transition.go | 16 ++++++++++------ ethchain/types.go | 2 +- 4 files changed, 14 insertions(+), 8 deletions(-) (limited to 'ethchain') diff --git a/ethchain/asm.go b/ethchain/asm.go index 277326ff9..c267f9b55 100644 --- a/ethchain/asm.go +++ b/ethchain/asm.go @@ -28,7 +28,7 @@ func Disassemble(script []byte) (asm []string) { if len(data) == 0 { data = []byte{0} } - asm = append(asm, fmt.Sprintf("0x%x", data)) + asm = append(asm, fmt.Sprintf("%#x", data)) pc.Add(pc, big.NewInt(a-1)) } diff --git a/ethchain/block_chain.go b/ethchain/block_chain.go index 8cede2403..19b5248d7 100644 --- a/ethchain/block_chain.go +++ b/ethchain/block_chain.go @@ -55,6 +55,8 @@ func (bc *BlockChain) NewBlock(coinbase []byte) *Block { nil, "") + block.MinGasPrice = big.NewInt(10000000000000) + if bc.CurrentBlock != nil { var mul *big.Int if block.Time < lastBlockTime+42 { diff --git a/ethchain/state_transition.go b/ethchain/state_transition.go index a080c5602..5ded0cddd 100644 --- a/ethchain/state_transition.go +++ b/ethchain/state_transition.go @@ -131,14 +131,21 @@ func (self *StateTransition) TransitionState() (err error) { return NonceError(tx.Nonce, sender.Nonce) } - // Increment the nonce for the next transaction - sender.Nonce += 1 - // Pre-pay gas / Buy gas of the coinbase account if err = self.BuyGas(); err != nil { return err } + // XXX Transactions after this point are considered valid. + + defer func() { + self.state.UpdateStateObject(sender) + self.state.UpdateStateObject(receiver) + }() + + // Increment the nonce for the next transaction + sender.Nonce += 1 + // Get the receiver (TODO fix this, if coinbase is the receiver we need to save/retrieve) receiver = self.Receiver() @@ -187,9 +194,6 @@ func (self *StateTransition) TransitionState() (err error) { remaining := new(big.Int).Mul(self.gas, tx.GasPrice) sender.AddAmount(remaining) - self.state.UpdateStateObject(sender) - self.state.UpdateStateObject(receiver) - return nil } diff --git a/ethchain/types.go b/ethchain/types.go index ee70a8d28..d89fad147 100644 --- a/ethchain/types.go +++ b/ethchain/types.go @@ -226,7 +226,7 @@ var opCodeToString = map[OpCode]string{ func (o OpCode) String() string { str := opCodeToString[o] if len(str) == 0 { - return fmt.Sprintf("Missing opcode 0x%x", int(o)) + return fmt.Sprintf("Missing opcode %#x", int(o)) } return str -- cgit v1.2.3 From 5871dbaf5a832a4fd34bdb22cf479d6b0b4da9fb Mon Sep 17 00:00:00 2001 From: obscuren Date: Sun, 15 Jun 2014 00:10:42 +0200 Subject: Set contract addr for new transactions --- ethchain/transaction.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'ethchain') diff --git a/ethchain/transaction.go b/ethchain/transaction.go index 7aaab2fd1..3d52e4f73 100644 --- a/ethchain/transaction.go +++ b/ethchain/transaction.go @@ -25,7 +25,7 @@ type Transaction struct { } func NewContractCreationTx(value, gas, gasPrice *big.Int, script []byte) *Transaction { - return &Transaction{Value: value, Gas: gas, GasPrice: gasPrice, Data: script, contractCreation: true} + return &Transaction{Recipient: ContractAddr, Value: value, Gas: gas, GasPrice: gasPrice, Data: script, contractCreation: true} } func NewTransactionMessage(to []byte, value, gas, gasPrice *big.Int, data []byte) *Transaction { -- cgit v1.2.3 From d80f999a215b74e23d21f3548486f996c3eb028d Mon Sep 17 00:00:00 2001 From: obscuren Date: Sun, 15 Jun 2014 00:11:06 +0200 Subject: Run contracts --- ethchain/state_transition.go | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'ethchain') diff --git a/ethchain/state_transition.go b/ethchain/state_transition.go index 5ded0cddd..2e2a51f72 100644 --- a/ethchain/state_transition.go +++ b/ethchain/state_transition.go @@ -188,6 +188,13 @@ func (self *StateTransition) TransitionState() (err error) { } receiver.script = code + } else { + if len(receiver.Script()) > 0 { + _, err := self.Eval(receiver.Script(), receiver) + if err != nil { + return fmt.Errorf("Error during code execution %v", err) + } + } } // Return remaining gas -- cgit v1.2.3 From 8198fd7913ea4066afb5c0cf5e57fa5ec4888fac Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 16 Jun 2014 00:51:04 +0200 Subject: Cache whole objects instead of states only --- ethchain/state.go | 98 +++++++++++++++++++++++++++++++++++++++++++++++- ethchain/state_object.go | 21 +++++++++++ 2 files changed, 117 insertions(+), 2 deletions(-) (limited to 'ethchain') diff --git a/ethchain/state.go b/ethchain/state.go index 5af748e00..f413fb8ed 100644 --- a/ethchain/state.go +++ b/ethchain/state.go @@ -16,14 +16,17 @@ type State struct { // Nested states states map[string]*State + stateObjects map[string]*StateObject + manifest *Manifest } // Create a new state from a given trie func NewState(trie *ethutil.Trie) *State { - return &State{trie: trie, states: make(map[string]*State), manifest: NewManifest()} + return &State{trie: trie, states: make(map[string]*State), stateObjects: make(map[string]*StateObject), manifest: NewManifest()} } +/* // Resets the trie and all siblings func (s *State) Reset() { s.trie.Undo() @@ -43,6 +46,35 @@ func (s *State) Sync() { s.trie.Sync() } +*/ + +// Resets the trie and all siblings +func (s *State) Reset() { + s.trie.Undo() + + // Reset all nested states + for _, stateObject := range s.stateObjects { + if stateObject.state == nil { + continue + } + + stateObject.state.Reset() + } +} + +// Syncs the trie and all siblings +func (s *State) Sync() { + // Sync all nested states + for _, stateObject := range s.stateObjects { + if stateObject.state == nil { + continue + } + + stateObject.state.Sync() + } + + s.trie.Sync() +} // Purges the current trie. func (s *State) Purge() int { @@ -54,6 +86,7 @@ func (s *State) EachStorage(cb ethutil.EachCallback) { it.Each(cb) } +/* func (s *State) GetStateObject(addr []byte) *StateObject { data := s.trie.Get(string(addr)) if data == "" { @@ -78,7 +111,6 @@ func (s *State) UpdateStateObject(object *StateObject) { if object.state != nil && s.states[string(addr)] == nil { s.states[string(addr)] = object.state - //fmt.Printf("update cached #%d %x addr: %x\n", object.state.trie.Cache().Len(), object.state.Root(), addr[0:4]) } ethutil.Config.Db.Put(ethutil.Sha3Bin(object.Script()), object.Script()) @@ -96,13 +128,66 @@ func (s *State) GetAccount(addr []byte) (account *StateObject) { account = NewStateObjectFromBytes(addr, []byte(data)) } + // Check if there's a cached state for this contract + cachedStateObject := s.states[string(addr)] + if cachedStateObject != nil { + account.state = cachedStateObject + } + return } +*/ + +func (self *State) UpdateStateObject(stateObject *StateObject) { + addr := stateObject.Address() + + if self.stateObjects[string(addr)] == nil { + self.stateObjects[string(addr)] = stateObject + } + + ethutil.Config.Db.Put(ethutil.Sha3Bin(stateObject.Script()), stateObject.Script()) + + self.trie.Update(string(addr), string(stateObject.RlpEncode())) + + self.manifest.AddObjectChange(stateObject) +} + +func (self *State) GetStateObject(addr []byte) *StateObject { + stateObject := self.stateObjects[string(addr)] + if stateObject != nil { + return stateObject + } + + data := self.trie.Get(string(addr)) + if len(data) == 0 { + return nil + } + + stateObject = NewStateObjectFromBytes(addr, []byte(data)) + self.stateObjects[string(addr)] = stateObject + + return stateObject +} + +func (self *State) GetOrNewStateObject(addr []byte) *StateObject { + stateObject := self.GetStateObject(addr) + if stateObject == nil { + stateObject = NewStateObject(addr) + self.stateObjects[string(addr)] = stateObject + } + + return stateObject +} + +func (self *State) GetAccount(addr []byte) *StateObject { + return self.GetOrNewStateObject(addr) +} func (s *State) Cmp(other *State) bool { return s.trie.Cmp(other.trie) } +/* func (s *State) Copy() *State { state := NewState(s.trie.Copy()) for k, subState := range s.states { @@ -111,6 +196,15 @@ func (s *State) Copy() *State { return state } +*/ +func (self *State) Copy() *State { + state := NewState(self.trie.Copy()) + for k, stateObject := range self.stateObjects { + state.stateObjects[k] = stateObject.Copy() + } + + return state +} func (s *State) Snapshot() *State { return s.Copy() diff --git a/ethchain/state_object.go b/ethchain/state_object.go index 12ebf8e9b..3775d436c 100644 --- a/ethchain/state_object.go +++ b/ethchain/state_object.go @@ -38,6 +38,10 @@ func MakeContract(tx *Transaction, state *State) *StateObject { return nil } +func NewStateObject(addr []byte) *StateObject { + return &StateObject{address: addr, Amount: new(big.Int)} +} + func NewContract(address []byte, Amount *big.Int, root []byte) *StateObject { contract := &StateObject{address: address, Amount: Amount, Nonce: 0} contract.state = NewState(ethutil.NewTrie(ethutil.Config.Db, string(root))) @@ -146,6 +150,23 @@ func (self *StateObject) BuyGas(gas, price *big.Int) error { return nil } +func (self *StateObject) Copy() *StateObject { + stCopy := &StateObject{} + stCopy.address = make([]byte, len(self.address)) + copy(stCopy.address, self.address) + stCopy.Amount = new(big.Int).Set(self.Amount) + stCopy.ScriptHash = make([]byte, len(self.ScriptHash)) + copy(stCopy.ScriptHash, self.ScriptHash) + stCopy.Nonce = self.Nonce + stCopy.state = self.state.Copy() + stCopy.script = make([]byte, len(self.script)) + copy(stCopy.script, self.script) + stCopy.initScript = make([]byte, len(self.initScript)) + copy(stCopy.initScript, self.initScript) + + return stCopy +} + // Returns the address of the contract/account func (c *StateObject) Address() []byte { return c.address -- cgit v1.2.3 From 02d8ad030fd1293a03cf905d50533678aaea40fd Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 16 Jun 2014 10:35:35 +0200 Subject: Keeping old code for reference --- ethchain/state.go | 177 +++++++++++++++++++++++++++--------------------------- 1 file changed, 89 insertions(+), 88 deletions(-) (limited to 'ethchain') diff --git a/ethchain/state.go b/ethchain/state.go index f413fb8ed..9a9d0a278 100644 --- a/ethchain/state.go +++ b/ethchain/state.go @@ -26,28 +26,6 @@ func NewState(trie *ethutil.Trie) *State { return &State{trie: trie, states: make(map[string]*State), stateObjects: make(map[string]*StateObject), manifest: NewManifest()} } -/* -// Resets the trie and all siblings -func (s *State) Reset() { - s.trie.Undo() - - // Reset all nested states - for _, state := range s.states { - state.Reset() - } -} - -// Syncs the trie and all siblings -func (s *State) Sync() { - // Sync all nested states - for _, state := range s.states { - state.Sync() - } - - s.trie.Sync() -} -*/ - // Resets the trie and all siblings func (s *State) Reset() { s.trie.Undo() @@ -86,58 +64,6 @@ func (s *State) EachStorage(cb ethutil.EachCallback) { it.Each(cb) } -/* -func (s *State) GetStateObject(addr []byte) *StateObject { - data := s.trie.Get(string(addr)) - if data == "" { - return nil - } - - stateObject := NewStateObjectFromBytes(addr, []byte(data)) - - // Check if there's a cached state for this contract - cachedStateObject := s.states[string(addr)] - if cachedStateObject != nil { - //fmt.Printf("get cached #%d %x addr: %x\n", cachedStateObject.trie.Cache().Len(), cachedStateObject.Root(), addr[0:4]) - stateObject.state = cachedStateObject - } - - return stateObject -} - -// Updates any given state object -func (s *State) UpdateStateObject(object *StateObject) { - addr := object.Address() - - if object.state != nil && s.states[string(addr)] == nil { - s.states[string(addr)] = object.state - } - - ethutil.Config.Db.Put(ethutil.Sha3Bin(object.Script()), object.Script()) - - s.trie.Update(string(addr), string(object.RlpEncode())) - - s.manifest.AddObjectChange(object) -} - -func (s *State) GetAccount(addr []byte) (account *StateObject) { - data := s.trie.Get(string(addr)) - if data == "" { - account = NewAccount(addr, big.NewInt(0)) - } else { - account = NewStateObjectFromBytes(addr, []byte(data)) - } - - // Check if there's a cached state for this contract - cachedStateObject := s.states[string(addr)] - if cachedStateObject != nil { - account.state = cachedStateObject - } - - return -} -*/ - func (self *State) UpdateStateObject(stateObject *StateObject) { addr := stateObject.Address() @@ -187,23 +113,17 @@ func (s *State) Cmp(other *State) bool { return s.trie.Cmp(other.trie) } -/* -func (s *State) Copy() *State { - state := NewState(s.trie.Copy()) - for k, subState := range s.states { - state.states[k] = subState.Copy() - } - - return state -} -*/ func (self *State) Copy() *State { - state := NewState(self.trie.Copy()) - for k, stateObject := range self.stateObjects { - state.stateObjects[k] = stateObject.Copy() + if self.trie != nil { + state := NewState(self.trie.Copy()) + for k, stateObject := range self.stateObjects { + state.stateObjects[k] = stateObject.Copy() + } + + return state } - return state + return nil } func (s *State) Snapshot() *State { @@ -259,3 +179,84 @@ func (m *Manifest) AddStorageChange(stateObject *StateObject, storageAddr []byte m.storageChanges[string(stateObject.Address())][string(storageAddr)] = storage } + +/* + +// Resets the trie and all siblings +func (s *State) Reset() { + s.trie.Undo() + + // Reset all nested states + for _, state := range s.states { + state.Reset() + } +} + +// Syncs the trie and all siblings +func (s *State) Sync() { + // Sync all nested states + for _, state := range s.states { + state.Sync() + } + + s.trie.Sync() +} +func (s *State) GetStateObject(addr []byte) *StateObject { + data := s.trie.Get(string(addr)) + if data == "" { + return nil + } + + stateObject := NewStateObjectFromBytes(addr, []byte(data)) + + // Check if there's a cached state for this contract + cachedStateObject := s.states[string(addr)] + if cachedStateObject != nil { + //fmt.Printf("get cached #%d %x addr: %x\n", cachedStateObject.trie.Cache().Len(), cachedStateObject.Root(), addr[0:4]) + stateObject.state = cachedStateObject + } + + return stateObject +} + +// Updates any given state object +func (s *State) UpdateStateObject(object *StateObject) { + addr := object.Address() + + if object.state != nil && s.states[string(addr)] == nil { + s.states[string(addr)] = object.state + } + + ethutil.Config.Db.Put(ethutil.Sha3Bin(object.Script()), object.Script()) + + s.trie.Update(string(addr), string(object.RlpEncode())) + + s.manifest.AddObjectChange(object) +} + +func (s *State) GetAccount(addr []byte) (account *StateObject) { + data := s.trie.Get(string(addr)) + if data == "" { + account = NewAccount(addr, big.NewInt(0)) + } else { + account = NewStateObjectFromBytes(addr, []byte(data)) + } + + // Check if there's a cached state for this contract + cachedStateObject := s.states[string(addr)] + if cachedStateObject != nil { + account.state = cachedStateObject + } + + return +} + +func (s *State) Copy() *State { + state := NewState(s.trie.Copy()) + for k, subState := range s.states { + state.states[k] = subState.Copy() + } + + return state +} +*/ -- cgit v1.2.3 From 1d76e433f7866763674e4ef06a4a4d9463276490 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 16 Jun 2014 10:40:21 +0200 Subject: Removed some comments --- ethchain/state_transition.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'ethchain') diff --git a/ethchain/state_transition.go b/ethchain/state_transition.go index 2e2a51f72..94546e556 100644 --- a/ethchain/state_transition.go +++ b/ethchain/state_transition.go @@ -102,7 +102,7 @@ func (self *StateTransition) BuyGas() error { if err != nil { return err } - self.state.UpdateStateObject(coinbase) + //self.state.UpdateStateObject(coinbase) self.AddGas(self.tx.Gas) sender.SubAmount(self.tx.GasValue()) @@ -177,7 +177,6 @@ func (self *StateTransition) TransitionState() (err error) { // Process the init code and create 'valid' contract if tx.CreatesContract() { - //fmt.Println(Disassemble(receiver.Init())) // Evaluate the initialization script // and use the return value as the // script section for the state object. -- cgit v1.2.3 From 15d1f753f7ac2f72ce0637135a17d86b29f15515 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 16 Jun 2014 11:13:06 +0200 Subject: Removed old fees --- ethchain/fees.go | 24 ------------------------ 1 file changed, 24 deletions(-) (limited to 'ethchain') diff --git a/ethchain/fees.go b/ethchain/fees.go index c0a5d2d88..743be86a2 100644 --- a/ethchain/fees.go +++ b/ethchain/fees.go @@ -4,30 +4,6 @@ import ( "math/big" ) -var TxFeeRat *big.Int = big.NewInt(100000000000000) - -var TxFee *big.Int = big.NewInt(100) -var StepFee *big.Int = big.NewInt(1) -var StoreFee *big.Int = big.NewInt(5) -var DataFee *big.Int = big.NewInt(20) -var ExtroFee *big.Int = big.NewInt(40) -var CryptoFee *big.Int = big.NewInt(20) -var ContractFee *big.Int = big.NewInt(100) - var BlockReward *big.Int = big.NewInt(1.5e+18) var UncleReward *big.Int = big.NewInt(1.125e+18) var UncleInclusionReward *big.Int = big.NewInt(1.875e+17) - -var Period1Reward *big.Int = new(big.Int) -var Period2Reward *big.Int = new(big.Int) -var Period3Reward *big.Int = new(big.Int) -var Period4Reward *big.Int = new(big.Int) - -func InitFees() { - StepFee.Mul(StepFee, TxFeeRat) - StoreFee.Mul(StoreFee, TxFeeRat) - DataFee.Mul(DataFee, TxFeeRat) - ExtroFee.Mul(ExtroFee, TxFeeRat) - CryptoFee.Mul(CryptoFee, TxFeeRat) - ContractFee.Mul(ContractFee, TxFeeRat) -} -- cgit v1.2.3 From 7b55bcf4840fc11315ffd055ce7d419ac9baf168 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 16 Jun 2014 11:13:19 +0200 Subject: Removed old fees --- ethchain/transaction_pool.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'ethchain') diff --git a/ethchain/transaction_pool.go b/ethchain/transaction_pool.go index 6538b0029..24836222a 100644 --- a/ethchain/transaction_pool.go +++ b/ethchain/transaction_pool.go @@ -179,7 +179,7 @@ func (pool *TxPool) ValidateTransaction(tx *Transaction) error { //sender := pool.Ethereum.StateManager().procState.GetAccount(tx.Sender()) sender := pool.Ethereum.StateManager().CurrentState().GetAccount(tx.Sender()) - totAmount := new(big.Int).Add(tx.Value, new(big.Int).Mul(TxFee, TxFeeRat)) + 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.Amount.Cmp(totAmount) < 0 { -- cgit v1.2.3 From 9f62d441a7c785b88f89d52643a9deaa822af15e Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 16 Jun 2014 11:14:01 +0200 Subject: Moved gas limit err check to buy gas --- ethchain/state_manager.go | 8 +++--- ethchain/state_object.go | 21 ++++++++++++--- ethchain/state_transition.go | 4 +-- ethchain/vm.go | 63 ++++++++++++++++++++++---------------------- 4 files changed, 56 insertions(+), 40 deletions(-) (limited to 'ethchain') diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index c68d5e001..4b1b872cc 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -97,7 +97,7 @@ func (sm *StateManager) BlockChain() *BlockChain { return sm.bc } -func (self *StateManager) ProcessTransactions(coinbase []byte, state *State, block, parent *Block, txs Transactions) (Receipts, Transactions, Transactions, error) { +func (self *StateManager) ProcessTransactions(coinbase *StateObject, state *State, block, parent *Block, txs Transactions) (Receipts, Transactions, Transactions, error) { var ( receipts Receipts handled, unhandled Transactions @@ -177,9 +177,12 @@ func (sm *StateManager) ProcessBlock(state *State, parent, block *Block, dontRea } fmt.Println(block.Receipts()) + coinbase := state.GetOrNewStateObject(block.Coinbase) + coinbase.gasPool = block.CalcGasLimit(parent) + // Process the transactions on to current block //sm.ApplyTransactions(block.Coinbase, state, parent, block.Transactions()) - sm.ProcessTransactions(block.Coinbase, state, block, parent, block.Transactions()) + sm.ProcessTransactions(coinbase, state, block, parent, block.Transactions()) // Block validation if err := sm.ValidateBlock(block); err != nil { @@ -194,7 +197,6 @@ func (sm *StateManager) ProcessBlock(state *State, parent, block *Block, dontRea return err } - //if !sm.compState.Cmp(state) { if !block.State().Cmp(state) { return fmt.Errorf("Invalid merkle root.\nrec: %x\nis: %x", block.State().trie.Root, state.trie.Root) } diff --git a/ethchain/state_object.go b/ethchain/state_object.go index 3775d436c..03f4c9219 100644 --- a/ethchain/state_object.go +++ b/ethchain/state_object.go @@ -17,6 +17,11 @@ type StateObject struct { state *State script []byte initScript []byte + + // Total gas pool is the total amount of gas currently + // left if this object is the coinbase. Gas is directly + // purchased of the coinbase. + gasPool *big.Int } // Converts an transaction in to a state object @@ -139,14 +144,22 @@ func (c *StateObject) ConvertGas(gas, price *big.Int) error { return nil } +func (self *StateObject) SetGasPool(gasLimit *big.Int) { + self.gasPool = new(big.Int).Set(gasLimit) + + ethutil.Config.Log.Printf(ethutil.LogLevelSystem, "%x fuel (+ %v)", self.Address(), self.gasPool) +} + func (self *StateObject) BuyGas(gas, price *big.Int) error { + if self.gasPool.Cmp(gas) < 0 { + return GasLimitError(self.gasPool, gas) + } + rGas := new(big.Int).Set(gas) rGas.Mul(rGas, price) self.AddAmount(rGas) - // TODO Do sub from TotalGasPool - // and check if enough left return nil } @@ -158,7 +171,9 @@ func (self *StateObject) Copy() *StateObject { stCopy.ScriptHash = make([]byte, len(self.ScriptHash)) copy(stCopy.ScriptHash, self.ScriptHash) stCopy.Nonce = self.Nonce - stCopy.state = self.state.Copy() + if self.state != nil { + stCopy.state = self.state.Copy() + } stCopy.script = make([]byte, len(self.script)) copy(stCopy.script, self.script) stCopy.initScript = make([]byte, len(self.initScript)) diff --git a/ethchain/state_transition.go b/ethchain/state_transition.go index 94546e556..76936aa7c 100644 --- a/ethchain/state_transition.go +++ b/ethchain/state_transition.go @@ -32,8 +32,8 @@ type StateTransition struct { cb, rec, sen *StateObject } -func NewStateTransition(coinbase []byte, tx *Transaction, state *State, block *Block) *StateTransition { - return &StateTransition{coinbase, tx, new(big.Int), state, block, nil, nil, nil} +func NewStateTransition(coinbase *StateObject, tx *Transaction, state *State, block *Block) *StateTransition { + return &StateTransition{coinbase.Address(), tx, new(big.Int), state, block, coinbase, nil, nil} } func (self *StateTransition) Coinbase() *StateObject { diff --git a/ethchain/vm.go b/ethchain/vm.go index f0059f6ac..2ba0e2ef3 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -169,7 +169,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro case CALL: require(7) gas.Set(GasCall) - addStepGasUsage(stack.data[stack.Len()-1]) + addStepGasUsage(stack.data[stack.Len()-2]) x := stack.data[stack.Len()-6].Uint64() + stack.data[stack.Len()-7].Uint64() y := stack.data[stack.Len()-4].Uint64() + stack.data[stack.Len()-5].Uint64() @@ -529,6 +529,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro vm.state.UpdateStateObject(contract) } case CALL: + // TODO RE-WRITE require(7) // Closure addr addr := stack.Pop() @@ -538,46 +539,44 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro inSize, inOffset := stack.Popn() // Pop return size and offset retSize, retOffset := stack.Popn() - // Make sure there's enough gas - if closure.Gas.Cmp(gas) < 0 { - stack.Push(ethutil.BigFalse) - - break - } // Get the arguments from the memory args := mem.Get(inOffset.Int64(), inSize.Int64()) snapshot := vm.state.Snapshot() - // Fetch the contract which will serve as the closure body - contract := vm.state.GetStateObject(addr.Bytes()) - - if contract != nil { - // Prepay for the gas - //closure.UseGas(gas) + closure.object.Nonce += 1 + if closure.object.Amount.Cmp(value) < 0 { + ethutil.Config.Log.Debugf("Insufficient funds to transfer value. Req %v, has %v", value, closure.object.Amount) - // Add the value to the state object - contract.AddAmount(value) - - // Create a new callable closure - closure := NewClosure(closure, contract, contract.script, vm.state, gas, closure.Price) - // Executer the closure and get the return value (if any) - ret, _, err := closure.Call(vm, args, hook) - if err != nil { - stack.Push(ethutil.BigFalse) - // Reset the changes applied this object - vm.state.Revert(snapshot) + stack.Push(ethutil.BigFalse) + } else { + // Fetch the contract which will serve as the closure body + contract := vm.state.GetStateObject(addr.Bytes()) + + if contract != nil { + // Add the value to the state object + contract.AddAmount(value) + + // Create a new callable closure + closure := NewClosure(closure, contract, contract.script, vm.state, gas, closure.Price) + // Executer the closure and get the return value (if any) + ret, _, err := closure.Call(vm, args, hook) + if err != nil { + stack.Push(ethutil.BigFalse) + // Reset the changes applied this object + vm.state.Revert(snapshot) + } else { + stack.Push(ethutil.BigTrue) + + vm.state.UpdateStateObject(contract) + + mem.Set(retOffset.Int64(), retSize.Int64(), ret) + } } else { - stack.Push(ethutil.BigTrue) - - vm.state.UpdateStateObject(contract) - - mem.Set(retOffset.Int64(), retSize.Int64(), ret) + ethutil.Config.Log.Debugf("Contract %x not found\n", addr.Bytes()) + stack.Push(ethutil.BigFalse) } - } else { - ethutil.Config.Log.Debugf("Contract %x not found\n", addr.Bytes()) - stack.Push(ethutil.BigFalse) } case RETURN: require(2) -- cgit v1.2.3 From 48bca30e61f869a00111abe5d818ac7379854616 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 16 Jun 2014 11:51:16 +0200 Subject: Fixed minor issue with the gas pool --- ethchain/state_manager.go | 2 +- ethchain/state_object.go | 4 ++-- ethchain/state_transition.go | 14 ++++++++------ 3 files changed, 11 insertions(+), 9 deletions(-) (limited to 'ethchain') diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 4b1b872cc..36bb14846 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -178,7 +178,7 @@ func (sm *StateManager) ProcessBlock(state *State, parent, block *Block, dontRea fmt.Println(block.Receipts()) coinbase := state.GetOrNewStateObject(block.Coinbase) - coinbase.gasPool = block.CalcGasLimit(parent) + coinbase.SetGasPool(block.CalcGasLimit(parent)) // Process the transactions on to current block //sm.ApplyTransactions(block.Coinbase, state, parent, block.Transactions()) diff --git a/ethchain/state_object.go b/ethchain/state_object.go index 03f4c9219..337c5a394 100644 --- a/ethchain/state_object.go +++ b/ethchain/state_object.go @@ -120,13 +120,13 @@ func (c *StateObject) ReturnGas(gas, price *big.Int, state *State) { func (c *StateObject) AddAmount(amount *big.Int) { c.SetAmount(new(big.Int).Add(c.Amount, amount)) - ethutil.Config.Log.Debugf("%x: #%d %v (+ %v)", c.Address(), c.Nonce, c.Amount, amount) + ethutil.Config.Log.Printf(ethutil.LogLevelSystem, "%x: #%d %v (+ %v)\n", c.Address(), c.Nonce, c.Amount, amount) } func (c *StateObject) SubAmount(amount *big.Int) { c.SetAmount(new(big.Int).Sub(c.Amount, amount)) - ethutil.Config.Log.Debugf("%x: #%d %v (- %v)", c.Address(), c.Nonce, c.Amount, amount) + ethutil.Config.Log.Printf(ethutil.LogLevelSystem, "%x: #%d %v (- %v)\n", c.Address(), c.Nonce, c.Amount, amount) } func (c *StateObject) SetAmount(amount *big.Int) { diff --git a/ethchain/state_transition.go b/ethchain/state_transition.go index 76936aa7c..5beef61b4 100644 --- a/ethchain/state_transition.go +++ b/ethchain/state_transition.go @@ -113,12 +113,14 @@ func (self *StateTransition) BuyGas() error { func (self *StateTransition) TransitionState() (err error) { //snapshot := st.state.Snapshot() - defer func() { - if r := recover(); r != nil { - ethutil.Config.Log.Infoln(r) - err = fmt.Errorf("state transition err %v", r) - } - }() + /* + defer func() { + if r := recover(); r != nil { + ethutil.Config.Log.Infoln(r) + err = fmt.Errorf("state transition err %v", r) + } + }() + */ var ( tx = self.tx -- cgit v1.2.3 From 8b15732c1e8a1a666ae7469bc43d989918ce754a Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 16 Jun 2014 12:04:56 +0200 Subject: Check for nil receiver --- ethchain/state_transition.go | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'ethchain') diff --git a/ethchain/state_transition.go b/ethchain/state_transition.go index 5beef61b4..c88f4727f 100644 --- a/ethchain/state_transition.go +++ b/ethchain/state_transition.go @@ -141,8 +141,13 @@ func (self *StateTransition) TransitionState() (err error) { // XXX Transactions after this point are considered valid. defer func() { - self.state.UpdateStateObject(sender) - self.state.UpdateStateObject(receiver) + if sender != nil { + self.state.UpdateStateObject(sender) + } + + if receiver != nil { + self.state.UpdateStateObject(receiver) + } }() // Increment the nonce for the next transaction -- cgit v1.2.3 From 0d7763283952a57e5421565cdda19ecabe3222f7 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 16 Jun 2014 12:25:18 +0200 Subject: Refund gas --- ethchain/state_object.go | 9 +++++++++ ethchain/state_transition.go | 17 +++++++++++++---- 2 files changed, 22 insertions(+), 4 deletions(-) (limited to 'ethchain') diff --git a/ethchain/state_object.go b/ethchain/state_object.go index 337c5a394..2c9dfb713 100644 --- a/ethchain/state_object.go +++ b/ethchain/state_object.go @@ -163,6 +163,15 @@ func (self *StateObject) BuyGas(gas, price *big.Int) error { return nil } +func (self *StateObject) RefundGas(gas, price *big.Int) { + self.gasPool.Add(self.gasPool, gas) + + rGas := new(big.Int).Set(gas) + rGas.Mul(rGas, price) + + self.Amount.Sub(self.Amount, rGas) +} + func (self *StateObject) Copy() *StateObject { stCopy := &StateObject{} stCopy.address = make([]byte, len(self.address)) diff --git a/ethchain/state_transition.go b/ethchain/state_transition.go index c88f4727f..25efd64cc 100644 --- a/ethchain/state_transition.go +++ b/ethchain/state_transition.go @@ -110,6 +110,15 @@ func (self *StateTransition) BuyGas() error { return nil } +func (self *StateTransition) RefundGas() { + coinbase, sender := self.Coinbase(), self.Sender() + coinbase.RefundGas(self.gas, self.tx.GasPrice) + + // Return remaining gas + remaining := new(big.Int).Mul(self.gas, self.tx.GasPrice) + sender.AddAmount(remaining) +} + func (self *StateTransition) TransitionState() (err error) { //snapshot := st.state.Snapshot() @@ -141,6 +150,8 @@ func (self *StateTransition) TransitionState() (err error) { // XXX Transactions after this point are considered valid. defer func() { + self.RefundGas() + if sender != nil { self.state.UpdateStateObject(sender) } @@ -148,6 +159,8 @@ func (self *StateTransition) TransitionState() (err error) { if receiver != nil { self.state.UpdateStateObject(receiver) } + + self.state.UpdateStateObject(self.Coinbase()) }() // Increment the nonce for the next transaction @@ -203,10 +216,6 @@ func (self *StateTransition) TransitionState() (err error) { } } - // Return remaining gas - remaining := new(big.Int).Mul(self.gas, tx.GasPrice) - sender.AddAmount(remaining) - return nil } -- cgit v1.2.3 From 887debb0559b283962530bb42998a67dd1b69347 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 16 Jun 2014 18:20:38 +0200 Subject: comment --- ethchain/state_object.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'ethchain') diff --git a/ethchain/state_object.go b/ethchain/state_object.go index 2c9dfb713..1445bcd82 100644 --- a/ethchain/state_object.go +++ b/ethchain/state_object.go @@ -147,7 +147,7 @@ func (c *StateObject) ConvertGas(gas, price *big.Int) error { func (self *StateObject) SetGasPool(gasLimit *big.Int) { self.gasPool = new(big.Int).Set(gasLimit) - ethutil.Config.Log.Printf(ethutil.LogLevelSystem, "%x fuel (+ %v)", self.Address(), self.gasPool) + ethutil.Config.Log.Printf(ethutil.LogLevelSystem, "%x: fuel (+ %v)", self.Address(), self.gasPool) } func (self *StateObject) BuyGas(gas, price *big.Int) error { -- cgit v1.2.3