diff options
author | obscuren <geffobscura@gmail.com> | 2014-05-26 06:42:07 +0800 |
---|---|---|
committer | obscuren <geffobscura@gmail.com> | 2014-05-26 06:42:07 +0800 |
commit | b1463b2dc23ebd072f5e1e2c9a74842fc7ff51db (patch) | |
tree | 96e360fc19b7c0a37172d6d27d1221bf175228e6 /ethchain | |
parent | 4e1c6a8a22924d06a2a972c024891cebcf8ea054 (diff) | |
parent | 1f3f76cb092e84bd2e90950f0d43d7657eae878e (diff) | |
download | dexon-b1463b2dc23ebd072f5e1e2c9a74842fc7ff51db.tar dexon-b1463b2dc23ebd072f5e1e2c9a74842fc7ff51db.tar.gz dexon-b1463b2dc23ebd072f5e1e2c9a74842fc7ff51db.tar.bz2 dexon-b1463b2dc23ebd072f5e1e2c9a74842fc7ff51db.tar.lz dexon-b1463b2dc23ebd072f5e1e2c9a74842fc7ff51db.tar.xz dexon-b1463b2dc23ebd072f5e1e2c9a74842fc7ff51db.tar.zst dexon-b1463b2dc23ebd072f5e1e2c9a74842fc7ff51db.zip |
Merge branch 'release/poc5-rc9'
Diffstat (limited to 'ethchain')
-rw-r--r-- | ethchain/block.go | 85 | ||||
-rw-r--r-- | ethchain/block_chain.go | 21 | ||||
-rw-r--r-- | ethchain/block_chain_test.go | 4 | ||||
-rw-r--r-- | ethchain/genesis.go | 2 | ||||
-rw-r--r-- | ethchain/state.go | 16 | ||||
-rw-r--r-- | ethchain/state_manager.go | 88 | ||||
-rw-r--r-- | ethchain/state_object.go | 12 | ||||
-rw-r--r-- | ethchain/state_object_test.go | 4 | ||||
-rw-r--r-- | ethchain/state_test.go | 31 | ||||
-rw-r--r-- | ethchain/transaction.go | 123 | ||||
-rw-r--r-- | ethchain/transaction_pool.go | 18 | ||||
-rw-r--r-- | ethchain/types.go | 7 | ||||
-rw-r--r-- | ethchain/vm.go | 18 | ||||
-rw-r--r-- | ethchain/vm_test.go | 64 |
14 files changed, 339 insertions, 154 deletions
diff --git a/ethchain/block.go b/ethchain/block.go index 3401632b1..73e29f878 100644 --- a/ethchain/block.go +++ b/ethchain/block.go @@ -1,6 +1,7 @@ package ethchain import ( + "bytes" "fmt" "github.com/ethereum/eth-go/ethutil" "math/big" @@ -55,6 +56,7 @@ type Block struct { Nonce []byte // List of transactions and/or contracts transactions []*Transaction + receipts []*Receipt TxSha []byte } @@ -84,24 +86,20 @@ func CreateBlock(root interface{}, base []byte, Difficulty *big.Int, Nonce []byte, - extra string, - txes []*Transaction) *Block { + extra string) *Block { block := &Block{ - // Slice of transactions to include in this block - transactions: txes, - PrevHash: prevHash, - Coinbase: base, - Difficulty: Difficulty, - Nonce: Nonce, - Time: time.Now().Unix(), - Extra: extra, - UncleSha: EmptyShaList, - GasUsed: new(big.Int), - MinGasPrice: new(big.Int), - GasLimit: new(big.Int), + PrevHash: prevHash, + Coinbase: base, + Difficulty: Difficulty, + Nonce: Nonce, + Time: time.Now().Unix(), + Extra: extra, + UncleSha: EmptyShaList, + GasUsed: new(big.Int), + MinGasPrice: new(big.Int), + GasLimit: new(big.Int), } - block.SetTransactions(txes) block.SetUncles([]*Block{}) block.state = NewState(ethutil.NewTrie(ethutil.Config.Db, root)) @@ -115,7 +113,10 @@ func (block *Block) Hash() []byte { } func (block *Block) HashNoNonce() []byte { - return ethutil.Sha3Bin(ethutil.Encode([]interface{}{block.PrevHash, block.UncleSha, block.Coinbase, block.state.trie.Root, block.TxSha, block.Difficulty, block.Time, block.Extra})) + return ethutil.Sha3Bin(ethutil.Encode([]interface{}{block.PrevHash, + block.UncleSha, block.Coinbase, block.state.trie.Root, + block.TxSha, block.Difficulty, block.Number, block.MinGasPrice, + block.GasLimit, block.GasUsed, block.Time, block.Extra})) } func (block *Block) State() *State { @@ -161,6 +162,16 @@ func (block *Block) BlockInfo() BlockInfo { return bi } +func (self *Block) GetTransaction(hash []byte) *Transaction { + for _, receipt := range self.receipts { + if bytes.Compare(receipt.Tx.Hash(), hash) == 0 { + return receipt.Tx + } + } + + return nil +} + // Sync the block's state and contract respectively func (block *Block) Sync() { block.state.Sync() @@ -172,15 +183,15 @@ func (block *Block) Undo() { } /////// Block Encoding -func (block *Block) rlpTxs() interface{} { +func (block *Block) rlpReceipts() interface{} { // Marshal the transactions of this block - encTx := make([]interface{}, len(block.transactions)) - for i, tx := range block.transactions { + encR := make([]interface{}, len(block.receipts)) + for i, r := range block.receipts { // Cast it to a string (safe) - encTx[i] = tx.RlpData() + encR[i] = r.RlpData() } - return encTx + return encR } func (block *Block) rlpUncles() interface{} { @@ -201,7 +212,12 @@ func (block *Block) SetUncles(uncles []*Block) { block.UncleSha = ethutil.Sha3Bin(ethutil.Encode(block.rlpUncles())) } -func (block *Block) SetTransactions(txs []*Transaction) { +func (self *Block) SetReceipts(receipts []*Receipt, txs []*Transaction) { + self.receipts = receipts + self.setTransactions(txs) +} + +func (block *Block) setTransactions(txs []*Transaction) { block.transactions = txs trie := ethutil.NewTrie(ethutil.Config.Db, "") @@ -221,7 +237,7 @@ func (block *Block) SetTransactions(txs []*Transaction) { } func (block *Block) Value() *ethutil.Value { - return ethutil.NewValue([]interface{}{block.header(), block.rlpTxs(), block.rlpUncles()}) + return ethutil.NewValue([]interface{}{block.header(), block.rlpReceipts(), block.rlpUncles()}) } func (block *Block) RlpEncode() []byte { @@ -245,6 +261,7 @@ func (block *Block) RlpValueDecode(decoder *ethutil.Value) { block.TxSha = header.Get(4).Bytes() block.Difficulty = header.Get(5).BigInt() block.Number = header.Get(6).BigInt() + //fmt.Printf("#%v : %x\n", block.Number, block.Coinbase) block.MinGasPrice = header.Get(7).BigInt() block.GasLimit = header.Get(8).BigInt() block.GasUsed = header.Get(9).BigInt() @@ -255,12 +272,13 @@ func (block *Block) RlpValueDecode(decoder *ethutil.Value) { // Tx list might be empty if this is an uncle. Uncles only have their // header set. if decoder.Get(1).IsNil() == false { // Yes explicitness - txes := decoder.Get(1) - block.transactions = make([]*Transaction, txes.Len()) - for i := 0; i < txes.Len(); i++ { - tx := NewTransactionFromValue(txes.Get(i)) - - block.transactions[i] = tx + receipts := decoder.Get(1) + block.transactions = make([]*Transaction, receipts.Len()) + block.receipts = make([]*Receipt, receipts.Len()) + for i := 0; i < receipts.Len(); i++ { + receipt := NewRecieptFromValue(receipts.Get(i)) + block.transactions[i] = receipt.Tx + block.receipts[i] = receipt } } @@ -299,6 +317,10 @@ func (block *Block) GetRoot() interface{} { return block.state.trie.Root } +func (self *Block) Receipts() []*Receipt { + return self.receipts +} + func (block *Block) header() []interface{} { return []interface{}{ // Sha of the previous block @@ -346,6 +368,7 @@ func (block *Block) String() string { Time: %v Extra: %v Nonce: %x + NumTx: %v `, block.Hash(), block.PrevHash, @@ -360,5 +383,7 @@ func (block *Block) String() string { block.GasUsed, block.Time, block.Extra, - block.Nonce) + block.Nonce, + len(block.transactions), + ) } diff --git a/ethchain/block_chain.go b/ethchain/block_chain.go index b72c78cdb..b45d254b5 100644 --- a/ethchain/block_chain.go +++ b/ethchain/block_chain.go @@ -36,7 +36,7 @@ func (bc *BlockChain) Genesis() *Block { return bc.genesisBlock } -func (bc *BlockChain) NewBlock(coinbase []byte, txs []*Transaction) *Block { +func (bc *BlockChain) NewBlock(coinbase []byte) *Block { var root interface{} var lastBlockTime int64 hash := ZeroHash256 @@ -53,8 +53,7 @@ func (bc *BlockChain) NewBlock(coinbase []byte, txs []*Transaction) *Block { coinbase, ethutil.BigPow(2, 32), nil, - "", - txs) + "") if bc.CurrentBlock != nil { var mul *big.Int @@ -272,16 +271,18 @@ func (bc *BlockChain) GetChain(hash []byte, amount int) []*Block { func AddTestNetFunds(block *Block) { for _, addr := range []string{ - "8a40bfaa73256b60764c1bf40675a99083efb075", // Gavin - "e6716f9544a56c530d868e4bfbacb172315bdead", // Jeffrey - "1e12515ce3e0f817a4ddef9ca55788a1d66bd2df", // Vit - "1a26338f0d905e295fccb71fa9ea849ffa12aaf4", // Alex - "2ef47100e0787b915105fd5e3f4ff6752079d5cb", // Maran - "cd2a3d9f938e13cd947ec05abc7fe734df8dd826", // Roman + "8a40bfaa73256b60764c1bf40675a99083efb075", + "e4157b34ea9615cfbde6b4fda419828124b70c78", + "1e12515ce3e0f817a4ddef9ca55788a1d66bd2df", + "6c386a4b26f73c802f34673f7248bb118f97424a", + "cd2a3d9f938e13cd947ec05abc7fe734df8dd826", + "2ef47100e0787b915105fd5e3f4ff6752079d5cb", + "e6716f9544a56c530d868e4bfbacb172315bdead", + "1a26338f0d905e295fccb71fa9ea849ffa12aaf4", } { codedAddr := ethutil.FromHex(addr) account := block.state.GetAccount(codedAddr) - account.Amount = ethutil.BigPow(2, 200) + account.Amount = ethutil.Big("1606938044258990275541962092341162602522202993782792835301376") //ethutil.BigPow(2, 200) block.state.UpdateStateObject(account) } log.Printf("%x\n", block.RlpEncode()) diff --git a/ethchain/block_chain_test.go b/ethchain/block_chain_test.go index 4e4bb9dd4..ecaf8ca89 100644 --- a/ethchain/block_chain_test.go +++ b/ethchain/block_chain_test.go @@ -50,7 +50,7 @@ func (tm *TestManager) Broadcast(msgType ethwire.MsgType, data []interface{}) { } func NewTestManager() *TestManager { - ethutil.ReadConfig(".ethtest", ethutil.LogStd) + ethutil.ReadConfig(".ethtest", ethutil.LogStd, "") db, err := ethdb.NewMemDatabase() if err != nil { @@ -74,7 +74,7 @@ func NewTestManager() *TestManager { func (tm *TestManager) AddFakeBlock(blk []byte) error { block := NewBlockFromBytes(blk) tm.Blocks = append(tm.Blocks, block) - err := tm.StateManager().ProcessBlock(tm.StateManager().CurrentState(), block, false) + err := tm.StateManager().Process(block, false) return err } func (tm *TestManager) CreateChain1() error { diff --git a/ethchain/genesis.go b/ethchain/genesis.go index b8f9f865a..359c47c26 100644 --- a/ethchain/genesis.go +++ b/ethchain/genesis.go @@ -23,7 +23,7 @@ var GenesisHeader = []interface{}{ // Root state "", // tx sha - ZeroHash256, + "", // Difficulty ethutil.BigPow(2, 22), // Number diff --git a/ethchain/state.go b/ethchain/state.go index 6ec6916f4..e209e0e2f 100644 --- a/ethchain/state.go +++ b/ethchain/state.go @@ -99,7 +99,21 @@ func (s *State) Cmp(other *State) bool { } func (s *State) Copy() *State { - return NewState(s.trie.Copy()) + state := NewState(s.trie.Copy()) + for k, subState := range s.states { + state.states[k] = subState.Copy() + } + + return state +} + +func (s *State) Snapshot() *State { + return s.Copy() +} + +func (s *State) Revert(snapshot *State) { + s.trie = snapshot.trie + s.states = snapshot.states } func (s *State) Put(key, object []byte) { diff --git a/ethchain/state_manager.go b/ethchain/state_manager.go index 8b56d65bb..2d2a32e2f 100644 --- a/ethchain/state_manager.go +++ b/ethchain/state_manager.go @@ -84,7 +84,7 @@ func (sm *StateManager) BlockChain() *BlockChain { return sm.bc } -func (sm *StateManager) MakeContract(state *State, tx *Transaction) *StateObject { +func (sm *StateManager) MakeStateObject(state *State, tx *Transaction) *StateObject { contract := MakeContract(tx, state) if contract != nil { state.states[string(tx.CreationAddress())] = contract.state @@ -97,40 +97,74 @@ func (sm *StateManager) MakeContract(state *State, tx *Transaction) *StateObject // 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) { +func (sm *StateManager) ApplyTransactions(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 { - sm.ApplyTransaction(state, block, tx) + usedGas, err := sm.ApplyTransaction(state, block, tx) + if err != nil { + ethutil.Config.Log.Infoln(err) + continue + } + + 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) } + + return receipts, txs } -func (sm *StateManager) ApplyTransaction(state *State, block *Block, tx *Transaction) error { - // If there's no recipient, it's a contract - // Check if this is a contract creation traction and if so - // create a contract of this tx. - if tx.IsContract() { - err := sm.Ethereum.TxPool().ProcessTransaction(tx, block, false) +func (sm *StateManager) ApplyTransaction(state *State, block *Block, tx *Transaction) (*big.Int, 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. + */ + totalGasUsed := big.NewInt(0) + // Apply the transaction to the current state + err := sm.Ethereum.TxPool().ProcessTransaction(tx, state, false) + if tx.CreatesContract() { if err == nil { - contract := sm.MakeContract(state, tx) + // Create a new state object and the transaction + // as it's data provider. + contract := sm.MakeStateObject(state, tx) if contract != nil { - sm.EvalScript(state, contract.Init(), contract, tx, block) + // Evaluate the initialization script + // and use the return value as the + // script section for the state object. + script, err := sm.EvalScript(state, contract.Init(), contract, tx, block) + if err != nil { + return nil, fmt.Errorf("[STATE] Error during init script run %v", err) + } + contract.script = script + state.UpdateStateObject(contract) } else { - return fmt.Errorf("[STATE] Unable to create contract") + return nil, fmt.Errorf("[STATE] Unable to create contract") } } else { - return fmt.Errorf("[STATE] contract create:", err) + return nil, fmt.Errorf("[STATE] contract creation tx:", err) } } else { - err := sm.Ethereum.TxPool().ProcessTransaction(tx, block, false) - contract := state.GetStateObject(tx.Recipient) - if err == nil && contract != nil && len(contract.Script()) > 0 { - sm.EvalScript(state, contract.Script(), contract, tx, block) + // 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 { + sm.EvalScript(state, stateObject.Script(), stateObject, tx, block) } else if err != nil { - return fmt.Errorf("[STATE] process:", err) + return nil, fmt.Errorf("[STATE] process:", err) } } - return nil + return totalGasUsed, nil } func (sm *StateManager) Process(block *Block, dontReact bool) error { @@ -276,6 +310,14 @@ func CalculateBlockReward(block *Block, uncleLength int) *big.Int { for i := 0; i < uncleLength; i++ { 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) } @@ -307,10 +349,10 @@ func (sm *StateManager) Stop() { sm.bc.Stop() } -func (sm *StateManager) EvalScript(state *State, script []byte, object *StateObject, tx *Transaction, block *Block) { +func (sm *StateManager) EvalScript(state *State, script []byte, object *StateObject, tx *Transaction, block *Block) (ret []byte, err error) { account := state.GetAccount(tx.Sender()) - err := account.ConvertGas(tx.Gas, tx.GasPrice) + err = account.ConvertGas(tx.Gas, tx.GasPrice) if err != nil { ethutil.Config.Log.Debugln(err) return @@ -327,11 +369,13 @@ func (sm *StateManager) EvalScript(state *State, script []byte, object *StateObj Value: tx.Value, //Price: tx.GasPrice, }) - closure.Call(vm, tx.Data, nil) + ret, err = closure.Call(vm, tx.Data, nil) // Update the account (refunds) state.UpdateStateObject(account) state.UpdateStateObject(object) + + return } func (sm *StateManager) notifyChanges(state *State) { diff --git a/ethchain/state_object.go b/ethchain/state_object.go index 8e059f334..3e9c6df40 100644 --- a/ethchain/state_object.go +++ b/ethchain/state_object.go @@ -28,8 +28,7 @@ func MakeContract(tx *Transaction, state *State) *StateObject { value := tx.Value contract := NewContract(addr, value, ZeroHash256) - contract.script = tx.Data - contract.initScript = tx.Init + contract.initScript = tx.Data state.UpdateStateObject(contract) @@ -82,12 +81,17 @@ func (c *StateObject) SetStorage(num *big.Int, val *ethutil.Value) { c.SetAddr(addr, val) } -func (c *StateObject) GetMem(num *big.Int) *ethutil.Value { +func (c *StateObject) GetStorage(num *big.Int) *ethutil.Value { nb := ethutil.BigToBytes(num, 256) return c.Addr(nb) } +/* DEPRECATED */ +func (c *StateObject) GetMem(num *big.Int) *ethutil.Value { + return c.GetStorage(num) +} + func (c *StateObject) GetInstr(pc *big.Int) *ethutil.Value { if int64(len(c.script)-1) < pc.Int64() { return ethutil.NewValue(0) @@ -146,7 +150,7 @@ func (c *StateObject) RlpEncode() []byte { if c.state != nil { root = c.state.trie.Root } else { - root = ZeroHash256 + root = "" } return ethutil.Encode([]interface{}{c.Amount, c.Nonce, root, ethutil.Sha3Bin(c.script)}) diff --git a/ethchain/state_object_test.go b/ethchain/state_object_test.go index e955acc56..91ed7c0dd 100644 --- a/ethchain/state_object_test.go +++ b/ethchain/state_object_test.go @@ -9,7 +9,7 @@ import ( ) func TestSync(t *testing.T) { - ethutil.ReadConfig("", ethutil.LogStd) + ethutil.ReadConfig("", ethutil.LogStd, "") db, _ := ethdb.NewMemDatabase() state := NewState(ethutil.NewTrie(db, "")) @@ -28,7 +28,7 @@ func TestSync(t *testing.T) { } func TestObjectGet(t *testing.T) { - ethutil.ReadConfig("", ethutil.LogStd) + ethutil.ReadConfig("", ethutil.LogStd, "") db, _ := ethdb.NewMemDatabase() ethutil.Config.Db = db diff --git a/ethchain/state_test.go b/ethchain/state_test.go new file mode 100644 index 000000000..4cc3fdf75 --- /dev/null +++ b/ethchain/state_test.go @@ -0,0 +1,31 @@ +package ethchain + +import ( + "fmt" + "github.com/ethereum/eth-go/ethdb" + "github.com/ethereum/eth-go/ethutil" + "testing" +) + +func TestSnapshot(t *testing.T) { + ethutil.ReadConfig("", ethutil.LogStd, "") + + db, _ := ethdb.NewMemDatabase() + state := NewState(ethutil.NewTrie(db, "")) + + stateObject := NewContract([]byte("aa"), ethutil.Big1, ZeroHash256) + state.UpdateStateObject(stateObject) + stateObject.SetStorage(ethutil.Big("0"), ethutil.NewValue(42)) + + snapshot := state.Snapshot() + + stateObject = state.GetStateObject([]byte("aa")) + stateObject.SetStorage(ethutil.Big("0"), ethutil.NewValue(43)) + + state.Revert(snapshot) + + stateObject = state.GetStateObject([]byte("aa")) + if !stateObject.GetStorage(ethutil.Big("0")).Cmp(ethutil.NewValue(42)) { + t.Error("Expected storage 0 to be 42") + } +} diff --git a/ethchain/transaction.go b/ethchain/transaction.go index bd7a0e424..2c5615f99 100644 --- a/ethchain/transaction.go +++ b/ethchain/transaction.go @@ -1,6 +1,7 @@ package ethchain import ( + "fmt" "github.com/ethereum/eth-go/ethutil" "github.com/obscuren/secp256k1-go" "math/big" @@ -15,7 +16,6 @@ type Transaction struct { Gas *big.Int GasPrice *big.Int Data []byte - Init []byte v byte r, s []byte @@ -23,8 +23,8 @@ type Transaction struct { contractCreation bool } -func NewContractCreationTx(value, gas, gasPrice *big.Int, script []byte, init []byte) *Transaction { - return &Transaction{Value: value, Gas: gas, GasPrice: gasPrice, Data: script, Init: init, contractCreation: true} +func NewContractCreationTx(value, gas, gasPrice *big.Int, script []byte) *Transaction { + return &Transaction{Value: value, Gas: gas, GasPrice: gasPrice, Data: script, contractCreation: true} } func NewTransactionMessage(to []byte, value, gas, gasPrice *big.Int, data []byte) *Transaction { @@ -46,19 +46,26 @@ func NewTransactionFromValue(val *ethutil.Value) *Transaction { } func (tx *Transaction) Hash() []byte { - data := []interface{}{tx.Nonce, tx.Value, tx.GasPrice, tx.Gas, tx.Recipient, tx.Data} + data := []interface{}{tx.Nonce, tx.GasPrice, tx.Gas, tx.Recipient, tx.Value, tx.Data} - if tx.contractCreation { - data = append(data, tx.Init) - } + /* + if tx.contractCreation { + data = append(data, tx.Init) + } + */ return ethutil.Sha3Bin(ethutil.NewValue(data).Encode()) } -func (tx *Transaction) IsContract() bool { +func (tx *Transaction) CreatesContract() bool { return tx.contractCreation } +/* Depricated */ +func (tx *Transaction) IsContract() bool { + return tx.CreatesContract() +} + func (tx *Transaction) CreationAddress() []byte { return ethutil.Sha3Bin(ethutil.NewValue([]interface{}{tx.Sender(), tx.Nonce}).Encode())[12:] } @@ -112,10 +119,6 @@ func (tx *Transaction) Sign(privk []byte) error { func (tx *Transaction) RlpData() interface{} { data := []interface{}{tx.Nonce, tx.GasPrice, tx.Gas, tx.Recipient, tx.Value, tx.Data} - if tx.contractCreation { - data = append(data, tx.Init) - } - return append(data, tx.v, tx.r, tx.s) } @@ -138,18 +141,90 @@ func (tx *Transaction) RlpValueDecode(decoder *ethutil.Value) { tx.Recipient = decoder.Get(3).Bytes() tx.Value = decoder.Get(4).BigInt() tx.Data = decoder.Get(5).Bytes() - - // If the list is of length 10 it's a contract creation tx - if decoder.Len() == 10 { + tx.v = byte(decoder.Get(6).Uint()) + tx.r = decoder.Get(7).Bytes() + tx.s = decoder.Get(8).Bytes() + if len(tx.Recipient) == 0 { tx.contractCreation = true - tx.Init = decoder.Get(6).Bytes() - - tx.v = byte(decoder.Get(7).Uint()) - tx.r = decoder.Get(8).Bytes() - tx.s = decoder.Get(9).Bytes() - } else { - tx.v = byte(decoder.Get(6).Uint()) - tx.r = decoder.Get(7).Bytes() - tx.s = decoder.Get(8).Bytes() } + + /* + // If the list is of length 10 it's a contract creation tx + if decoder.Len() == 10 { + tx.contractCreation = true + tx.Init = decoder.Get(6).Bytes() + + tx.v = byte(decoder.Get(7).Uint()) + tx.r = decoder.Get(8).Bytes() + tx.s = decoder.Get(9).Bytes() + } else { + tx.v = byte(decoder.Get(6).Uint()) + tx.r = decoder.Get(7).Bytes() + tx.s = decoder.Get(8).Bytes() + } + */ +} + +func (tx *Transaction) String() string { + return fmt.Sprintf(` + TX(%x) + Contract: %v + From: %x + To: %x + Nonce: %v + GasPrice: %v + Gas: %v + Value: %v + Data: 0x%x + V: 0x%x + R: 0x%x + S: 0x%x + `, + tx.Hash(), + len(tx.Recipient) == 0, + tx.Sender(), + tx.Recipient, + tx.Nonce, + tx.GasPrice, + tx.Gas, + tx.Value, + tx.Data, + tx.v, + tx.r, + tx.s) +} + +type Receipt struct { + Tx *Transaction + PostState []byte + CumulativeGasUsed *big.Int +} + +func NewRecieptFromValue(val *ethutil.Value) *Receipt { + r := &Receipt{} + r.RlpValueDecode(val) + + return r +} + +func (self *Receipt) RlpValueDecode(decoder *ethutil.Value) { + self.Tx = NewTransactionFromValue(decoder.Get(0)) + self.PostState = decoder.Get(1).Bytes() + self.CumulativeGasUsed = decoder.Get(2).BigInt() +} + +func (self *Receipt) RlpData() interface{} { + return []interface{}{self.Tx.RlpData(), self.PostState, self.CumulativeGasUsed} +} + +func (self *Receipt) String() string { + return fmt.Sprintf(` + R + Tx:[ %v] + PostState: 0x%x + CumulativeGasUsed: %v + `, + self.Tx, + self.PostState, + self.CumulativeGasUsed) } diff --git a/ethchain/transaction_pool.go b/ethchain/transaction_pool.go index dcf0c4c31..ee026ffdd 100644 --- a/ethchain/transaction_pool.go +++ b/ethchain/transaction_pool.go @@ -91,15 +91,15 @@ func (pool *TxPool) addTransaction(tx *Transaction) { // Process transaction validates the Tx and processes funds from the // sender to the recipient. -func (pool *TxPool) ProcessTransaction(tx *Transaction, block *Block, toContract bool) (err error) { +func (pool *TxPool) ProcessTransaction(tx *Transaction, state *State, toContract bool) (err error) { defer func() { if r := recover(); r != nil { - log.Println(r) + ethutil.Config.Log.Infoln(r) err = fmt.Errorf("%v", r) } }() // Get the sender - sender := block.state.GetAccount(tx.Sender()) + sender := state.GetAccount(tx.Sender()) if sender.Nonce != tx.Nonce { return fmt.Errorf("[TXPL] Invalid account nonce, state nonce is %d transaction nonce is %d instead", sender.Nonce, tx.Nonce) @@ -107,19 +107,21 @@ func (pool *TxPool) ProcessTransaction(tx *Transaction, block *Block, toContract // 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(TxFee, TxFeeRat)) + totAmount := new(big.Int).Add(tx.Value, new(big.Int).Mul(tx.Gas, tx.GasPrice)) if sender.Amount.Cmp(totAmount) < 0 { return fmt.Errorf("[TXPL] Insufficient amount in sender's (%x) account", tx.Sender()) } + //fmt.Println(tx) // Get the receiver - receiver := block.state.GetAccount(tx.Recipient) + receiver := state.GetAccount(tx.Recipient) sender.Nonce += 1 // Send Tx to self if bytes.Compare(tx.Recipient, tx.Sender()) == 0 { // Subtract the fee - sender.SubAmount(new(big.Int).Mul(TxFee, TxFeeRat)) + sender.SubAmount(new(big.Int).Mul(GasTx, tx.GasPrice)) } else { // Subtract the amount from the senders account sender.SubAmount(totAmount) @@ -127,10 +129,10 @@ func (pool *TxPool) ProcessTransaction(tx *Transaction, block *Block, toContract // Add the amount to receivers account which should conclude this transaction receiver.AddAmount(tx.Value) - block.state.UpdateStateObject(receiver) + state.UpdateStateObject(receiver) } - block.state.UpdateStateObject(sender) + state.UpdateStateObject(sender) ethutil.Config.Log.Infof("[TXPL] Processed Tx %x\n", tx.Hash()) diff --git a/ethchain/types.go b/ethchain/types.go index 9964bbe3b..e0fdd5191 100644 --- a/ethchain/types.go +++ b/ethchain/types.go @@ -322,3 +322,10 @@ func IsOpCode(s string) bool { } return false } + +func AppendScript(init, script []byte) []byte { + s := append(init, byte(oRETURN)) + s = append(s, script...) + + return s +} diff --git a/ethchain/vm.go b/ethchain/vm.go index d8254998e..e025920f3 100644 --- a/ethchain/vm.go +++ b/ethchain/vm.go @@ -18,6 +18,7 @@ var ( GasCreate = big.NewInt(100) GasCall = big.NewInt(20) GasMemory = big.NewInt(1) + GasTx = big.NewInt(500) ) func CalculateTxGas(initSize, scriptSize *big.Int) *big.Int { @@ -425,6 +426,10 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro value := stack.Pop() size, offset := stack.Popn() + // Snapshot the current stack so we are able to + // revert back to it later. + snapshot := vm.state.Snapshot() + // Generate a new address addr := ethutil.CreateAddress(closure.callee.Address(), closure.callee.N()) // Create a new contract @@ -447,6 +452,9 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro closure.Script, err = closure.Call(vm, nil, hook) if err != nil { stack.Push(ethutil.BigFalse) + + // Revert the state as it was before. + vm.state.Revert(snapshot) } else { stack.Push(ethutil.BigD(addr)) @@ -472,6 +480,8 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro // 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()) @@ -494,14 +504,14 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro if err != nil { stack.Push(ethutil.BigFalse) // Reset the changes applied this object - //contract.State().Reset() + vm.state.Revert(snapshot) } else { stack.Push(ethutil.BigTrue) - } - vm.state.UpdateStateObject(contract) + vm.state.UpdateStateObject(contract) - mem.Set(retOffset.Int64(), retSize.Int64(), ret) + mem.Set(retOffset.Int64(), retSize.Int64(), ret) + } } else { ethutil.Config.Log.Debugf("Contract %x not found\n", addr.Bytes()) stack.Push(ethutil.BigFalse) diff --git a/ethchain/vm_test.go b/ethchain/vm_test.go index 2ec70536a..520f9a2ed 100644 --- a/ethchain/vm_test.go +++ b/ethchain/vm_test.go @@ -1,6 +1,5 @@ package ethchain -/* import ( _ "bytes" "fmt" @@ -13,60 +12,33 @@ import ( ) func TestRun4(t *testing.T) { - ethutil.ReadConfig("", ethutil.LogStd) + ethutil.ReadConfig("", ethutil.LogStd, "") db, _ := ethdb.NewMemDatabase() state := NewState(ethutil.NewTrie(db, "")) - script, err := mutan.Compile(strings.NewReader(` - int32 a = 10 - int32 b = 20 - if a > b { - int32 c = this.caller() - } - exit() - `), false) - tx := NewContractCreationTx(ethutil.Big("0"), ethutil.Big("1000"), ethutil.Big("100"), script, nil) - tx.Sign(ContractAddr) - addr := tx.CreationAddress() - contract := MakeContract(tx, state) - state.UpdateStateObject(contract) - fmt.Printf("%x\n", addr) - callerScript, err := mutan.Compile(strings.NewReader(` - // Check if there's any cash in the initial store - if this.store[1000] == 0 { - this.store[1000] = 10**20 - } - - - this.store[1001] = this.value() * 20 - this.store[this.origin()] = this.store[this.origin()] + 1000 + this.store[this.origin()] = 10**20 + hello := "world" - if this.store[1001] > 20 { - this.store[1001] = 10^50 - } - - int8 ret = 0 - int8 arg = 10 - call(0xe6a12555fad1fb6eaaaed69001a87313d1fd7b54, 0, 100, arg, ret) - - big t - for int8 i = 0; i < 10; i++ { - t = i - } + return lambda { + big to = this.data[0] + big from = this.origin() + big value = this.data[1] - if 10 > 20 { - int8 shouldnt = 2 - } else { - int8 should = 1 + if this.store[from] >= value { + this.store[from] = this.store[from] - value + this.store[to] = this.store[to] + value } + } `), false) if err != nil { fmt.Println(err) } + fmt.Println(Disassemble(callerScript)) - callerTx := NewContractCreationTx(ethutil.Big("0"), ethutil.Big("1000"), ethutil.Big("100"), callerScript, nil) + callerTx := NewContractCreationTx(ethutil.Big("0"), ethutil.Big("1000"), ethutil.Big("100"), callerScript) + callerTx.Sign([]byte("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")) // Contract addr as test address gas := big.NewInt(1000) @@ -79,7 +51,7 @@ func TestRun4(t *testing.T) { fmt.Println(err) } fmt.Println("account.Amount =", account.Amount) - callerClosure := NewClosure(account, c, c.script, state, gas, gasPrice) + callerClosure := NewClosure(account, c, callerScript, state, gas, gasPrice) vm := NewVm(state, nil, RuntimeVars{ Origin: account.Address(), @@ -89,10 +61,10 @@ func TestRun4(t *testing.T) { Time: 1, Diff: big.NewInt(256), }) - _, e = callerClosure.Call(vm, nil, nil) + var ret []byte + ret, e = callerClosure.Call(vm, nil, nil) if e != nil { fmt.Println("error", e) } - fmt.Println("account.Amount =", account.Amount) + fmt.Println(ret) } -*/ |