From ca74bcc4cdf389b5ef5520f9ab5a7aec08424f30 Mon Sep 17 00:00:00 2001 From: obscuren Date: Mon, 17 Nov 2014 12:12:55 +0100 Subject: cleaning up --- chain/chain_manager.go | 285 +++++++++++++++++++++++-------------------------- 1 file changed, 131 insertions(+), 154 deletions(-) (limited to 'chain') diff --git a/chain/chain_manager.go b/chain/chain_manager.go index df390a4c0..02741bc0b 100644 --- a/chain/chain_manager.go +++ b/chain/chain_manager.go @@ -13,9 +13,39 @@ import ( var chainlogger = logger.NewLogger("CHAIN") +func AddTestNetFunds(block *Block) { + for _, addr := range []string{ + "51ba59315b3a95761d0863b05ccc7a7f54703d99", + "e4157b34ea9615cfbde6b4fda419828124b70c78", + "b9c015918bdaba24b4ff057a92a3873d6eb201be", + "6c386a4b26f73c802f34673f7248bb118f97424a", + "cd2a3d9f938e13cd947ec05abc7fe734df8dd826", + "2ef47100e0787b915105fd5e3f4ff6752079d5cb", + "e6716f9544a56c530d868e4bfbacb172315bdead", + "1a26338f0d905e295fccb71fa9ea849ffa12aaf4", + } { + codedAddr := ethutil.Hex2Bytes(addr) + account := block.state.GetAccount(codedAddr) + account.SetBalance(ethutil.Big("1606938044258990275541962092341162602522202993782792835301376")) //ethutil.BigPow(2, 200) + block.state.UpdateStateObject(account) + } +} + +func CalcDifficulty(block, parent *Block) *big.Int { + diff := new(big.Int) + + adjust := new(big.Int).Rsh(parent.Difficulty, 10) + if block.Time >= parent.Time+5 { + diff.Sub(parent.Difficulty, adjust) + } else { + diff.Add(parent.Difficulty, adjust) + } + + return diff +} + type ChainManager struct { - Ethereum EthManager - // The famous, the fabulous Mister GENESIIIIIIS (block) + eth EthManager genesisBlock *Block // Last known total difficulty TD *big.Int @@ -31,17 +61,34 @@ type ChainManager struct { func NewChainManager(ethereum EthManager) *ChainManager { bc := &ChainManager{} bc.genesisBlock = NewBlockFromBytes(ethutil.Encode(Genesis)) - bc.Ethereum = ethereum + bc.eth = ethereum bc.setLastBlock() return bc } -func (bc *ChainManager) Genesis() *Block { - return bc.genesisBlock +func (bc *ChainManager) setLastBlock() { + data, _ := ethutil.Config.Db.Get([]byte("LastBlock")) + if len(data) != 0 { + // Prep genesis + AddTestNetFunds(bc.genesisBlock) + + block := NewBlockFromBytes(data) + bc.CurrentBlock = block + bc.LastBlockHash = block.Hash() + bc.LastBlockNumber = block.Number.Uint64() + + // Set the last know difficulty (might be 0x0 as initial value, Genesis) + bc.TD = ethutil.BigD(ethutil.Config.Db.LastKnownTD()) + } else { + bc.Reset() + } + + chainlogger.Infof("Last block (#%d) %x\n", bc.LastBlockNumber, bc.CurrentBlock.Hash()) } +// Block creation & chain handling func (bc *ChainManager) NewBlock(coinbase []byte) *Block { var root interface{} hash := ZeroHash256 @@ -72,19 +119,6 @@ func (bc *ChainManager) NewBlock(coinbase []byte) *Block { return block } -func CalcDifficulty(block, parent *Block) *big.Int { - diff := new(big.Int) - - adjust := new(big.Int).Rsh(parent.Difficulty, 10) - if block.Time >= parent.Time+5 { - diff.Sub(parent.Difficulty, adjust) - } else { - diff.Add(parent.Difficulty, adjust) - } - - return diff -} - func (bc *ChainManager) Reset() { AddTestNetFunds(bc.genesisBlock) @@ -99,38 +133,31 @@ func (bc *ChainManager) Reset() { bc.TD = ethutil.BigD(ethutil.Config.Db.LastKnownTD()) } -func (bc *ChainManager) HasBlock(hash []byte) bool { - data, _ := ethutil.Config.Db.Get(hash) - return len(data) != 0 -} - -// TODO: At one point we might want to save a block by prevHash in the db to optimise this... -func (bc *ChainManager) HasBlockWithPrevHash(hash []byte) bool { - block := bc.CurrentBlock - - for ; block != nil; block = bc.GetBlock(block.PrevHash) { - if bytes.Compare(hash, block.PrevHash) == 0 { - return true - } - } - return false -} +// Add a block to the chain and record addition information +func (bc *ChainManager) add(block *Block) { + bc.writeBlockInfo(block) -func (bc *ChainManager) CalculateBlockTD(block *Block) *big.Int { - blockDiff := new(big.Int) + bc.CurrentBlock = block + bc.LastBlockHash = block.Hash() - for _, uncle := range block.Uncles { - blockDiff = blockDiff.Add(blockDiff, uncle.Difficulty) - } - blockDiff = blockDiff.Add(blockDiff, block.Difficulty) + encodedBlock := block.RlpEncode() + ethutil.Config.Db.Put(block.Hash(), encodedBlock) + ethutil.Config.Db.Put([]byte("LastBlock"), encodedBlock) - return blockDiff + //chainlogger.Infof("Imported block #%d (%x...)\n", block.Number, block.Hash()[0:4]) } -func (bc *ChainManager) GenesisBlock() *Block { +// Accessors +func (bc *ChainManager) Genesis() *Block { return bc.genesisBlock } +// Block fetching methods +func (bc *ChainManager) HasBlock(hash []byte) bool { + data, _ := ethutil.Config.Db.Get(hash) + return len(data) != 0 +} + func (self *ChainManager) GetChainHashesFromHash(hash []byte, max uint64) (chain [][]byte) { block := self.GetBlock(hash) if block == nil { @@ -152,83 +179,6 @@ func (self *ChainManager) GetChainHashesFromHash(hash []byte, max uint64) (chain return } -func AddTestNetFunds(block *Block) { - for _, addr := range []string{ - "51ba59315b3a95761d0863b05ccc7a7f54703d99", - "e4157b34ea9615cfbde6b4fda419828124b70c78", - "b9c015918bdaba24b4ff057a92a3873d6eb201be", - "6c386a4b26f73c802f34673f7248bb118f97424a", - "cd2a3d9f938e13cd947ec05abc7fe734df8dd826", - "2ef47100e0787b915105fd5e3f4ff6752079d5cb", - "e6716f9544a56c530d868e4bfbacb172315bdead", - "1a26338f0d905e295fccb71fa9ea849ffa12aaf4", - } { - codedAddr := ethutil.Hex2Bytes(addr) - account := block.state.GetAccount(codedAddr) - account.SetBalance(ethutil.Big("1606938044258990275541962092341162602522202993782792835301376")) //ethutil.BigPow(2, 200) - block.state.UpdateStateObject(account) - } -} - -func (bc *ChainManager) setLastBlock() { - data, _ := ethutil.Config.Db.Get([]byte("LastBlock")) - if len(data) != 0 { - // Prep genesis - AddTestNetFunds(bc.genesisBlock) - - block := NewBlockFromBytes(data) - bc.CurrentBlock = block - bc.LastBlockHash = block.Hash() - bc.LastBlockNumber = block.Number.Uint64() - - // Set the last know difficulty (might be 0x0 as initial value, Genesis) - bc.TD = ethutil.BigD(ethutil.Config.Db.LastKnownTD()) - } else { - bc.Reset() - } - - chainlogger.Infof("Last block (#%d) %x\n", bc.LastBlockNumber, bc.CurrentBlock.Hash()) -} - -func (bc *ChainManager) SetTotalDifficulty(td *big.Int) { - ethutil.Config.Db.Put([]byte("LTD"), td.Bytes()) - bc.TD = td -} - -// Add a block to the chain and record addition information -func (bc *ChainManager) add(block *Block) { - bc.writeBlockInfo(block) - - bc.CurrentBlock = block - bc.LastBlockHash = block.Hash() - - encodedBlock := block.RlpEncode() - ethutil.Config.Db.Put(block.Hash(), encodedBlock) - ethutil.Config.Db.Put([]byte("LastBlock"), encodedBlock) - - //chainlogger.Infof("Imported block #%d (%x...)\n", block.Number, block.Hash()[0:4]) -} - -func (self *ChainManager) CalcTotalDiff(block *Block) (*big.Int, error) { - parent := self.GetBlock(block.PrevHash) - if parent == nil { - return nil, fmt.Errorf("Unable to calculate total diff without known parent %x", block.PrevHash) - } - - parentTd := parent.BlockInfo().TD - - uncleDiff := new(big.Int) - for _, uncle := range block.Uncles { - uncleDiff = uncleDiff.Add(uncleDiff, uncle.Difficulty) - } - - td := new(big.Int) - td = td.Add(parentTd, uncleDiff) - td = td.Add(td, block.Difficulty) - - return td, nil -} - func (self *ChainManager) GetBlock(hash []byte) *Block { data, _ := ethutil.Config.Db.Get(hash) if len(data) == 0 { @@ -262,22 +212,29 @@ func (self *ChainManager) GetBlockByNumber(num uint64) *Block { return block } -func (self *ChainManager) GetBlockBack(num uint64) *Block { - block := self.CurrentBlock +func (bc *ChainManager) SetTotalDifficulty(td *big.Int) { + ethutil.Config.Db.Put([]byte("LTD"), td.Bytes()) + bc.TD = td +} - for ; num != 0 && block != nil; num-- { - block = self.GetBlock(block.PrevHash) +func (self *ChainManager) CalcTotalDiff(block *Block) (*big.Int, error) { + parent := self.GetBlock(block.PrevHash) + if parent == nil { + return nil, fmt.Errorf("Unable to calculate total diff without known parent %x", block.PrevHash) } - return block -} + parentTd := parent.BlockInfo().TD -func (bc *ChainManager) BlockInfoByHash(hash []byte) BlockInfo { - bi := BlockInfo{} - data, _ := ethutil.Config.Db.Get(append(hash, []byte("Info")...)) - bi.RlpDecode(data) + uncleDiff := new(big.Int) + for _, uncle := range block.Uncles { + uncleDiff = uncleDiff.Add(uncleDiff, uncle.Difficulty) + } - return bi + td := new(big.Int) + td = td.Add(parentTd, uncleDiff) + td = td.Add(td, block.Difficulty) + + return td, nil } func (bc *ChainManager) BlockInfo(block *Block) BlockInfo { @@ -303,24 +260,8 @@ func (bc *ChainManager) Stop() { } } -type link struct { - block *Block - messages state.Messages - td *big.Int -} - -type BlockChain struct { - *list.List -} - -func NewChain(blocks Blocks) *BlockChain { - chain := &BlockChain{list.New()} - - for _, block := range blocks { - chain.PushBack(&link{block, nil, nil}) - } - - return chain +func (self *ChainManager) NewIterator(startHash []byte) *ChainIterator { + return &ChainIterator{self, self.GetBlock(startHash)} } // This function assumes you've done your checking. No checking is done at this stage anymore @@ -330,8 +271,8 @@ func (self *ChainManager) InsertChain(chain *BlockChain) { self.add(link.block) self.SetTotalDifficulty(link.td) - self.Ethereum.EventMux().Post(NewBlockEvent{link.block}) - self.Ethereum.EventMux().Post(link.messages) + self.eth.EventMux().Post(NewBlockEvent{link.block}) + self.eth.EventMux().Post(link.messages) } b, e := chain.Front(), chain.Back() @@ -352,16 +293,13 @@ func (self *ChainManager) TestChain(chain *BlockChain) (td *big.Int, err error) parent = self.GetBlock(block.PrevHash) ) - //fmt.Println("parent", parent) - //fmt.Println("current", block) - if parent == nil { err = fmt.Errorf("incoming chain broken on hash %x\n", block.PrevHash[0:4]) return } var messages state.Messages - td, messages, err = self.Ethereum.BlockManager().ProcessWithParent(block, parent) + td, messages, err = self.eth.BlockManager().ProcessWithParent(block, parent) if err != nil { chainlogger.Infoln(err) chainlogger.Debugf("Block #%v failed (%x...)\n", block.Number, block.Hash()[0:4]) @@ -383,3 +321,42 @@ func (self *ChainManager) TestChain(chain *BlockChain) (td *big.Int, err error) return } + +type link struct { + block *Block + messages state.Messages + td *big.Int +} + +type BlockChain struct { + *list.List +} + +func NewChain(blocks Blocks) *BlockChain { + chain := &BlockChain{list.New()} + + for _, block := range blocks { + chain.PushBack(&link{block, nil, nil}) + } + + return chain +} + +func (self *BlockChain) RlpEncode() []byte { + dat := make([]interface{}, 0) + for e := self.Front(); e != nil; e = e.Next() { + dat = append(dat, e.Value.(*link).block.RlpData()) + } + + return ethutil.Encode(dat) +} + +type ChainIterator struct { + cm *ChainManager + block *Block // current block in the iterator +} + +func (self *ChainIterator) Prev() *Block { + self.block = self.cm.GetBlock(self.block.PrevHash) + return self.block +} -- cgit v1.2.3 From a1b6a9ac29d0aa8d29a2c0535bafdb5fe4d4830b Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 18 Nov 2014 16:58:22 +0100 Subject: Begin of moving objects to types package * Block(s) * Transaction(s) --- chain/block.go | 419 ---------------------------------------- chain/block_manager.go | 38 ++-- chain/bloom9.go | 56 ------ chain/bloom9_test.go | 29 --- chain/chain_manager.go | 68 ++++--- chain/dagger.go | 5 +- chain/derive_sha.go | 20 -- chain/events.go | 8 +- chain/filter.go | 9 +- chain/receipt.go | 60 ------ chain/state_transition.go | 11 +- chain/transaction.go | 224 --------------------- chain/transaction_pool.go | 41 ++-- chain/transaction_test.go | 1 - chain/types/block.go | 419 ++++++++++++++++++++++++++++++++++++++++ chain/types/bloom9.go | 56 ++++++ chain/types/bloom9_test.go | 30 +++ chain/types/common.go | 10 + chain/types/derive_sha.go | 20 ++ chain/types/receipt.go | 68 +++++++ chain/types/transaction.go | 224 +++++++++++++++++++++ chain/types/transaction_test.go | 1 + chain/vm_env.go | 7 +- 23 files changed, 929 insertions(+), 895 deletions(-) delete mode 100644 chain/block.go delete mode 100644 chain/bloom9.go delete mode 100644 chain/bloom9_test.go delete mode 100644 chain/derive_sha.go delete mode 100644 chain/receipt.go delete mode 100644 chain/transaction.go delete mode 100644 chain/transaction_test.go create mode 100644 chain/types/block.go create mode 100644 chain/types/bloom9.go create mode 100644 chain/types/bloom9_test.go create mode 100644 chain/types/common.go create mode 100644 chain/types/derive_sha.go create mode 100644 chain/types/receipt.go create mode 100644 chain/types/transaction.go create mode 100644 chain/types/transaction_test.go (limited to 'chain') diff --git a/chain/block.go b/chain/block.go deleted file mode 100644 index a4ab560dc..000000000 --- a/chain/block.go +++ /dev/null @@ -1,419 +0,0 @@ -package chain - -import ( - "bytes" - "fmt" - "math/big" - "sort" - "time" - - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/ethutil" - "github.com/ethereum/go-ethereum/state" - "github.com/ethereum/go-ethereum/trie" -) - -type BlockInfo struct { - Number uint64 - Hash []byte - Parent []byte - TD *big.Int -} - -func (bi *BlockInfo) RlpDecode(data []byte) { - decoder := ethutil.NewValueFromBytes(data) - - bi.Number = decoder.Get(0).Uint() - bi.Hash = decoder.Get(1).Bytes() - bi.Parent = decoder.Get(2).Bytes() - bi.TD = decoder.Get(3).BigInt() -} - -func (bi *BlockInfo) RlpEncode() []byte { - return ethutil.Encode([]interface{}{bi.Number, bi.Hash, bi.Parent, bi.TD}) -} - -type Blocks []*Block - -func (self Blocks) AsSet() ethutil.UniqueSet { - set := make(ethutil.UniqueSet) - for _, block := range self { - set.Insert(block.Hash()) - } - - return set -} - -type BlockBy func(b1, b2 *Block) bool - -func (self BlockBy) Sort(blocks Blocks) { - bs := blockSorter{ - blocks: blocks, - by: self, - } - sort.Sort(bs) -} - -type blockSorter struct { - blocks Blocks - by func(b1, b2 *Block) bool -} - -func (self blockSorter) Len() int { return len(self.blocks) } -func (self blockSorter) Swap(i, j int) { - self.blocks[i], self.blocks[j] = self.blocks[j], self.blocks[i] -} -func (self blockSorter) Less(i, j int) bool { return self.by(self.blocks[i], self.blocks[j]) } - -func Number(b1, b2 *Block) bool { return b1.Number.Cmp(b2.Number) < 0 } - -type Block struct { - // Hash to the previous block - PrevHash ethutil.Bytes - // Uncles of this block - Uncles Blocks - UncleSha []byte - // The coin base address - Coinbase []byte - // Block Trie state - //state *ethutil.Trie - state *state.State - // Difficulty for the current block - Difficulty *big.Int - // Creation time - Time int64 - // The block number - Number *big.Int - // Minimum Gas Price - MinGasPrice *big.Int - // Gas limit - GasLimit *big.Int - // Gas used - GasUsed *big.Int - // Extra data - Extra string - // Block Nonce for verification - Nonce ethutil.Bytes - // List of transactions and/or contracts - transactions Transactions - receipts Receipts - TxSha, ReceiptSha []byte - LogsBloom []byte -} - -func NewBlockFromBytes(raw []byte) *Block { - block := &Block{} - block.RlpDecode(raw) - - return block -} - -// New block takes a raw encoded string -func NewBlockFromRlpValue(rlpValue *ethutil.Value) *Block { - block := &Block{} - block.RlpValueDecode(rlpValue) - - return block -} - -func CreateBlock(root interface{}, - prevHash []byte, - base []byte, - Difficulty *big.Int, - Nonce []byte, - extra string) *Block { - - block := &Block{ - PrevHash: prevHash, - Coinbase: base, - Difficulty: Difficulty, - Nonce: Nonce, - Time: time.Now().Unix(), - Extra: extra, - UncleSha: nil, - GasUsed: new(big.Int), - MinGasPrice: new(big.Int), - GasLimit: new(big.Int), - } - block.SetUncles([]*Block{}) - - block.state = state.New(trie.New(ethutil.Config.Db, root)) - - return block -} - -// Returns a hash of the block -func (block *Block) Hash() ethutil.Bytes { - return crypto.Sha3(ethutil.NewValue(block.header()).Encode()) - //return crypto.Sha3(block.Value().Encode()) -} - -func (block *Block) HashNoNonce() []byte { - return crypto.Sha3(ethutil.Encode(block.miningHeader())) -} - -func (block *Block) State() *state.State { - return block.state -} - -func (block *Block) Transactions() []*Transaction { - return block.transactions -} - -func (block *Block) CalcGasLimit(parent *Block) *big.Int { - if block.Number.Cmp(big.NewInt(0)) == 0 { - return ethutil.BigPow(10, 6) - } - - // ((1024-1) * parent.gasLimit + (gasUsed * 6 / 5)) / 1024 - - previous := new(big.Int).Mul(big.NewInt(1024-1), parent.GasLimit) - current := new(big.Rat).Mul(new(big.Rat).SetInt(parent.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 := big.NewInt(125000) - - return ethutil.BigMax(min, result) -} - -func (block *Block) BlockInfo() BlockInfo { - bi := BlockInfo{} - data, _ := ethutil.Config.Db.Get(append(block.Hash(), []byte("Info")...)) - bi.RlpDecode(data) - - return bi -} - -func (self *Block) GetTransaction(hash []byte) *Transaction { - for _, tx := range self.transactions { - if bytes.Compare(tx.Hash(), hash) == 0 { - return tx - } - } - - return nil -} - -// Sync the block's state and contract respectively -func (block *Block) Sync() { - block.state.Sync() -} - -func (block *Block) Undo() { - // Sync the block state itself - block.state.Reset() -} - -/////// Block Encoding -func (block *Block) rlpReceipts() interface{} { - // Marshal the transactions of this block - encR := make([]interface{}, len(block.receipts)) - for i, r := range block.receipts { - // Cast it to a string (safe) - encR[i] = r.RlpData() - } - - return encR -} - -func (block *Block) rlpUncles() interface{} { - // Marshal the transactions of this block - uncles := make([]interface{}, len(block.Uncles)) - for i, uncle := range block.Uncles { - // Cast it to a string (safe) - uncles[i] = uncle.header() - } - - return uncles -} - -func (block *Block) SetUncles(uncles []*Block) { - block.Uncles = uncles - block.UncleSha = crypto.Sha3(ethutil.Encode(block.rlpUncles())) -} - -func (self *Block) SetReceipts(receipts Receipts) { - self.receipts = receipts - self.ReceiptSha = DeriveSha(receipts) - self.LogsBloom = CreateBloom(receipts) -} - -func (self *Block) SetTransactions(txs Transactions) { - self.transactions = txs - self.TxSha = DeriveSha(txs) -} - -func (block *Block) Value() *ethutil.Value { - return ethutil.NewValue([]interface{}{block.header(), block.transactions, block.rlpUncles()}) -} - -func (block *Block) RlpEncode() []byte { - // Encode a slice interface which contains the header and the list of - // transactions. - return block.Value().Encode() -} - -func (block *Block) RlpDecode(data []byte) { - rlpValue := ethutil.NewValueFromBytes(data) - block.RlpValueDecode(rlpValue) -} - -func (block *Block) RlpValueDecode(decoder *ethutil.Value) { - block.setHeader(decoder.Get(0)) - - // Tx list might be empty if this is an uncle. Uncles only have their - // header set. - if decoder.Get(1).IsNil() == false { // Yes explicitness - //receipts := decoder.Get(1) - //block.receipts = make([]*Receipt, receipts.Len()) - txs := decoder.Get(1) - block.transactions = make(Transactions, txs.Len()) - for i := 0; i < txs.Len(); i++ { - block.transactions[i] = NewTransactionFromValue(txs.Get(i)) - //receipt := NewRecieptFromValue(receipts.Get(i)) - //block.transactions[i] = receipt.Tx - //block.receipts[i] = receipt - } - - } - - if decoder.Get(2).IsNil() == false { // Yes explicitness - uncles := decoder.Get(2) - block.Uncles = make([]*Block, uncles.Len()) - for i := 0; i < uncles.Len(); i++ { - block.Uncles[i] = NewUncleBlockFromValue(uncles.Get(i)) - } - } - -} - -func (self *Block) setHeader(header *ethutil.Value) { - self.PrevHash = header.Get(0).Bytes() - self.UncleSha = header.Get(1).Bytes() - self.Coinbase = header.Get(2).Bytes() - self.state = state.New(trie.New(ethutil.Config.Db, header.Get(3).Val)) - self.TxSha = header.Get(4).Bytes() - self.ReceiptSha = header.Get(5).Bytes() - self.LogsBloom = header.Get(6).Bytes() - self.Difficulty = header.Get(7).BigInt() - self.Number = header.Get(8).BigInt() - self.MinGasPrice = header.Get(9).BigInt() - self.GasLimit = header.Get(10).BigInt() - self.GasUsed = header.Get(11).BigInt() - self.Time = int64(header.Get(12).BigInt().Uint64()) - self.Extra = header.Get(13).Str() - self.Nonce = header.Get(14).Bytes() -} - -func NewUncleBlockFromValue(header *ethutil.Value) *Block { - block := &Block{} - block.setHeader(header) - - return block -} - -func (block *Block) Trie() *trie.Trie { - return block.state.Trie -} - -func (block *Block) Root() interface{} { - return block.state.Root() -} - -func (block *Block) Diff() *big.Int { - return block.Difficulty -} - -func (self *Block) Receipts() []*Receipt { - return self.receipts -} - -func (block *Block) miningHeader() []interface{} { - return []interface{}{ - // Sha of the previous block - block.PrevHash, - // Sha of uncles - block.UncleSha, - // Coinbase address - block.Coinbase, - // root state - block.Root(), - // tx root - block.TxSha, - // Sha of tx - block.ReceiptSha, - // Bloom - block.LogsBloom, - // Current block Difficulty - block.Difficulty, - // The block number - block.Number, - // Block minimum gas price - block.MinGasPrice, - // Block upper gas bound - block.GasLimit, - // Block gas used - block.GasUsed, - // Time the block was found? - block.Time, - // Extra data - block.Extra, - } -} - -func (block *Block) header() []interface{} { - return append(block.miningHeader(), block.Nonce) -} - -func (block *Block) String() string { - return fmt.Sprintf(` - BLOCK(%x): Size: %v - PrevHash: %x - UncleSha: %x - Coinbase: %x - Root: %x - TxSha %x - ReceiptSha: %x - Bloom: %x - Difficulty: %v - Number: %v - MinGas: %v - MaxLimit: %v - GasUsed: %v - Time: %v - Extra: %v - Nonce: %x - NumTx: %v -`, - block.Hash(), - block.Size(), - block.PrevHash, - block.UncleSha, - block.Coinbase, - block.Root(), - block.TxSha, - block.ReceiptSha, - block.LogsBloom, - block.Difficulty, - block.Number, - block.MinGasPrice, - block.GasLimit, - block.GasUsed, - block.Time, - block.Extra, - block.Nonce, - len(block.transactions), - ) -} - -func (self *Block) Size() ethutil.StorageSize { - return ethutil.StorageSize(len(self.RlpEncode())) -} - -// Implement RlpEncodable -func (self *Block) RlpData() interface{} { - return self.Value().Val -} diff --git a/chain/block_manager.go b/chain/block_manager.go index efe9e0862..e652ad10e 100644 --- a/chain/block_manager.go +++ b/chain/block_manager.go @@ -9,6 +9,7 @@ import ( "sync" "time" + "github.com/ethereum/go-ethereum/chain/types" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/ethutil" "github.com/ethereum/go-ethereum/event" @@ -69,7 +70,7 @@ type BlockManager struct { // The last attempted block is mainly used for debugging purposes // This does not have to be a valid block and will be set during // 'Process' & canonical validation. - lastAttemptedBlock *Block + lastAttemptedBlock *types.Block events event.Subscription } @@ -117,11 +118,11 @@ func (sm *BlockManager) ChainManager() *ChainManager { return sm.bc } -func (self *BlockManager) ProcessTransactions(coinbase *state.StateObject, state *state.State, block, parent *Block, txs Transactions) (Receipts, Transactions, Transactions, Transactions, error) { +func (self *BlockManager) ProcessTransactions(coinbase *state.StateObject, state *state.State, block, parent *types.Block, txs types.Transactions) (types.Receipts, types.Transactions, types.Transactions, types.Transactions, error) { var ( - receipts Receipts - handled, unhandled Transactions - erroneous Transactions + receipts types.Receipts + handled, unhandled types.Transactions + erroneous types.Transactions totalUsedGas = big.NewInt(0) err error ) @@ -159,8 +160,9 @@ done: txGas.Sub(txGas, st.gas) cumulative := new(big.Int).Set(totalUsedGas.Add(totalUsedGas, txGas)) - receipt := &Receipt{ethutil.CopyBytes(state.Root()), cumulative, nil /*bloom*/, state.Logs()} - receipt.Bloom = CreateBloom(Receipts{receipt}) + receipt := types.NewReceipt(state.Root(), cumulative) + receipt.SetLogs(state.Logs()) + receipt.Bloom = types.CreateBloom(types.Receipts{receipt}) // Notify all subscribers go self.eth.EventMux().Post(TxPostEvent{tx}) @@ -178,7 +180,7 @@ done: return receipts, handled, unhandled, erroneous, err } -func (sm *BlockManager) Process(block *Block) (td *big.Int, msgs state.Messages, err error) { +func (sm *BlockManager) Process(block *types.Block) (td *big.Int, msgs state.Messages, err error) { // Processing a blocks may never happen simultaneously sm.mutex.Lock() defer sm.mutex.Unlock() @@ -195,7 +197,7 @@ func (sm *BlockManager) Process(block *Block) (td *big.Int, msgs state.Messages, return sm.ProcessWithParent(block, parent) } -func (sm *BlockManager) ProcessWithParent(block, parent *Block) (td *big.Int, messages state.Messages, err error) { +func (sm *BlockManager) ProcessWithParent(block, parent *types.Block) (td *big.Int, messages state.Messages, err error) { sm.lastAttemptedBlock = block state := parent.State().Copy() @@ -215,13 +217,13 @@ func (sm *BlockManager) ProcessWithParent(block, parent *Block) (td *big.Int, me return } - txSha := DeriveSha(block.transactions) + txSha := types.DeriveSha(block.Transactions()) if bytes.Compare(txSha, block.TxSha) != 0 { err = fmt.Errorf("validating transaction root. received=%x got=%x", block.TxSha, txSha) return } - receiptSha := DeriveSha(receipts) + receiptSha := types.DeriveSha(receipts) if bytes.Compare(receiptSha, block.ReceiptSha) != 0 { err = fmt.Errorf("validating receipt root. received=%x got=%x", block.ReceiptSha, receiptSha) return @@ -238,8 +240,8 @@ func (sm *BlockManager) ProcessWithParent(block, parent *Block) (td *big.Int, me return } - block.receipts = receipts // although this isn't necessary it be in the future - rbloom := CreateBloom(receipts) + //block.receipts = receipts // although this isn't necessary it be in the future + rbloom := types.CreateBloom(receipts) if bytes.Compare(rbloom, block.LogsBloom) != 0 { err = fmt.Errorf("unable to replicate block's bloom=%x", rbloom) return @@ -272,7 +274,7 @@ func (sm *BlockManager) ProcessWithParent(block, parent *Block) (td *big.Int, me } } -func (sm *BlockManager) ApplyDiff(state *state.State, parent, block *Block) (receipts Receipts, err error) { +func (sm *BlockManager) ApplyDiff(state *state.State, parent, block *types.Block) (receipts types.Receipts, err error) { coinbase := state.GetOrNewStateObject(block.Coinbase) coinbase.SetGasPool(block.CalcGasLimit(parent)) @@ -285,7 +287,7 @@ func (sm *BlockManager) ApplyDiff(state *state.State, parent, block *Block) (rec return receipts, nil } -func (sm *BlockManager) CalculateTD(block *Block) (*big.Int, bool) { +func (sm *BlockManager) CalculateTD(block *types.Block) (*big.Int, bool) { uncleDiff := new(big.Int) for _, uncle := range block.Uncles { uncleDiff = uncleDiff.Add(uncleDiff, uncle.Difficulty) @@ -311,7 +313,7 @@ func (sm *BlockManager) CalculateTD(block *Block) (*big.Int, bool) { // Validates the current block. Returns an error if the block was invalid, // an uncle or anything that isn't on the current block chain. // Validation validates easy over difficult (dagger takes longer time = difficult) -func (sm *BlockManager) ValidateBlock(block, parent *Block) error { +func (sm *BlockManager) ValidateBlock(block, parent *types.Block) error { expd := CalcDifficulty(block, parent) if expd.Cmp(block.Difficulty) < 0 { return fmt.Errorf("Difficulty check failed for block %v, %v", block.Difficulty, expd) @@ -337,7 +339,7 @@ func (sm *BlockManager) ValidateBlock(block, parent *Block) error { return nil } -func (sm *BlockManager) AccumelateRewards(state *state.State, block, parent *Block) error { +func (sm *BlockManager) AccumelateRewards(state *state.State, block, parent *types.Block) error { reward := new(big.Int).Set(BlockReward) knownUncles := ethutil.Set(parent.Uncles) @@ -380,7 +382,7 @@ func (sm *BlockManager) AccumelateRewards(state *state.State, block, parent *Blo return nil } -func (sm *BlockManager) GetMessages(block *Block) (messages []*state.Message, err error) { +func (sm *BlockManager) GetMessages(block *types.Block) (messages []*state.Message, err error) { if !sm.bc.HasBlock(block.PrevHash) { return nil, ParentError(block.PrevHash) } diff --git a/chain/bloom9.go b/chain/bloom9.go deleted file mode 100644 index c610bd101..000000000 --- a/chain/bloom9.go +++ /dev/null @@ -1,56 +0,0 @@ -package chain - -import ( - "math/big" - - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/ethutil" - "github.com/ethereum/go-ethereum/state" -) - -func CreateBloom(receipts Receipts) []byte { - bin := new(big.Int) - for _, receipt := range receipts { - bin.Or(bin, logsBloom(receipt.logs)) - } - - return ethutil.LeftPadBytes(bin.Bytes(), 64) -} - -func logsBloom(logs state.Logs) *big.Int { - bin := new(big.Int) - for _, log := range logs { - data := [][]byte{log.Address} - for _, topic := range log.Topics { - data = append(data, topic) - } - - for _, b := range data { - bin.Or(bin, ethutil.BigD(bloom9(crypto.Sha3(b)).Bytes())) - } - - //if log.Data != nil { - // data = append(data, log.Data) - //} - } - - return bin -} - -func bloom9(b []byte) *big.Int { - r := new(big.Int) - for _, i := range []int{0, 2, 4} { - t := big.NewInt(1) - b := uint(b[i+1]) + 256*(uint(b[i])&1) - r.Or(r, t.Lsh(t, b)) - } - - return r -} - -func BloomLookup(bin, topic []byte) bool { - bloom := ethutil.BigD(bin) - cmp := bloom9(crypto.Sha3(topic)) - - return bloom.And(bloom, cmp).Cmp(cmp) == 0 -} diff --git a/chain/bloom9_test.go b/chain/bloom9_test.go deleted file mode 100644 index 8b1b962cb..000000000 --- a/chain/bloom9_test.go +++ /dev/null @@ -1,29 +0,0 @@ -package chain - -import ( - "testing" - "github.com/ethereum/go-ethereum/state" -) - -func TestBloom9(t *testing.T) { - testCase := []byte("testtest") - bin := LogsBloom([]state.Log{ - {testCase, [][]byte{[]byte("hellohello")}, nil}, - }).Bytes() - res := BloomLookup(bin, testCase) - - if !res { - t.Errorf("Bloom lookup failed") - } -} - -/* -func TestAddress(t *testing.T) { - block := &Block{} - block.Coinbase = ethutil.Hex2Bytes("22341ae42d6dd7384bc8584e50419ea3ac75b83f") - fmt.Printf("%x\n", crypto.Sha3(block.Coinbase)) - - bin := CreateBloom(block) - fmt.Printf("bin = %x\n", ethutil.LeftPadBytes(bin, 64)) -} -*/ diff --git a/chain/chain_manager.go b/chain/chain_manager.go index 02741bc0b..11df4e17e 100644 --- a/chain/chain_manager.go +++ b/chain/chain_manager.go @@ -6,6 +6,7 @@ import ( "fmt" "math/big" + "github.com/ethereum/go-ethereum/chain/types" "github.com/ethereum/go-ethereum/ethutil" "github.com/ethereum/go-ethereum/logger" "github.com/ethereum/go-ethereum/state" @@ -13,7 +14,7 @@ import ( var chainlogger = logger.NewLogger("CHAIN") -func AddTestNetFunds(block *Block) { +func AddTestNetFunds(block *types.Block) { for _, addr := range []string{ "51ba59315b3a95761d0863b05ccc7a7f54703d99", "e4157b34ea9615cfbde6b4fda419828124b70c78", @@ -25,13 +26,13 @@ func AddTestNetFunds(block *Block) { "1a26338f0d905e295fccb71fa9ea849ffa12aaf4", } { codedAddr := ethutil.Hex2Bytes(addr) - account := block.state.GetAccount(codedAddr) + account := block.State().GetAccount(codedAddr) account.SetBalance(ethutil.Big("1606938044258990275541962092341162602522202993782792835301376")) //ethutil.BigPow(2, 200) - block.state.UpdateStateObject(account) + block.State().UpdateStateObject(account) } } -func CalcDifficulty(block, parent *Block) *big.Int { +func CalcDifficulty(block, parent *types.Block) *big.Int { diff := new(big.Int) adjust := new(big.Int).Rsh(parent.Difficulty, 10) @@ -45,36 +46,41 @@ func CalcDifficulty(block, parent *Block) *big.Int { } type ChainManager struct { - eth EthManager - genesisBlock *Block + //eth EthManager + processor types.BlockProcessor + genesisBlock *types.Block // Last known total difficulty TD *big.Int LastBlockNumber uint64 - CurrentBlock *Block + CurrentBlock *types.Block LastBlockHash []byte workingChain *BlockChain } -func NewChainManager(ethereum EthManager) *ChainManager { +func NewChainManager() *ChainManager { bc := &ChainManager{} - bc.genesisBlock = NewBlockFromBytes(ethutil.Encode(Genesis)) - bc.eth = ethereum + bc.genesisBlock = types.NewBlockFromBytes(ethutil.Encode(Genesis)) + //bc.eth = ethereum bc.setLastBlock() return bc } +func (self *ChainManager) SetProcessor(proc types.BlockProcessor) { + self.processor = proc +} + func (bc *ChainManager) setLastBlock() { data, _ := ethutil.Config.Db.Get([]byte("LastBlock")) if len(data) != 0 { // Prep genesis AddTestNetFunds(bc.genesisBlock) - block := NewBlockFromBytes(data) + block := types.NewBlockFromBytes(data) bc.CurrentBlock = block bc.LastBlockHash = block.Hash() bc.LastBlockNumber = block.Number.Uint64() @@ -89,7 +95,7 @@ func (bc *ChainManager) setLastBlock() { } // Block creation & chain handling -func (bc *ChainManager) NewBlock(coinbase []byte) *Block { +func (bc *ChainManager) NewBlock(coinbase []byte) *types.Block { var root interface{} hash := ZeroHash256 @@ -98,7 +104,7 @@ func (bc *ChainManager) NewBlock(coinbase []byte) *Block { hash = bc.LastBlockHash } - block := CreateBlock( + block := types.CreateBlock( root, hash, coinbase, @@ -122,7 +128,7 @@ func (bc *ChainManager) NewBlock(coinbase []byte) *Block { func (bc *ChainManager) Reset() { AddTestNetFunds(bc.genesisBlock) - bc.genesisBlock.state.Trie.Sync() + bc.genesisBlock.Trie().Sync() // Prepare the genesis block bc.add(bc.genesisBlock) bc.CurrentBlock = bc.genesisBlock @@ -134,7 +140,7 @@ func (bc *ChainManager) Reset() { } // Add a block to the chain and record addition information -func (bc *ChainManager) add(block *Block) { +func (bc *ChainManager) add(block *types.Block) { bc.writeBlockInfo(block) bc.CurrentBlock = block @@ -148,7 +154,7 @@ func (bc *ChainManager) add(block *Block) { } // Accessors -func (bc *ChainManager) Genesis() *Block { +func (bc *ChainManager) Genesis() *types.Block { return bc.genesisBlock } @@ -179,7 +185,7 @@ func (self *ChainManager) GetChainHashesFromHash(hash []byte, max uint64) (chain return } -func (self *ChainManager) GetBlock(hash []byte) *Block { +func (self *ChainManager) GetBlock(hash []byte) *types.Block { data, _ := ethutil.Config.Db.Get(hash) if len(data) == 0 { if self.workingChain != nil { @@ -194,10 +200,10 @@ func (self *ChainManager) GetBlock(hash []byte) *Block { return nil } - return NewBlockFromBytes(data) + return types.NewBlockFromBytes(data) } -func (self *ChainManager) GetBlockByNumber(num uint64) *Block { +func (self *ChainManager) GetBlockByNumber(num uint64) *types.Block { block := self.CurrentBlock for ; block != nil; block = self.GetBlock(block.PrevHash) { if block.Number.Uint64() == num { @@ -217,7 +223,7 @@ func (bc *ChainManager) SetTotalDifficulty(td *big.Int) { bc.TD = td } -func (self *ChainManager) CalcTotalDiff(block *Block) (*big.Int, error) { +func (self *ChainManager) CalcTotalDiff(block *types.Block) (*big.Int, error) { parent := self.GetBlock(block.PrevHash) if parent == nil { return nil, fmt.Errorf("Unable to calculate total diff without known parent %x", block.PrevHash) @@ -237,8 +243,8 @@ func (self *ChainManager) CalcTotalDiff(block *Block) (*big.Int, error) { return td, nil } -func (bc *ChainManager) BlockInfo(block *Block) BlockInfo { - bi := BlockInfo{} +func (bc *ChainManager) BlockInfo(block *types.Block) types.BlockInfo { + bi := types.BlockInfo{} data, _ := ethutil.Config.Db.Get(append(block.Hash(), []byte("Info")...)) bi.RlpDecode(data) @@ -246,9 +252,9 @@ func (bc *ChainManager) BlockInfo(block *Block) BlockInfo { } // Unexported method for writing extra non-essential block info to the db -func (bc *ChainManager) writeBlockInfo(block *Block) { +func (bc *ChainManager) writeBlockInfo(block *types.Block) { bc.LastBlockNumber++ - bi := BlockInfo{Number: bc.LastBlockNumber, Hash: block.Hash(), Parent: block.PrevHash, TD: bc.TD} + bi := types.BlockInfo{Number: bc.LastBlockNumber, Hash: block.Hash(), Parent: block.PrevHash, TD: bc.TD} // For now we use the block hash with the words "info" appended as key ethutil.Config.Db.Put(append(block.Hash(), []byte("Info")...), bi.RlpEncode()) @@ -271,8 +277,8 @@ func (self *ChainManager) InsertChain(chain *BlockChain) { self.add(link.block) self.SetTotalDifficulty(link.td) - self.eth.EventMux().Post(NewBlockEvent{link.block}) - self.eth.EventMux().Post(link.messages) + //self.eth.EventMux().Post(NewBlockEvent{link.block}) + //self.eth.EventMux().Post(link.messages) } b, e := chain.Front(), chain.Back() @@ -299,7 +305,7 @@ func (self *ChainManager) TestChain(chain *BlockChain) (td *big.Int, err error) } var messages state.Messages - td, messages, err = self.eth.BlockManager().ProcessWithParent(block, parent) + td, messages, err = self.processor.ProcessWithParent(block, parent) //self.eth.BlockManager().ProcessWithParent(block, parent) if err != nil { chainlogger.Infoln(err) chainlogger.Debugf("Block #%v failed (%x...)\n", block.Number, block.Hash()[0:4]) @@ -323,7 +329,7 @@ func (self *ChainManager) TestChain(chain *BlockChain) (td *big.Int, err error) } type link struct { - block *Block + block *types.Block messages state.Messages td *big.Int } @@ -332,7 +338,7 @@ type BlockChain struct { *list.List } -func NewChain(blocks Blocks) *BlockChain { +func NewChain(blocks types.Blocks) *BlockChain { chain := &BlockChain{list.New()} for _, block := range blocks { @@ -353,10 +359,10 @@ func (self *BlockChain) RlpEncode() []byte { type ChainIterator struct { cm *ChainManager - block *Block // current block in the iterator + block *types.Block // current block in the iterator } -func (self *ChainIterator) Prev() *Block { +func (self *ChainIterator) Prev() *types.Block { self.block = self.cm.GetBlock(self.block.PrevHash) return self.block } diff --git a/chain/dagger.go b/chain/dagger.go index 2cf70e091..f7e2229e9 100644 --- a/chain/dagger.go +++ b/chain/dagger.go @@ -6,6 +6,7 @@ import ( "math/rand" "time" + "github.com/ethereum/go-ethereum/chain/types" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/ethutil" "github.com/ethereum/go-ethereum/logger" @@ -15,7 +16,7 @@ import ( var powlogger = logger.NewLogger("POW") type PoW interface { - Search(block *Block, stop <-chan struct{}) []byte + Search(block *types.Block, stop <-chan struct{}) []byte Verify(hash []byte, diff *big.Int, nonce []byte) bool GetHashrate() int64 Turbo(bool) @@ -35,7 +36,7 @@ func (pow *EasyPow) Turbo(on bool) { pow.turbo = on } -func (pow *EasyPow) Search(block *Block, stop <-chan struct{}) []byte { +func (pow *EasyPow) Search(block *types.Block, stop <-chan struct{}) []byte { r := rand.New(rand.NewSource(time.Now().UnixNano())) hash := block.HashNoNonce() diff := block.Difficulty diff --git a/chain/derive_sha.go b/chain/derive_sha.go deleted file mode 100644 index 4246aeb02..000000000 --- a/chain/derive_sha.go +++ /dev/null @@ -1,20 +0,0 @@ -package chain - -import ( - "github.com/ethereum/go-ethereum/ethutil" - "github.com/ethereum/go-ethereum/trie" -) - -type DerivableList interface { - Len() int - GetRlp(i int) []byte -} - -func DeriveSha(list DerivableList) []byte { - trie := trie.New(ethutil.Config.Db, "") - for i := 0; i < list.Len(); i++ { - trie.Update(string(ethutil.NewValue(i).Encode()), string(list.GetRlp(i))) - } - - return trie.GetRoot() -} diff --git a/chain/events.go b/chain/events.go index 2703e955d..06ab6be79 100644 --- a/chain/events.go +++ b/chain/events.go @@ -1,10 +1,12 @@ package chain +import "github.com/ethereum/go-ethereum/chain/types" + // TxPreEvent is posted when a transaction enters the transaction pool. -type TxPreEvent struct{ Tx *Transaction } +type TxPreEvent struct{ Tx *types.Transaction } // TxPostEvent is posted when a transaction has been processed. -type TxPostEvent struct{ Tx *Transaction } +type TxPostEvent struct{ Tx *types.Transaction } // NewBlockEvent is posted when a block has been imported. -type NewBlockEvent struct{ Block *Block } +type NewBlockEvent struct{ Block *types.Block } diff --git a/chain/filter.go b/chain/filter.go index 3c0b02d4f..fd8adaa8f 100644 --- a/chain/filter.go +++ b/chain/filter.go @@ -5,6 +5,7 @@ import ( "math" "math/big" + "github.com/ethereum/go-ethereum/chain/types" "github.com/ethereum/go-ethereum/ethutil" "github.com/ethereum/go-ethereum/state" ) @@ -24,7 +25,7 @@ type Filter struct { Altered []AccountChange - BlockCallback func(*Block) + BlockCallback func(*types.Block) MessageCallback func(state.Messages) } @@ -171,11 +172,11 @@ func (self *Filter) FilterMessages(msgs []*state.Message) []*state.Message { return messages } -func (self *Filter) bloomFilter(block *Block) bool { +func (self *Filter) bloomFilter(block *types.Block) bool { var fromIncluded, toIncluded bool if len(self.from) > 0 { for _, from := range self.from { - if BloomLookup(block.LogsBloom, from) { + if types.BloomLookup(block.LogsBloom, from) { fromIncluded = true break } @@ -186,7 +187,7 @@ func (self *Filter) bloomFilter(block *Block) bool { if len(self.to) > 0 { for _, to := range self.to { - if BloomLookup(block.LogsBloom, ethutil.U256(new(big.Int).Add(ethutil.Big1, ethutil.BigD(to))).Bytes()) { + if types.BloomLookup(block.LogsBloom, ethutil.U256(new(big.Int).Add(ethutil.Big1, ethutil.BigD(to))).Bytes()) { toIncluded = true break } diff --git a/chain/receipt.go b/chain/receipt.go deleted file mode 100644 index fa53f1cdb..000000000 --- a/chain/receipt.go +++ /dev/null @@ -1,60 +0,0 @@ -package chain - -import ( - "bytes" - "fmt" - "math/big" - - "github.com/ethereum/go-ethereum/ethutil" - "github.com/ethereum/go-ethereum/state" -) - -type Receipt struct { - PostState []byte - CumulativeGasUsed *big.Int - Bloom []byte - logs state.Logs -} - -func NewRecieptFromValue(val *ethutil.Value) *Receipt { - r := &Receipt{} - r.RlpValueDecode(val) - - return r -} - -func (self *Receipt) RlpValueDecode(decoder *ethutil.Value) { - self.PostState = decoder.Get(0).Bytes() - self.CumulativeGasUsed = decoder.Get(1).BigInt() - self.Bloom = decoder.Get(2).Bytes() - - it := decoder.Get(3).NewIterator() - for it.Next() { - self.logs = append(self.logs, state.NewLogFromValue(it.Value())) - } -} - -func (self *Receipt) RlpData() interface{} { - return []interface{}{self.PostState, self.CumulativeGasUsed, self.Bloom, self.logs.RlpData()} -} - -func (self *Receipt) RlpEncode() []byte { - return ethutil.Encode(self.RlpData()) -} - -func (self *Receipt) Cmp(other *Receipt) bool { - if bytes.Compare(self.PostState, other.PostState) != 0 { - return false - } - - return true -} - -func (self *Receipt) String() string { - return fmt.Sprintf("receipt{med=%x cgas=%v bloom=%x logs=%v}", self.PostState, self.CumulativeGasUsed, self.Bloom, self.logs) -} - -type Receipts []*Receipt - -func (self Receipts) Len() int { return len(self) } -func (self Receipts) GetRlp(i int) []byte { return ethutil.Rlp(self[i]) } diff --git a/chain/state_transition.go b/chain/state_transition.go index afe044299..789698675 100644 --- a/chain/state_transition.go +++ b/chain/state_transition.go @@ -4,6 +4,7 @@ import ( "fmt" "math/big" + "github.com/ethereum/go-ethereum/chain/types" "github.com/ethereum/go-ethereum/state" "github.com/ethereum/go-ethereum/vm" ) @@ -26,17 +27,17 @@ import ( */ type StateTransition struct { coinbase, receiver []byte - tx *Transaction + tx *types.Transaction gas, gasPrice *big.Int value *big.Int data []byte state *state.State - block *Block + block *types.Block cb, rec, sen *state.StateObject } -func NewStateTransition(coinbase *state.StateObject, tx *Transaction, state *state.State, block *Block) *StateTransition { +func NewStateTransition(coinbase *state.StateObject, tx *types.Transaction, state *state.State, block *types.Block) *StateTransition { return &StateTransition{coinbase.Address(), tx.Recipient, tx, new(big.Int), new(big.Int).Set(tx.GasPrice), tx.Value, tx.Data, state, block, coinbase, nil, nil} } @@ -203,7 +204,7 @@ func (self *StateTransition) TransitionState() (err error) { }) // Process the init code and create 'valid' contract - if IsContractAddr(self.receiver) { + if types.IsContractAddr(self.receiver) { // Evaluate the initialization script // and use the return value as the // script section for the state object. @@ -280,7 +281,7 @@ func (self *StateTransition) Eval(msg *state.Message, script []byte, context *st } // Converts an transaction in to a state object -func MakeContract(tx *Transaction, state *state.State) *state.StateObject { +func MakeContract(tx *types.Transaction, state *state.State) *state.StateObject { addr := tx.CreationAddress(state) contract := state.GetOrNewStateObject(addr) diff --git a/chain/transaction.go b/chain/transaction.go deleted file mode 100644 index d81a0ea1b..000000000 --- a/chain/transaction.go +++ /dev/null @@ -1,224 +0,0 @@ -package chain - -import ( - "fmt" - "math/big" - - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/ethutil" - "github.com/ethereum/go-ethereum/state" - "github.com/obscuren/secp256k1-go" -) - -var ContractAddr = []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} - -func IsContractAddr(addr []byte) bool { - return len(addr) == 0 - //return bytes.Compare(addr, ContractAddr) == 0 -} - -type Transaction struct { - Nonce uint64 - Recipient []byte - Value *big.Int - Gas *big.Int - GasPrice *big.Int - Data []byte - v byte - r, s []byte - - // Indicates whether this tx is a contract creation transaction - contractCreation bool -} - -func NewContractCreationTx(value, gas, gasPrice *big.Int, script []byte) *Transaction { - return &Transaction{Recipient: nil, Value: value, Gas: gas, GasPrice: gasPrice, Data: script, contractCreation: true} -} - -func NewTransactionMessage(to []byte, value, gas, gasPrice *big.Int, data []byte) *Transaction { - return &Transaction{Recipient: to, Value: value, GasPrice: gasPrice, Gas: gas, Data: data, contractCreation: IsContractAddr(to)} -} - -func NewTransactionFromBytes(data []byte) *Transaction { - tx := &Transaction{} - tx.RlpDecode(data) - - return tx -} - -func NewTransactionFromValue(val *ethutil.Value) *Transaction { - tx := &Transaction{} - tx.RlpValueDecode(val) - - 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} - - return crypto.Sha3(ethutil.NewValue(data).Encode()) -} - -func (tx *Transaction) CreatesContract() bool { - return tx.contractCreation -} - -/* Deprecated */ -func (tx *Transaction) IsContract() bool { - return tx.CreatesContract() -} - -func (tx *Transaction) CreationAddress(state *state.State) []byte { - // Generate a new address - addr := crypto.Sha3(ethutil.NewValue([]interface{}{tx.Sender(), tx.Nonce}).Encode())[12:] - //for i := uint64(0); state.GetStateObject(addr) != nil; i++ { - // addr = crypto.Sha3(ethutil.NewValue([]interface{}{tx.Sender(), tx.Nonce + i}).Encode())[12:] - //} - - return addr -} - -func (tx *Transaction) Signature(key []byte) []byte { - hash := tx.Hash() - - sig, _ := secp256k1.Sign(hash, key) - - return sig -} - -func (tx *Transaction) PublicKey() []byte { - hash := tx.Hash() - - // TODO - r := ethutil.LeftPadBytes(tx.r, 32) - s := ethutil.LeftPadBytes(tx.s, 32) - - sig := append(r, s...) - sig = append(sig, tx.v-27) - - pubkey := crypto.Ecrecover(append(hash, sig...)) - //pubkey, _ := secp256k1.RecoverPubkey(hash, sig) - - return pubkey -} - -func (tx *Transaction) Sender() []byte { - pubkey := tx.PublicKey() - - // Validate the returned key. - // Return nil if public key isn't in full format - if len(pubkey) != 0 && pubkey[0] != 4 { - return nil - } - - return crypto.Sha3(pubkey[1:])[12:] -} - -func (tx *Transaction) Sign(privk []byte) error { - - sig := tx.Signature(privk) - - tx.r = sig[:32] - tx.s = sig[32:64] - tx.v = sig[64] + 27 - - return nil -} - -func (tx *Transaction) RlpData() interface{} { - data := []interface{}{tx.Nonce, tx.GasPrice, tx.Gas, tx.Recipient, tx.Value, tx.Data} - - // TODO Remove prefixing zero's - - return append(data, tx.v, new(big.Int).SetBytes(tx.r).Bytes(), new(big.Int).SetBytes(tx.s).Bytes()) -} - -func (tx *Transaction) RlpValue() *ethutil.Value { - return ethutil.NewValue(tx.RlpData()) -} - -func (tx *Transaction) RlpEncode() []byte { - return tx.RlpValue().Encode() -} - -func (tx *Transaction) RlpDecode(data []byte) { - tx.RlpValueDecode(ethutil.NewValueFromBytes(data)) -} - -func (tx *Transaction) RlpValueDecode(decoder *ethutil.Value) { - tx.Nonce = decoder.Get(0).Uint() - tx.GasPrice = decoder.Get(1).BigInt() - tx.Gas = decoder.Get(2).BigInt() - tx.Recipient = decoder.Get(3).Bytes() - tx.Value = decoder.Get(4).BigInt() - tx.Data = decoder.Get(5).Bytes() - tx.v = byte(decoder.Get(6).Uint()) - - tx.r = decoder.Get(7).Bytes() - tx.s = decoder.Get(8).Bytes() - - if IsContractAddr(tx.Recipient) { - tx.contractCreation = true - } -} - -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) -} - -// Transaction slice type for basic sorting -type Transactions []*Transaction - -func (self Transactions) RlpData() interface{} { - // Marshal the transactions of this block - enc := make([]interface{}, len(self)) - for i, tx := range self { - // Cast it to a string (safe) - enc[i] = tx.RlpData() - } - - return enc -} -func (s Transactions) Len() int { return len(s) } -func (s Transactions) Swap(i, j int) { s[i], s[j] = s[j], s[i] } -func (s Transactions) GetRlp(i int) []byte { return ethutil.Rlp(s[i]) } - -type TxByNonce struct{ Transactions } - -func (s TxByNonce) Less(i, j int) bool { - return s.Transactions[i].Nonce < s.Transactions[j].Nonce -} diff --git a/chain/transaction_pool.go b/chain/transaction_pool.go index ff75089d6..119712ba8 100644 --- a/chain/transaction_pool.go +++ b/chain/transaction_pool.go @@ -7,6 +7,7 @@ import ( "math/big" "sync" + "github.com/ethereum/go-ethereum/chain/types" "github.com/ethereum/go-ethereum/logger" "github.com/ethereum/go-ethereum/state" "github.com/ethereum/go-ethereum/wire" @@ -16,7 +17,7 @@ var txplogger = logger.NewLogger("TXP") const txPoolQueueSize = 50 -type TxPoolHook chan *Transaction +type TxPoolHook chan *types.Transaction type TxMsgTy byte const ( @@ -26,21 +27,21 @@ const ( var MinGasPrice = big.NewInt(10000000000000) type TxMsg struct { - Tx *Transaction + Tx *types.Transaction Type TxMsgTy } -func EachTx(pool *list.List, it func(*Transaction, *list.Element) bool) { +func EachTx(pool *list.List, it func(*types.Transaction, *list.Element) bool) { for e := pool.Front(); e != nil; e = e.Next() { - if it(e.Value.(*Transaction), e) { + if it(e.Value.(*types.Transaction), e) { break } } } -func FindTx(pool *list.List, finder func(*Transaction, *list.Element) bool) *Transaction { +func FindTx(pool *list.List, finder func(*types.Transaction, *list.Element) bool) *types.Transaction { for e := pool.Front(); e != nil; e = e.Next() { - if tx, ok := e.Value.(*Transaction); ok { + if tx, ok := e.Value.(*types.Transaction); ok { if finder(tx, e) { return tx } @@ -51,7 +52,7 @@ func FindTx(pool *list.List, finder func(*Transaction, *list.Element) bool) *Tra } type TxProcessor interface { - ProcessTransaction(tx *Transaction) + ProcessTransaction(tx *types.Transaction) } // The tx pool a thread safe transaction pool handler. In order to @@ -65,7 +66,7 @@ type TxPool struct { mutex sync.Mutex // Queueing channel for reading and writing incoming // transactions to - queueChan chan *Transaction + queueChan chan *types.Transaction // Quiting channel quit chan bool // The actual pool @@ -79,14 +80,14 @@ type TxPool struct { func NewTxPool(ethereum EthManager) *TxPool { return &TxPool{ pool: list.New(), - queueChan: make(chan *Transaction, txPoolQueueSize), + queueChan: make(chan *types.Transaction, txPoolQueueSize), quit: make(chan bool), Ethereum: ethereum, } } // Blocking function. Don't use directly. Use QueueTransaction instead -func (pool *TxPool) addTransaction(tx *Transaction) { +func (pool *TxPool) addTransaction(tx *types.Transaction) { pool.mutex.Lock() defer pool.mutex.Unlock() @@ -96,7 +97,7 @@ func (pool *TxPool) addTransaction(tx *Transaction) { pool.Ethereum.Broadcast(wire.MsgTxTy, []interface{}{tx.RlpData()}) } -func (pool *TxPool) ValidateTransaction(tx *Transaction) error { +func (pool *TxPool) ValidateTransaction(tx *types.Transaction) error { // Get the last block so we can retrieve the sender and receiver from // the merkle trie block := pool.Ethereum.ChainManager().CurrentBlock @@ -142,7 +143,7 @@ out: select { case tx := <-pool.queueChan: hash := tx.Hash() - foundTx := FindTx(pool.pool, func(tx *Transaction, e *list.Element) bool { + foundTx := FindTx(pool.pool, func(tx *types.Transaction, e *list.Element) bool { return bytes.Compare(tx.Hash(), hash) == 0 }) @@ -172,18 +173,18 @@ out: } } -func (pool *TxPool) QueueTransaction(tx *Transaction) { +func (pool *TxPool) QueueTransaction(tx *types.Transaction) { pool.queueChan <- tx } -func (pool *TxPool) CurrentTransactions() []*Transaction { +func (pool *TxPool) CurrentTransactions() []*types.Transaction { pool.mutex.Lock() defer pool.mutex.Unlock() - txList := make([]*Transaction, pool.pool.Len()) + txList := make([]*types.Transaction, pool.pool.Len()) i := 0 for e := pool.pool.Front(); e != nil; e = e.Next() { - tx := e.Value.(*Transaction) + tx := e.Value.(*types.Transaction) txList[i] = tx @@ -198,7 +199,7 @@ func (pool *TxPool) RemoveInvalid(state *state.State) { defer pool.mutex.Unlock() for e := pool.pool.Front(); e != nil; e = e.Next() { - tx := e.Value.(*Transaction) + tx := e.Value.(*types.Transaction) sender := state.GetAccount(tx.Sender()) err := pool.ValidateTransaction(tx) if err != nil || sender.Nonce >= tx.Nonce { @@ -207,12 +208,12 @@ func (pool *TxPool) RemoveInvalid(state *state.State) { } } -func (self *TxPool) RemoveSet(txs Transactions) { +func (self *TxPool) RemoveSet(txs types.Transactions) { self.mutex.Lock() defer self.mutex.Unlock() for _, tx := range txs { - EachTx(self.pool, func(t *Transaction, element *list.Element) bool { + EachTx(self.pool, func(t *types.Transaction, element *list.Element) bool { if t == tx { self.pool.Remove(element) return true // To stop the loop @@ -222,7 +223,7 @@ func (self *TxPool) RemoveSet(txs Transactions) { } } -func (pool *TxPool) Flush() []*Transaction { +func (pool *TxPool) Flush() []*types.Transaction { txList := pool.CurrentTransactions() // Recreate a new list all together diff --git a/chain/transaction_test.go b/chain/transaction_test.go deleted file mode 100644 index fef1d2010..000000000 --- a/chain/transaction_test.go +++ /dev/null @@ -1 +0,0 @@ -package chain diff --git a/chain/types/block.go b/chain/types/block.go new file mode 100644 index 000000000..b311433e3 --- /dev/null +++ b/chain/types/block.go @@ -0,0 +1,419 @@ +package types + +import ( + "bytes" + "fmt" + "math/big" + "sort" + "time" + + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/ethutil" + "github.com/ethereum/go-ethereum/state" + "github.com/ethereum/go-ethereum/trie" +) + +type BlockInfo struct { + Number uint64 + Hash []byte + Parent []byte + TD *big.Int +} + +func (bi *BlockInfo) RlpDecode(data []byte) { + decoder := ethutil.NewValueFromBytes(data) + + bi.Number = decoder.Get(0).Uint() + bi.Hash = decoder.Get(1).Bytes() + bi.Parent = decoder.Get(2).Bytes() + bi.TD = decoder.Get(3).BigInt() +} + +func (bi *BlockInfo) RlpEncode() []byte { + return ethutil.Encode([]interface{}{bi.Number, bi.Hash, bi.Parent, bi.TD}) +} + +type Blocks []*Block + +func (self Blocks) AsSet() ethutil.UniqueSet { + set := make(ethutil.UniqueSet) + for _, block := range self { + set.Insert(block.Hash()) + } + + return set +} + +type BlockBy func(b1, b2 *Block) bool + +func (self BlockBy) Sort(blocks Blocks) { + bs := blockSorter{ + blocks: blocks, + by: self, + } + sort.Sort(bs) +} + +type blockSorter struct { + blocks Blocks + by func(b1, b2 *Block) bool +} + +func (self blockSorter) Len() int { return len(self.blocks) } +func (self blockSorter) Swap(i, j int) { + self.blocks[i], self.blocks[j] = self.blocks[j], self.blocks[i] +} +func (self blockSorter) Less(i, j int) bool { return self.by(self.blocks[i], self.blocks[j]) } + +func Number(b1, b2 *Block) bool { return b1.Number.Cmp(b2.Number) < 0 } + +type Block struct { + // Hash to the previous block + PrevHash ethutil.Bytes + // Uncles of this block + Uncles Blocks + UncleSha []byte + // The coin base address + Coinbase []byte + // Block Trie state + //state *ethutil.Trie + state *state.State + // Difficulty for the current block + Difficulty *big.Int + // Creation time + Time int64 + // The block number + Number *big.Int + // Minimum Gas Price + MinGasPrice *big.Int + // Gas limit + GasLimit *big.Int + // Gas used + GasUsed *big.Int + // Extra data + Extra string + // Block Nonce for verification + Nonce ethutil.Bytes + // List of transactions and/or contracts + transactions Transactions + receipts Receipts + TxSha, ReceiptSha []byte + LogsBloom []byte +} + +func NewBlockFromBytes(raw []byte) *Block { + block := &Block{} + block.RlpDecode(raw) + + return block +} + +// New block takes a raw encoded string +func NewBlockFromRlpValue(rlpValue *ethutil.Value) *Block { + block := &Block{} + block.RlpValueDecode(rlpValue) + + return block +} + +func CreateBlock(root interface{}, + prevHash []byte, + base []byte, + Difficulty *big.Int, + Nonce []byte, + extra string) *Block { + + block := &Block{ + PrevHash: prevHash, + Coinbase: base, + Difficulty: Difficulty, + Nonce: Nonce, + Time: time.Now().Unix(), + Extra: extra, + UncleSha: nil, + GasUsed: new(big.Int), + MinGasPrice: new(big.Int), + GasLimit: new(big.Int), + } + block.SetUncles([]*Block{}) + + block.state = state.New(trie.New(ethutil.Config.Db, root)) + + return block +} + +// Returns a hash of the block +func (block *Block) Hash() ethutil.Bytes { + return crypto.Sha3(ethutil.NewValue(block.header()).Encode()) + //return crypto.Sha3(block.Value().Encode()) +} + +func (block *Block) HashNoNonce() []byte { + return crypto.Sha3(ethutil.Encode(block.miningHeader())) +} + +func (block *Block) State() *state.State { + return block.state +} + +func (block *Block) Transactions() Transactions { + return block.transactions +} + +func (block *Block) CalcGasLimit(parent *Block) *big.Int { + if block.Number.Cmp(big.NewInt(0)) == 0 { + return ethutil.BigPow(10, 6) + } + + // ((1024-1) * parent.gasLimit + (gasUsed * 6 / 5)) / 1024 + + previous := new(big.Int).Mul(big.NewInt(1024-1), parent.GasLimit) + current := new(big.Rat).Mul(new(big.Rat).SetInt(parent.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 := big.NewInt(125000) + + return ethutil.BigMax(min, result) +} + +func (block *Block) BlockInfo() BlockInfo { + bi := BlockInfo{} + data, _ := ethutil.Config.Db.Get(append(block.Hash(), []byte("Info")...)) + bi.RlpDecode(data) + + return bi +} + +func (self *Block) GetTransaction(hash []byte) *Transaction { + for _, tx := range self.transactions { + if bytes.Compare(tx.Hash(), hash) == 0 { + return tx + } + } + + return nil +} + +// Sync the block's state and contract respectively +func (block *Block) Sync() { + block.state.Sync() +} + +func (block *Block) Undo() { + // Sync the block state itself + block.state.Reset() +} + +/////// Block Encoding +func (block *Block) rlpReceipts() interface{} { + // Marshal the transactions of this block + encR := make([]interface{}, len(block.receipts)) + for i, r := range block.receipts { + // Cast it to a string (safe) + encR[i] = r.RlpData() + } + + return encR +} + +func (block *Block) rlpUncles() interface{} { + // Marshal the transactions of this block + uncles := make([]interface{}, len(block.Uncles)) + for i, uncle := range block.Uncles { + // Cast it to a string (safe) + uncles[i] = uncle.header() + } + + return uncles +} + +func (block *Block) SetUncles(uncles []*Block) { + block.Uncles = uncles + block.UncleSha = crypto.Sha3(ethutil.Encode(block.rlpUncles())) +} + +func (self *Block) SetReceipts(receipts Receipts) { + self.receipts = receipts + self.ReceiptSha = DeriveSha(receipts) + self.LogsBloom = CreateBloom(receipts) +} + +func (self *Block) SetTransactions(txs Transactions) { + self.transactions = txs + self.TxSha = DeriveSha(txs) +} + +func (block *Block) Value() *ethutil.Value { + return ethutil.NewValue([]interface{}{block.header(), block.transactions, block.rlpUncles()}) +} + +func (block *Block) RlpEncode() []byte { + // Encode a slice interface which contains the header and the list of + // transactions. + return block.Value().Encode() +} + +func (block *Block) RlpDecode(data []byte) { + rlpValue := ethutil.NewValueFromBytes(data) + block.RlpValueDecode(rlpValue) +} + +func (block *Block) RlpValueDecode(decoder *ethutil.Value) { + block.setHeader(decoder.Get(0)) + + // Tx list might be empty if this is an uncle. Uncles only have their + // header set. + if decoder.Get(1).IsNil() == false { // Yes explicitness + //receipts := decoder.Get(1) + //block.receipts = make([]*Receipt, receipts.Len()) + txs := decoder.Get(1) + block.transactions = make(Transactions, txs.Len()) + for i := 0; i < txs.Len(); i++ { + block.transactions[i] = NewTransactionFromValue(txs.Get(i)) + //receipt := NewRecieptFromValue(receipts.Get(i)) + //block.transactions[i] = receipt.Tx + //block.receipts[i] = receipt + } + + } + + if decoder.Get(2).IsNil() == false { // Yes explicitness + uncles := decoder.Get(2) + block.Uncles = make([]*Block, uncles.Len()) + for i := 0; i < uncles.Len(); i++ { + block.Uncles[i] = NewUncleBlockFromValue(uncles.Get(i)) + } + } + +} + +func (self *Block) setHeader(header *ethutil.Value) { + self.PrevHash = header.Get(0).Bytes() + self.UncleSha = header.Get(1).Bytes() + self.Coinbase = header.Get(2).Bytes() + self.state = state.New(trie.New(ethutil.Config.Db, header.Get(3).Val)) + self.TxSha = header.Get(4).Bytes() + self.ReceiptSha = header.Get(5).Bytes() + self.LogsBloom = header.Get(6).Bytes() + self.Difficulty = header.Get(7).BigInt() + self.Number = header.Get(8).BigInt() + self.MinGasPrice = header.Get(9).BigInt() + self.GasLimit = header.Get(10).BigInt() + self.GasUsed = header.Get(11).BigInt() + self.Time = int64(header.Get(12).BigInt().Uint64()) + self.Extra = header.Get(13).Str() + self.Nonce = header.Get(14).Bytes() +} + +func NewUncleBlockFromValue(header *ethutil.Value) *Block { + block := &Block{} + block.setHeader(header) + + return block +} + +func (block *Block) Trie() *trie.Trie { + return block.state.Trie +} + +func (block *Block) Root() interface{} { + return block.state.Root() +} + +func (block *Block) Diff() *big.Int { + return block.Difficulty +} + +func (self *Block) Receipts() []*Receipt { + return self.receipts +} + +func (block *Block) miningHeader() []interface{} { + return []interface{}{ + // Sha of the previous block + block.PrevHash, + // Sha of uncles + block.UncleSha, + // Coinbase address + block.Coinbase, + // root state + block.Root(), + // tx root + block.TxSha, + // Sha of tx + block.ReceiptSha, + // Bloom + block.LogsBloom, + // Current block Difficulty + block.Difficulty, + // The block number + block.Number, + // Block minimum gas price + block.MinGasPrice, + // Block upper gas bound + block.GasLimit, + // Block gas used + block.GasUsed, + // Time the block was found? + block.Time, + // Extra data + block.Extra, + } +} + +func (block *Block) header() []interface{} { + return append(block.miningHeader(), block.Nonce) +} + +func (block *Block) String() string { + return fmt.Sprintf(` + BLOCK(%x): Size: %v + PrevHash: %x + UncleSha: %x + Coinbase: %x + Root: %x + TxSha %x + ReceiptSha: %x + Bloom: %x + Difficulty: %v + Number: %v + MinGas: %v + MaxLimit: %v + GasUsed: %v + Time: %v + Extra: %v + Nonce: %x + NumTx: %v +`, + block.Hash(), + block.Size(), + block.PrevHash, + block.UncleSha, + block.Coinbase, + block.Root(), + block.TxSha, + block.ReceiptSha, + block.LogsBloom, + block.Difficulty, + block.Number, + block.MinGasPrice, + block.GasLimit, + block.GasUsed, + block.Time, + block.Extra, + block.Nonce, + len(block.transactions), + ) +} + +func (self *Block) Size() ethutil.StorageSize { + return ethutil.StorageSize(len(self.RlpEncode())) +} + +// Implement RlpEncodable +func (self *Block) RlpData() interface{} { + return self.Value().Val +} diff --git a/chain/types/bloom9.go b/chain/types/bloom9.go new file mode 100644 index 000000000..626711cca --- /dev/null +++ b/chain/types/bloom9.go @@ -0,0 +1,56 @@ +package types + +import ( + "math/big" + + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/ethutil" + "github.com/ethereum/go-ethereum/state" +) + +func CreateBloom(receipts Receipts) []byte { + bin := new(big.Int) + for _, receipt := range receipts { + bin.Or(bin, logsBloom(receipt.logs)) + } + + return ethutil.LeftPadBytes(bin.Bytes(), 64) +} + +func logsBloom(logs state.Logs) *big.Int { + bin := new(big.Int) + for _, log := range logs { + data := [][]byte{log.Address} + for _, topic := range log.Topics { + data = append(data, topic) + } + + for _, b := range data { + bin.Or(bin, ethutil.BigD(bloom9(crypto.Sha3(b)).Bytes())) + } + + //if log.Data != nil { + // data = append(data, log.Data) + //} + } + + return bin +} + +func bloom9(b []byte) *big.Int { + r := new(big.Int) + for _, i := range []int{0, 2, 4} { + t := big.NewInt(1) + b := uint(b[i+1]) + 256*(uint(b[i])&1) + r.Or(r, t.Lsh(t, b)) + } + + return r +} + +func BloomLookup(bin, topic []byte) bool { + bloom := ethutil.BigD(bin) + cmp := bloom9(crypto.Sha3(topic)) + + return bloom.And(bloom, cmp).Cmp(cmp) == 0 +} diff --git a/chain/types/bloom9_test.go b/chain/types/bloom9_test.go new file mode 100644 index 000000000..8ee63becb --- /dev/null +++ b/chain/types/bloom9_test.go @@ -0,0 +1,30 @@ +package types + +import ( + "testing" + + "github.com/ethereum/go-ethereum/state" +) + +func TestBloom9(t *testing.T) { + testCase := []byte("testtest") + bin := LogsBloom([]state.Log{ + {testCase, [][]byte{[]byte("hellohello")}, nil}, + }).Bytes() + res := BloomLookup(bin, testCase) + + if !res { + t.Errorf("Bloom lookup failed") + } +} + +/* +func TestAddress(t *testing.T) { + block := &Block{} + block.Coinbase = ethutil.Hex2Bytes("22341ae42d6dd7384bc8584e50419ea3ac75b83f") + fmt.Printf("%x\n", crypto.Sha3(block.Coinbase)) + + bin := CreateBloom(block) + fmt.Printf("bin = %x\n", ethutil.LeftPadBytes(bin, 64)) +} +*/ diff --git a/chain/types/common.go b/chain/types/common.go new file mode 100644 index 000000000..ae0e7c3fa --- /dev/null +++ b/chain/types/common.go @@ -0,0 +1,10 @@ +package types + +import ( + "math/big" + "github.com/ethereum/go-ethereum/state" +) + +type BlockProcessor interface { + ProcessWithParent(*Block, *Block) (*big.Int, state.Messages, error) +} diff --git a/chain/types/derive_sha.go b/chain/types/derive_sha.go new file mode 100644 index 000000000..1897ff198 --- /dev/null +++ b/chain/types/derive_sha.go @@ -0,0 +1,20 @@ +package types + +import ( + "github.com/ethereum/go-ethereum/ethutil" + "github.com/ethereum/go-ethereum/trie" +) + +type DerivableList interface { + Len() int + GetRlp(i int) []byte +} + +func DeriveSha(list DerivableList) []byte { + trie := trie.New(ethutil.Config.Db, "") + for i := 0; i < list.Len(); i++ { + trie.Update(string(ethutil.NewValue(i).Encode()), string(list.GetRlp(i))) + } + + return trie.GetRoot() +} diff --git a/chain/types/receipt.go b/chain/types/receipt.go new file mode 100644 index 000000000..25fa8fb07 --- /dev/null +++ b/chain/types/receipt.go @@ -0,0 +1,68 @@ +package types + +import ( + "bytes" + "fmt" + "math/big" + + "github.com/ethereum/go-ethereum/ethutil" + "github.com/ethereum/go-ethereum/state" +) + +type Receipt struct { + PostState []byte + CumulativeGasUsed *big.Int + Bloom []byte + logs state.Logs +} + +func NewReceipt(root []byte, cumalativeGasUsed *big.Int) *Receipt { + return &Receipt{PostState: ethutil.CopyBytes(root), CumulativeGasUsed: cumalativeGasUsed} +} + +func NewRecieptFromValue(val *ethutil.Value) *Receipt { + r := &Receipt{} + r.RlpValueDecode(val) + + return r +} + +func (self *Receipt) SetLogs(logs state.Logs) { + self.logs = logs +} + +func (self *Receipt) RlpValueDecode(decoder *ethutil.Value) { + self.PostState = decoder.Get(0).Bytes() + self.CumulativeGasUsed = decoder.Get(1).BigInt() + self.Bloom = decoder.Get(2).Bytes() + + it := decoder.Get(3).NewIterator() + for it.Next() { + self.logs = append(self.logs, state.NewLogFromValue(it.Value())) + } +} + +func (self *Receipt) RlpData() interface{} { + return []interface{}{self.PostState, self.CumulativeGasUsed, self.Bloom, self.logs.RlpData()} +} + +func (self *Receipt) RlpEncode() []byte { + return ethutil.Encode(self.RlpData()) +} + +func (self *Receipt) Cmp(other *Receipt) bool { + if bytes.Compare(self.PostState, other.PostState) != 0 { + return false + } + + return true +} + +func (self *Receipt) String() string { + return fmt.Sprintf("receipt{med=%x cgas=%v bloom=%x logs=%v}", self.PostState, self.CumulativeGasUsed, self.Bloom, self.logs) +} + +type Receipts []*Receipt + +func (self Receipts) Len() int { return len(self) } +func (self Receipts) GetRlp(i int) []byte { return ethutil.Rlp(self[i]) } diff --git a/chain/types/transaction.go b/chain/types/transaction.go new file mode 100644 index 000000000..626a7e5ce --- /dev/null +++ b/chain/types/transaction.go @@ -0,0 +1,224 @@ +package types + +import ( + "fmt" + "math/big" + + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/ethutil" + "github.com/ethereum/go-ethereum/state" + "github.com/obscuren/secp256k1-go" +) + +var ContractAddr = []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} + +func IsContractAddr(addr []byte) bool { + return len(addr) == 0 + //return bytes.Compare(addr, ContractAddr) == 0 +} + +type Transaction struct { + Nonce uint64 + Recipient []byte + Value *big.Int + Gas *big.Int + GasPrice *big.Int + Data []byte + v byte + r, s []byte + + // Indicates whether this tx is a contract creation transaction + contractCreation bool +} + +func NewContractCreationTx(value, gas, gasPrice *big.Int, script []byte) *Transaction { + return &Transaction{Recipient: nil, Value: value, Gas: gas, GasPrice: gasPrice, Data: script, contractCreation: true} +} + +func NewTransactionMessage(to []byte, value, gas, gasPrice *big.Int, data []byte) *Transaction { + return &Transaction{Recipient: to, Value: value, GasPrice: gasPrice, Gas: gas, Data: data, contractCreation: IsContractAddr(to)} +} + +func NewTransactionFromBytes(data []byte) *Transaction { + tx := &Transaction{} + tx.RlpDecode(data) + + return tx +} + +func NewTransactionFromValue(val *ethutil.Value) *Transaction { + tx := &Transaction{} + tx.RlpValueDecode(val) + + 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} + + return crypto.Sha3(ethutil.NewValue(data).Encode()) +} + +func (tx *Transaction) CreatesContract() bool { + return tx.contractCreation +} + +/* Deprecated */ +func (tx *Transaction) IsContract() bool { + return tx.CreatesContract() +} + +func (tx *Transaction) CreationAddress(state *state.State) []byte { + // Generate a new address + addr := crypto.Sha3(ethutil.NewValue([]interface{}{tx.Sender(), tx.Nonce}).Encode())[12:] + //for i := uint64(0); state.GetStateObject(addr) != nil; i++ { + // addr = crypto.Sha3(ethutil.NewValue([]interface{}{tx.Sender(), tx.Nonce + i}).Encode())[12:] + //} + + return addr +} + +func (tx *Transaction) Signature(key []byte) []byte { + hash := tx.Hash() + + sig, _ := secp256k1.Sign(hash, key) + + return sig +} + +func (tx *Transaction) PublicKey() []byte { + hash := tx.Hash() + + // TODO + r := ethutil.LeftPadBytes(tx.r, 32) + s := ethutil.LeftPadBytes(tx.s, 32) + + sig := append(r, s...) + sig = append(sig, tx.v-27) + + pubkey := crypto.Ecrecover(append(hash, sig...)) + //pubkey, _ := secp256k1.RecoverPubkey(hash, sig) + + return pubkey +} + +func (tx *Transaction) Sender() []byte { + pubkey := tx.PublicKey() + + // Validate the returned key. + // Return nil if public key isn't in full format + if len(pubkey) != 0 && pubkey[0] != 4 { + return nil + } + + return crypto.Sha3(pubkey[1:])[12:] +} + +func (tx *Transaction) Sign(privk []byte) error { + + sig := tx.Signature(privk) + + tx.r = sig[:32] + tx.s = sig[32:64] + tx.v = sig[64] + 27 + + return nil +} + +func (tx *Transaction) RlpData() interface{} { + data := []interface{}{tx.Nonce, tx.GasPrice, tx.Gas, tx.Recipient, tx.Value, tx.Data} + + // TODO Remove prefixing zero's + + return append(data, tx.v, new(big.Int).SetBytes(tx.r).Bytes(), new(big.Int).SetBytes(tx.s).Bytes()) +} + +func (tx *Transaction) RlpValue() *ethutil.Value { + return ethutil.NewValue(tx.RlpData()) +} + +func (tx *Transaction) RlpEncode() []byte { + return tx.RlpValue().Encode() +} + +func (tx *Transaction) RlpDecode(data []byte) { + tx.RlpValueDecode(ethutil.NewValueFromBytes(data)) +} + +func (tx *Transaction) RlpValueDecode(decoder *ethutil.Value) { + tx.Nonce = decoder.Get(0).Uint() + tx.GasPrice = decoder.Get(1).BigInt() + tx.Gas = decoder.Get(2).BigInt() + tx.Recipient = decoder.Get(3).Bytes() + tx.Value = decoder.Get(4).BigInt() + tx.Data = decoder.Get(5).Bytes() + tx.v = byte(decoder.Get(6).Uint()) + + tx.r = decoder.Get(7).Bytes() + tx.s = decoder.Get(8).Bytes() + + if IsContractAddr(tx.Recipient) { + tx.contractCreation = true + } +} + +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) +} + +// Transaction slice type for basic sorting +type Transactions []*Transaction + +func (self Transactions) RlpData() interface{} { + // Marshal the transactions of this block + enc := make([]interface{}, len(self)) + for i, tx := range self { + // Cast it to a string (safe) + enc[i] = tx.RlpData() + } + + return enc +} +func (s Transactions) Len() int { return len(s) } +func (s Transactions) Swap(i, j int) { s[i], s[j] = s[j], s[i] } +func (s Transactions) GetRlp(i int) []byte { return ethutil.Rlp(s[i]) } + +type TxByNonce struct{ Transactions } + +func (s TxByNonce) Less(i, j int) bool { + return s.Transactions[i].Nonce < s.Transactions[j].Nonce +} diff --git a/chain/types/transaction_test.go b/chain/types/transaction_test.go new file mode 100644 index 000000000..ab1254f4c --- /dev/null +++ b/chain/types/transaction_test.go @@ -0,0 +1 @@ +package types diff --git a/chain/vm_env.go b/chain/vm_env.go index 4f3dc3ca4..c1911ff51 100644 --- a/chain/vm_env.go +++ b/chain/vm_env.go @@ -3,17 +3,18 @@ package chain import ( "math/big" + "github.com/ethereum/go-ethereum/chain/types" "github.com/ethereum/go-ethereum/state" "github.com/ethereum/go-ethereum/vm" ) type VMEnv struct { state *state.State - block *Block - tx *Transaction + block *types.Block + tx *types.Transaction } -func NewEnv(state *state.State, tx *Transaction, block *Block) *VMEnv { +func NewEnv(state *state.State, tx *types.Transaction, block *types.Block) *VMEnv { return &VMEnv{ state: state, block: block, -- cgit v1.2.3 From f8d0cd9906a1ec4a4a1e95868a279312363f8b49 Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 18 Nov 2014 19:44:17 +0100 Subject: Added a callback mechanism to chain adding. Not sure if this is the right approach. Why? BlockChain shouldn't need the "Ethereum" object. BlockChain shouldn't need to worry about notifying listeners or message propagation. --- chain/chain_manager.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'chain') diff --git a/chain/chain_manager.go b/chain/chain_manager.go index 11df4e17e..970fa5377 100644 --- a/chain/chain_manager.go +++ b/chain/chain_manager.go @@ -271,14 +271,14 @@ func (self *ChainManager) NewIterator(startHash []byte) *ChainIterator { } // This function assumes you've done your checking. No checking is done at this stage anymore -func (self *ChainManager) InsertChain(chain *BlockChain) { +func (self *ChainManager) InsertChain(chain *BlockChain, call func(*types.Block, state.Messages)) { for e := chain.Front(); e != nil; e = e.Next() { link := e.Value.(*link) self.add(link.block) self.SetTotalDifficulty(link.td) - //self.eth.EventMux().Post(NewBlockEvent{link.block}) - //self.eth.EventMux().Post(link.messages) + + call(link.block, link.messages) } b, e := chain.Front(), chain.Back() -- cgit v1.2.3 From 93e693be72e1a7734e826016316434c1e2320de9 Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 18 Nov 2014 19:52:45 +0100 Subject: Fixed tests for 'types' --- chain/helper_test.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'chain') diff --git a/chain/helper_test.go b/chain/helper_test.go index 459e3e63a..8c7532111 100644 --- a/chain/helper_test.go +++ b/chain/helper_test.go @@ -4,6 +4,7 @@ import ( "container/list" "fmt" + "github.com/ethereum/go-ethereum/chain/types" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/ethutil" @@ -19,7 +20,7 @@ type TestManager struct { db ethutil.Database txPool *TxPool blockChain *ChainManager - Blocks []*Block + Blocks []*types.Block } func (s *TestManager) IsListening() bool { -- cgit v1.2.3 From 14e2e488fdf0f4d6ed1a5a48ffbbe883faa7edb6 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 19 Nov 2014 12:25:52 +0100 Subject: Added `chain` tests & minor fixes * Fork tests (equal and larger chains) * `chain.link` fields are now exported * moved debug function from state to dump.go --- chain/chain_manager.go | 26 +++++----- chain/chain_manager_test.go | 115 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 128 insertions(+), 13 deletions(-) (limited to 'chain') diff --git a/chain/chain_manager.go b/chain/chain_manager.go index 970fa5377..11e16fa7d 100644 --- a/chain/chain_manager.go +++ b/chain/chain_manager.go @@ -191,8 +191,8 @@ func (self *ChainManager) GetBlock(hash []byte) *types.Block { if self.workingChain != nil { // Check the temp chain for e := self.workingChain.Front(); e != nil; e = e.Next() { - if bytes.Compare(e.Value.(*link).block.Hash(), hash) == 0 { - return e.Value.(*link).block + if bytes.Compare(e.Value.(*link).Block.Hash(), hash) == 0 { + return e.Value.(*link).Block } } } @@ -275,15 +275,15 @@ func (self *ChainManager) InsertChain(chain *BlockChain, call func(*types.Block, for e := chain.Front(); e != nil; e = e.Next() { link := e.Value.(*link) - self.add(link.block) - self.SetTotalDifficulty(link.td) + self.add(link.Block) + self.SetTotalDifficulty(link.Td) - call(link.block, link.messages) + call(link.Block, link.Messages) } b, e := chain.Front(), chain.Back() if b != nil && e != nil { - front, back := b.Value.(*link).block, e.Value.(*link).block + front, back := b.Value.(*link).Block, e.Value.(*link).Block chainlogger.Infof("Imported %d blocks. #%v (%x) / %#v (%x)", chain.Len(), front.Number, front.Hash()[0:4], back.Number, back.Hash()[0:4]) } } @@ -295,7 +295,7 @@ func (self *ChainManager) TestChain(chain *BlockChain) (td *big.Int, err error) for e := chain.Front(); e != nil; e = e.Next() { var ( l = e.Value.(*link) - block = l.block + block = l.Block parent = self.GetBlock(block.PrevHash) ) @@ -314,8 +314,8 @@ func (self *ChainManager) TestChain(chain *BlockChain) (td *big.Int, err error) err = fmt.Errorf("incoming chain failed %v\n", err) return } - l.td = td - l.messages = messages + l.Td = td + l.Messages = messages } if td.Cmp(self.TD) <= 0 { @@ -329,9 +329,9 @@ func (self *ChainManager) TestChain(chain *BlockChain) (td *big.Int, err error) } type link struct { - block *types.Block - messages state.Messages - td *big.Int + Block *types.Block + Messages state.Messages + Td *big.Int } type BlockChain struct { @@ -351,7 +351,7 @@ func NewChain(blocks types.Blocks) *BlockChain { func (self *BlockChain) RlpEncode() []byte { dat := make([]interface{}, 0) for e := self.Front(); e != nil; e = e.Next() { - dat = append(dat, e.Value.(*link).block.RlpData()) + dat = append(dat, e.Value.(*link).Block.RlpData()) } return ethutil.Encode(dat) diff --git a/chain/chain_manager_test.go b/chain/chain_manager_test.go index fef1d2010..0314914a9 100644 --- a/chain/chain_manager_test.go +++ b/chain/chain_manager_test.go @@ -1 +1,116 @@ package chain + +import ( + "fmt" + "math/big" + "testing" + "time" + + "github.com/ethereum/go-ethereum/chain/types" + "github.com/ethereum/go-ethereum/ethdb" + "github.com/ethereum/go-ethereum/ethutil" + "github.com/ethereum/go-ethereum/state" +) + +var TD *big.Int + +func init() { + ethutil.ReadConfig(".ethtest", "/tmp/ethtest", "") + ethutil.Config.Db, _ = ethdb.NewMemDatabase() +} + +type fakeproc struct { +} + +func (self fakeproc) ProcessWithParent(a, b *types.Block) (*big.Int, state.Messages, error) { + TD = new(big.Int).Add(TD, big.NewInt(1)) + return TD, nil, nil +} + +func makechain(cman *ChainManager, max int) *BlockChain { + blocks := make(types.Blocks, max) + for i := 0; i < max; i++ { + addr := ethutil.LeftPadBytes([]byte{byte(i)}, 20) + block := cman.NewBlock(addr) + if i != 0 { + cman.CurrentBlock = blocks[i-1] + } + blocks[i] = block + } + return NewChain(blocks) +} + +func TestLongerFork(t *testing.T) { + cman := NewChainManager() + cman.SetProcessor(fakeproc{}) + + TD = big.NewInt(1) + chainA := makechain(cman, 5) + + TD = big.NewInt(1) + chainB := makechain(cman, 10) + + td, err := cman.TestChain(chainA) + if err != nil { + t.Error("unable to create new TD from chainA:", err) + } + cman.TD = td + + _, err = cman.TestChain(chainB) + if err != nil { + t.Error("expected chainB not to give errors:", err) + } +} + +func TestEqualFork(t *testing.T) { + cman := NewChainManager() + cman.SetProcessor(fakeproc{}) + + TD = big.NewInt(1) + chainA := makechain(cman, 5) + + TD = big.NewInt(2) + chainB := makechain(cman, 5) + + td, err := cman.TestChain(chainA) + if err != nil { + t.Error("unable to create new TD from chainA:", err) + } + cman.TD = td + + _, err = cman.TestChain(chainB) + if err != nil { + t.Error("expected chainB not to give errors:", err) + } +} + +func TestBrokenChain(t *testing.T) { + cman := NewChainManager() + cman.SetProcessor(fakeproc{}) + + TD = big.NewInt(1) + chain := makechain(cman, 5) + chain.Remove(chain.Front()) + + _, err := cman.TestChain(chain) + if err == nil { + t.Error("expected broken chain to return error") + } +} + +func BenchmarkChainTesting(b *testing.B) { + const chainlen = 1000 + + ethutil.ReadConfig(".ethtest", "/tmp/ethtest", "") + ethutil.Config.Db, _ = ethdb.NewMemDatabase() + + cman := NewChainManager() + cman.SetProcessor(fakeproc{}) + + TD = big.NewInt(1) + chain := makechain(cman, chainlen) + + stime := time.Now() + cman.TestChain(chain) + fmt.Println(chainlen, "took", time.Since(stime)) +} -- cgit v1.2.3