aboutsummaryrefslogtreecommitdiffstats
path: root/core
diff options
context:
space:
mode:
Diffstat (limited to 'core')
-rw-r--r--core/block_processor.go100
-rw-r--r--core/block_processor_test.go34
-rw-r--r--core/chain_manager.go77
-rw-r--r--core/error.go23
-rw-r--r--core/events.go3
-rw-r--r--core/filter.go30
-rw-r--r--core/genesis.go44
-rw-r--r--core/helper_test.go8
-rw-r--r--core/manager.go4
-rw-r--r--core/state_transition.go9
-rw-r--r--core/transaction_pool.go35
-rw-r--r--core/types/block.go17
-rw-r--r--core/types/receipt.go2
13 files changed, 230 insertions, 156 deletions
diff --git a/core/block_processor.go b/core/block_processor.go
index 0eb3f8920..fd591a29d 100644
--- a/core/block_processor.go
+++ b/core/block_processor.go
@@ -48,8 +48,9 @@ type BlockProcessor struct {
func NewBlockProcessor(db ethutil.Database, txpool *TxPool, chainManager *ChainManager, eventMux *event.TypeMux) *BlockProcessor {
sm := &BlockProcessor{
- db: db,
- mem: make(map[string]*big.Int),
+ db: db,
+ mem: make(map[string]*big.Int),
+ //Pow: &ethash.Ethash{},
Pow: ezp.New(),
bc: chainManager,
eventMux: eventMux,
@@ -59,12 +60,12 @@ func NewBlockProcessor(db ethutil.Database, txpool *TxPool, chainManager *ChainM
return sm
}
-func (sm *BlockProcessor) TransitionState(statedb *state.StateDB, parent, block *types.Block) (receipts types.Receipts, err error) {
+func (sm *BlockProcessor) TransitionState(statedb *state.StateDB, parent, block *types.Block, transientProcess bool) (receipts types.Receipts, err error) {
coinbase := statedb.GetOrNewStateObject(block.Header().Coinbase)
coinbase.SetGasPool(CalcGasLimit(parent, block))
// Process the transactions on to parent state
- receipts, _, _, _, err = sm.ApplyTransactions(coinbase, statedb, block, block.Transactions(), false)
+ receipts, _, _, _, err = sm.ApplyTransactions(coinbase, statedb, block, block.Transactions(), transientProcess)
if err != nil {
return nil, err
}
@@ -72,38 +73,40 @@ func (sm *BlockProcessor) TransitionState(statedb *state.StateDB, parent, block
return receipts, nil
}
-func (self *BlockProcessor) ApplyTransaction(coinbase *state.StateObject, state *state.StateDB, block *types.Block, tx *types.Transaction, usedGas *big.Int, transientProcess bool) (*types.Receipt, *big.Int, error) {
+func (self *BlockProcessor) ApplyTransaction(coinbase *state.StateObject, statedb *state.StateDB, block *types.Block, tx *types.Transaction, usedGas *big.Int, transientProcess bool) (*types.Receipt, *big.Int, error) {
// If we are mining this block and validating we want to set the logs back to 0
- state.EmptyLogs()
+ statedb.EmptyLogs()
txGas := new(big.Int).Set(tx.Gas())
- cb := state.GetStateObject(coinbase.Address())
- st := NewStateTransition(NewEnv(state, self.bc, tx, block), tx, cb)
+ cb := statedb.GetStateObject(coinbase.Address())
+ st := NewStateTransition(NewEnv(statedb, self.bc, tx, block), tx, cb)
_, err := st.TransitionState()
+ if err != nil && (IsNonceErr(err) || state.IsGasLimitErr(err)) {
+ return nil, nil, err
+ }
txGas.Sub(txGas, st.gas)
// Update the state with pending changes
- state.Update(txGas)
+ statedb.Update(txGas)
cumulative := new(big.Int).Set(usedGas.Add(usedGas, txGas))
- receipt := types.NewReceipt(state.Root(), cumulative)
- receipt.SetLogs(state.Logs())
+ receipt := types.NewReceipt(statedb.Root(), cumulative)
+ receipt.SetLogs(statedb.Logs())
receipt.Bloom = types.CreateBloom(types.Receipts{receipt})
chainlogger.Debugln(receipt)
// Notify all subscribers
if !transientProcess {
go self.eventMux.Post(TxPostEvent{tx})
+ go self.eventMux.Post(statedb.Logs())
}
- go self.eventMux.Post(state.Logs())
-
return receipt, txGas, err
}
-func (self *BlockProcessor) ApplyTransactions(coinbase *state.StateObject, state *state.StateDB, block *types.Block, txs types.Transactions, transientProcess bool) (types.Receipts, types.Transactions, types.Transactions, types.Transactions, error) {
+func (self *BlockProcessor) ApplyTransactions(coinbase *state.StateObject, statedb *state.StateDB, block *types.Block, txs types.Transactions, transientProcess bool) (types.Receipts, types.Transactions, types.Transactions, types.Transactions, error) {
var (
receipts types.Receipts
handled, unhandled types.Transactions
@@ -114,12 +117,12 @@ func (self *BlockProcessor) ApplyTransactions(coinbase *state.StateObject, state
)
for _, tx := range txs {
- receipt, txGas, err := self.ApplyTransaction(coinbase, state, block, tx, totalUsedGas, transientProcess)
+ receipt, txGas, err := self.ApplyTransaction(coinbase, statedb, block, tx, totalUsedGas, transientProcess)
if err != nil {
switch {
case IsNonceErr(err):
return nil, nil, nil, nil, err
- case IsGasLimitErr(err):
+ case state.IsGasLimitErr(err):
return nil, nil, nil, nil, err
default:
statelogger.Infoln(err)
@@ -143,6 +146,9 @@ func (self *BlockProcessor) ApplyTransactions(coinbase *state.StateObject, state
return receipts, handled, unhandled, erroneous, err
}
+// Process block will attempt to process the given block's transactions and applies them
+// on top of the block's parent state (given it exists) and will return wether it was
+// successful or not.
func (sm *BlockProcessor) Process(block *types.Block) (td *big.Int, err error) {
// Processing a blocks may never happen simultaneously
sm.mutex.Lock()
@@ -158,39 +164,44 @@ func (sm *BlockProcessor) Process(block *types.Block) (td *big.Int, err error) {
}
parent := sm.bc.GetBlock(header.ParentHash)
- return sm.ProcessWithParent(block, parent)
+ return sm.processWithParent(block, parent)
}
-func (sm *BlockProcessor) ProcessWithParent(block, parent *types.Block) (td *big.Int, err error) {
+func (sm *BlockProcessor) processWithParent(block, parent *types.Block) (td *big.Int, err error) {
sm.lastAttemptedBlock = block
+ // Create a new state based on the parent's root (e.g., create copy)
state := state.New(parent.Root(), sm.db)
- //state := state.New(parent.Trie().Copy())
// Block validation
if err = sm.ValidateBlock(block, parent); err != nil {
return
}
- receipts, err := sm.TransitionState(state, parent, block)
+ receipts, err := sm.TransitionState(state, parent, block, false)
if err != nil {
return
}
header := block.Header()
+ // Validate the received block's bloom with the one derived from the generated receipts.
+ // For valid blocks this should always validate to true.
rbloom := types.CreateBloom(receipts)
if bytes.Compare(rbloom, header.Bloom) != 0 {
err = fmt.Errorf("unable to replicate block's bloom=%x", rbloom)
return
}
+ // The transactions Trie's root (R = (Tr [[H1, T1], [H2, T2], ... [Hn, Tn]]))
+ // can be used by light clients to make sure they've received the correct Txs
txSha := types.DeriveSha(block.Transactions())
if bytes.Compare(txSha, header.TxHash) != 0 {
err = fmt.Errorf("validating transaction root. received=%x got=%x", header.TxHash, txSha)
return
}
+ // Tre receipt Trie's root (R = (Tr [[H1, R1], ... [Hn, R1]]))
receiptSha := types.DeriveSha(receipts)
if bytes.Compare(receiptSha, header.ReceiptHash) != 0 {
fmt.Println("receipts", receipts)
@@ -198,12 +209,14 @@ func (sm *BlockProcessor) ProcessWithParent(block, parent *types.Block) (td *big
return
}
+ // Accumulate static rewards; block reward, uncle's and uncle inclusion.
if err = sm.AccumulateRewards(state, block, parent); err != nil {
return
}
+ // Commit state objects/accounts to a temporary trie (does not save)
+ // used to calculate the state root.
state.Update(ethutil.Big0)
-
if !bytes.Equal(header.Root, state.Root()) {
err = fmt.Errorf("invalid merkle root. received=%x got=%x", header.Root, state.Root())
return
@@ -213,10 +226,6 @@ func (sm *BlockProcessor) ProcessWithParent(block, parent *types.Block) (td *big
td = CalculateTD(block, parent)
// Sync the current block's state to the database
state.Sync()
- // Set the block hashes for the current messages
- state.Manifest().SetHash(block.Hash())
- // Reset the manifest XXX We need this?
- state.Manifest().Reset()
// Remove transactions from the pool
sm.txpool.RemoveSet(block.Transactions())
@@ -243,7 +252,11 @@ func (sm *BlockProcessor) ValidateBlock(block, parent *types.Block) error {
}
if block.Time() > time.Now().Unix() {
- return fmt.Errorf("block time is in the future")
+ return BlockFutureErr
+ }
+
+ if new(big.Int).Sub(block.Number(), parent.Number()).Cmp(big.NewInt(1)) != 0 {
+ return BlockNumberErr
}
// Verify the nonce of the block. Return an error if it's not valid
@@ -282,41 +295,17 @@ func (sm *BlockProcessor) AccumulateRewards(statedb *state.StateDB, block, paren
r := new(big.Int)
r.Mul(BlockReward, big.NewInt(15)).Div(r, big.NewInt(16))
- uncleAccount := statedb.GetAccount(uncle.Coinbase)
- uncleAccount.AddAmount(r)
+ statedb.AddBalance(uncle.Coinbase, r)
reward.Add(reward, new(big.Int).Div(BlockReward, big.NewInt(32)))
}
// Get the account associated with the coinbase
- account := statedb.GetAccount(block.Header().Coinbase)
- // Reward amount of ether to the coinbase address
- account.AddAmount(reward)
+ statedb.AddBalance(block.Header().Coinbase, reward)
return nil
}
-func (sm *BlockProcessor) GetMessages(block *types.Block) (messages []*state.Message, err error) {
- if !sm.bc.HasBlock(block.Header().ParentHash) {
- return nil, ParentError(block.Header().ParentHash)
- }
-
- sm.lastAttemptedBlock = block
-
- var (
- parent = sm.bc.GetBlock(block.Header().ParentHash)
- //state = state.New(parent.Trie().Copy())
- state = state.New(parent.Root(), sm.db)
- )
-
- defer state.Reset()
-
- sm.TransitionState(state, parent, block)
- sm.AccumulateRewards(state, block, parent)
-
- return state.Manifest().Messages, nil
-}
-
func (sm *BlockProcessor) GetLogs(block *types.Block) (logs state.Logs, err error) {
if !sm.bc.HasBlock(block.Header().ParentHash) {
return nil, ParentError(block.Header().ParentHash)
@@ -326,13 +315,10 @@ func (sm *BlockProcessor) GetLogs(block *types.Block) (logs state.Logs, err erro
var (
parent = sm.bc.GetBlock(block.Header().ParentHash)
- //state = state.New(parent.Trie().Copy())
- state = state.New(parent.Root(), sm.db)
+ state = state.New(parent.Root(), sm.db)
)
- defer state.Reset()
-
- sm.TransitionState(state, parent, block)
+ sm.TransitionState(state, parent, block, true)
sm.AccumulateRewards(state, block, parent)
return state.Logs(), nil
diff --git a/core/block_processor_test.go b/core/block_processor_test.go
new file mode 100644
index 000000000..35aeaa714
--- /dev/null
+++ b/core/block_processor_test.go
@@ -0,0 +1,34 @@
+package core
+
+import (
+ "math/big"
+ "testing"
+
+ "github.com/ethereum/go-ethereum/ethdb"
+ "github.com/ethereum/go-ethereum/event"
+)
+
+func proc() (*BlockProcessor, *ChainManager) {
+ db, _ := ethdb.NewMemDatabase()
+ var mux event.TypeMux
+
+ chainMan := NewChainManager(db, &mux)
+ return NewBlockProcessor(db, nil, chainMan, &mux), chainMan
+}
+
+func TestNumber(t *testing.T) {
+ bp, chain := proc()
+ block1 := chain.NewBlock(nil)
+ block1.Header().Number = big.NewInt(3)
+
+ err := bp.ValidateBlock(block1, chain.Genesis())
+ if err != BlockNumberErr {
+ t.Errorf("expected block number error")
+ }
+
+ block1 = chain.NewBlock(nil)
+ err = bp.ValidateBlock(block1, chain.Genesis())
+ if err == BlockNumberErr {
+ t.Errorf("didn't expect block number error")
+ }
+}
diff --git a/core/chain_manager.go b/core/chain_manager.go
index 0847980ca..9ef091c3c 100644
--- a/core/chain_manager.go
+++ b/core/chain_manager.go
@@ -16,6 +16,11 @@ import (
var chainlogger = logger.NewLogger("CHAIN")
+type ChainEvent struct {
+ Block *types.Block
+ Td *big.Int
+}
+
type StateQuery interface {
GetAccount(addr []byte) *state.StateObject
}
@@ -73,27 +78,28 @@ type ChainManager struct {
eventMux *event.TypeMux
genesisBlock *types.Block
// Last known total difficulty
- mu sync.RWMutex
- td *big.Int
- lastBlockNumber uint64
- currentBlock *types.Block
- lastBlockHash []byte
+ mu sync.RWMutex
+ tsmu sync.RWMutex
+ td *big.Int
+ currentBlock *types.Block
+ lastBlockHash []byte
transState *state.StateDB
}
-func (self *ChainManager) Td() *big.Int {
- self.mu.RLock()
- defer self.mu.RUnlock()
+func NewChainManager(db ethutil.Database, mux *event.TypeMux) *ChainManager {
+ bc := &ChainManager{db: db, genesisBlock: GenesisBlock(db), eventMux: mux}
+ bc.setLastBlock()
+ bc.transState = bc.State().Copy()
- return self.td
+ return bc
}
-func (self *ChainManager) LastBlockNumber() uint64 {
+func (self *ChainManager) Td() *big.Int {
self.mu.RLock()
defer self.mu.RUnlock()
- return self.lastBlockNumber
+ return self.td
}
func (self *ChainManager) LastBlockHash() []byte {
@@ -110,14 +116,6 @@ func (self *ChainManager) CurrentBlock() *types.Block {
return self.currentBlock
}
-func NewChainManager(db ethutil.Database, mux *event.TypeMux) *ChainManager {
- bc := &ChainManager{db: db, genesisBlock: GenesisBlock(db), eventMux: mux}
- bc.setLastBlock()
- bc.transState = bc.State().Copy()
-
- return bc
-}
-
func (self *ChainManager) Status() (td *big.Int, currentBlock []byte, genesisBlock []byte) {
self.mu.RLock()
defer self.mu.RUnlock()
@@ -134,9 +132,16 @@ func (self *ChainManager) State() *state.StateDB {
}
func (self *ChainManager) TransState() *state.StateDB {
+ self.tsmu.RLock()
+ defer self.tsmu.RUnlock()
+
return self.transState
}
+func (self *ChainManager) setTransState(statedb *state.StateDB) {
+ self.transState = statedb
+}
+
func (bc *ChainManager) setLastBlock() {
data, _ := bc.db.Get([]byte("LastBlock"))
if len(data) != 0 {
@@ -144,7 +149,6 @@ func (bc *ChainManager) setLastBlock() {
rlp.Decode(bytes.NewReader(data), &block)
bc.currentBlock = &block
bc.lastBlockHash = block.Hash()
- bc.lastBlockNumber = block.Header().Number.Uint64()
// Set the last know difficulty (might be 0x0 as initial value, Genesis)
bc.td = ethutil.BigD(bc.db.LastKnownTD())
@@ -152,7 +156,7 @@ func (bc *ChainManager) setLastBlock() {
bc.Reset()
}
- chainlogger.Infof("Last block (#%d) %x TD=%v\n", bc.lastBlockNumber, bc.currentBlock.Hash(), bc.td)
+ chainlogger.Infof("Last block (#%v) %x TD=%v\n", bc.currentBlock.Number(), bc.currentBlock.Hash(), bc.td)
}
// Block creation & chain handling
@@ -163,7 +167,7 @@ func (bc *ChainManager) NewBlock(coinbase []byte) *types.Block {
var root []byte
parentHash := ZeroHash256
- if bc.CurrentBlock != nil {
+ if bc.currentBlock != nil {
root = bc.currentBlock.Header().Root
parentHash = bc.lastBlockHash
}
@@ -175,6 +179,9 @@ func (bc *ChainManager) NewBlock(coinbase []byte) *types.Block {
ethutil.BigPow(2, 32),
nil,
"")
+ block.SetUncles(nil)
+ block.SetTransactions(nil)
+ block.SetReceipts(nil)
parent := bc.currentBlock
if parent != nil {
@@ -226,8 +233,6 @@ func (bc *ChainManager) insert(block *types.Block) {
}
func (bc *ChainManager) write(block *types.Block) {
- bc.writeBlockInfo(block)
-
encodedBlock := ethutil.Encode(block.RlpDataForStorage())
bc.db.Put(block.Hash(), encodedBlock)
}
@@ -263,6 +268,7 @@ func (self *ChainManager) GetBlockHashesFromHash(hash []byte, max uint64) (chain
break
}
}
+ fmt.Printf("get hash %x (%d)\n", hash, len(chain))
return
}
@@ -346,11 +352,6 @@ func (self *ChainManager) CalcTotalDiff(block *types.Block) (*big.Int, error) {
return td, nil
}
-// Unexported method for writing extra non-essential block info to the db
-func (bc *ChainManager) writeBlockInfo(block *types.Block) {
- bc.lastBlockNumber++
-}
-
func (bc *ChainManager) Stop() {
if bc.CurrentBlock != nil {
chainlogger.Infoln("Stopped")
@@ -358,6 +359,9 @@ func (bc *ChainManager) Stop() {
}
func (self *ChainManager) InsertChain(chain types.Blocks) error {
+ self.tsmu.Lock()
+ defer self.tsmu.Unlock()
+
for _, block := range chain {
td, err := self.processor.Process(block)
if err != nil {
@@ -373,6 +377,7 @@ func (self *ChainManager) InsertChain(chain types.Blocks) error {
}
block.Td = td
+ var chain, split bool
self.mu.Lock()
{
self.write(block)
@@ -380,17 +385,25 @@ func (self *ChainManager) InsertChain(chain types.Blocks) error {
if td.Cmp(self.td) > 0 {
if block.Header().Number.Cmp(new(big.Int).Add(cblock.Header().Number, ethutil.Big1)) < 0 {
chainlogger.Infof("Split detected. New head #%v (%x) TD=%v, was #%v (%x) TD=%v\n", block.Header().Number, block.Hash()[:4], td, cblock.Header().Number, cblock.Hash()[:4], self.td)
+ split = true
}
self.setTotalDifficulty(td)
self.insert(block)
- self.transState = state.New(cblock.Root(), self.db) //state.New(cblock.Trie().Copy())
- }
+ chain = true
+ }
}
self.mu.Unlock()
- self.eventMux.Post(NewBlockEvent{block})
+ if chain {
+ self.eventMux.Post(ChainEvent{block, td})
+ }
+
+ if split {
+ self.setTransState(state.New(block.Root(), self.db))
+ self.eventMux.Post(ChainSplitEvent{block})
+ }
}
return nil
diff --git a/core/error.go b/core/error.go
index 11d8c1653..e86bacb2d 100644
--- a/core/error.go
+++ b/core/error.go
@@ -1,10 +1,16 @@
package core
import (
+ "errors"
"fmt"
"math/big"
)
+var (
+ BlockNumberErr = errors.New("block number invalid")
+ BlockFutureErr = errors.New("block time is in the future")
+)
+
// Parent error. In case a parent is unknown this error will be thrown
// by the block manager
type ParentErr struct {
@@ -62,23 +68,6 @@ func IsValidationErr(err error) bool {
return ok
}
-type GasLimitErr struct {
- Message string
- Is, Max *big.Int
-}
-
-func IsGasLimitErr(err error) bool {
- _, ok := err.(*GasLimitErr)
-
- return ok
-}
-func (err *GasLimitErr) Error() string {
- return err.Message
-}
-func GasLimitError(is, max *big.Int) *GasLimitErr {
- return &GasLimitErr{Message: fmt.Sprintf("GasLimit error. Max %s, transaction would take it to %s", max, is), Is: is, Max: max}
-}
-
type NonceErr struct {
Message string
Is, Exp uint64
diff --git a/core/events.go b/core/events.go
index fe106da49..4cbbc609c 100644
--- a/core/events.go
+++ b/core/events.go
@@ -13,3 +13,6 @@ type NewBlockEvent struct{ Block *types.Block }
// NewMinedBlockEvent is posted when a block has been imported.
type NewMinedBlockEvent struct{ Block *types.Block }
+
+// ChainSplit is posted when a new head is detected
+type ChainSplitEvent struct{ Block *types.Block }
diff --git a/core/filter.go b/core/filter.go
index b93fcc8a5..cdf7b282d 100644
--- a/core/filter.go
+++ b/core/filter.go
@@ -16,7 +16,7 @@ type FilterOptions struct {
Earliest int64
Latest int64
- Address []byte
+ Address [][]byte
Topics [][]byte
Skip int
@@ -25,11 +25,11 @@ type FilterOptions struct {
// Filtering interface
type Filter struct {
- eth EthManager
+ eth Backend
earliest int64
latest int64
skip int
- address []byte
+ address [][]byte
max int
topics [][]byte
@@ -40,7 +40,7 @@ type Filter struct {
// Create a new filter which uses a bloom filter on blocks to figure out whether a particular block
// is interesting or not.
-func NewFilter(eth EthManager) *Filter {
+func NewFilter(eth Backend) *Filter {
return &Filter{eth: eth}
}
@@ -65,7 +65,7 @@ func (self *Filter) SetLatestBlock(latest int64) {
self.latest = latest
}
-func (self *Filter) SetAddress(addr []byte) {
+func (self *Filter) SetAddress(addr [][]byte) {
self.address = addr
}
@@ -111,14 +111,14 @@ func (self *Filter) Find() state.Logs {
// current parameters
if self.bloomFilter(block) {
// Get the logs of the block
- logs, err := self.eth.BlockProcessor().GetLogs(block)
+ unfiltered, err := self.eth.BlockProcessor().GetLogs(block)
if err != nil {
chainlogger.Warnln("err: filter get logs ", err)
break
}
- logs = append(logs, self.FilterLogs(logs)...)
+ logs = append(logs, self.FilterLogs(unfiltered)...)
}
block = self.eth.ChainManager().GetBlock(block.ParentHash())
@@ -145,7 +145,7 @@ func (self *Filter) FilterLogs(logs state.Logs) state.Logs {
// Filter the logs for interesting stuff
Logs:
for _, log := range logs {
- if !bytes.Equal(self.address, log.Address()) {
+ if !includes(self.address, log.Address()) {
continue
}
@@ -163,8 +163,18 @@ Logs:
}
func (self *Filter) bloomFilter(block *types.Block) bool {
- if len(self.address) > 0 && !types.BloomLookup(block.Bloom(), self.address) {
- return false
+ if len(self.address) > 0 {
+ var included bool
+ for _, addr := range self.address {
+ if types.BloomLookup(block.Bloom(), addr) {
+ included = true
+ break
+ }
+ }
+
+ if !included {
+ return false
+ }
}
for _, topic := range self.topics {
diff --git a/core/genesis.go b/core/genesis.go
index c870ce61e..75b4fc100 100644
--- a/core/genesis.go
+++ b/core/genesis.go
@@ -1,7 +1,10 @@
package core
import (
+ "encoding/json"
+ "fmt"
"math/big"
+ "os"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
@@ -31,24 +34,39 @@ func GenesisBlock(db ethutil.Database) *types.Block {
genesis.SetTransactions(types.Transactions{})
genesis.SetReceipts(types.Receipts{})
+ var accounts map[string]struct{ Balance string }
+ err := json.Unmarshal(genesisData, &accounts)
+ if err != nil {
+ fmt.Println("enable to decode genesis json data:", err)
+ os.Exit(1)
+ }
+
statedb := state.New(genesis.Root(), db)
- for _, addr := range []string{
- "dbdbdb2cbd23b783741e8d7fcf51e459b497e4a6",
- "e4157b34ea9615cfbde6b4fda419828124b70c78",
- "b9c015918bdaba24b4ff057a92a3873d6eb201be",
- "6c386a4b26f73c802f34673f7248bb118f97424a",
- "cd2a3d9f938e13cd947ec05abc7fe734df8dd826",
- "2ef47100e0787b915105fd5e3f4ff6752079d5cb",
- "e6716f9544a56c530d868e4bfbacb172315bdead",
- "1a26338f0d905e295fccb71fa9ea849ffa12aaf4",
- } {
+ for addr, account := range accounts {
codedAddr := ethutil.Hex2Bytes(addr)
- account := statedb.GetAccount(codedAddr)
- account.SetBalance(ethutil.Big("1606938044258990275541962092341162602522202993782792835301376")) //ethutil.BigPow(2, 200)
- statedb.UpdateStateObject(account)
+ accountState := statedb.GetAccount(codedAddr)
+ accountState.SetBalance(ethutil.Big(account.Balance))
+ statedb.UpdateStateObject(accountState)
}
statedb.Sync()
genesis.Header().Root = statedb.Root()
+ fmt.Printf("+++ genesis +++\nRoot: %x\nHash: %x\n", genesis.Header().Root, genesis.Hash())
+
return genesis
}
+
+var genesisData = []byte(`{
+ "dbdbdb2cbd23b783741e8d7fcf51e459b497e4a6": {"balance": "1606938044258990275541962092341162602522202993782792835301376"},
+ "e4157b34ea9615cfbde6b4fda419828124b70c78": {"balance": "1606938044258990275541962092341162602522202993782792835301376"},
+ "b9c015918bdaba24b4ff057a92a3873d6eb201be": {"balance": "1606938044258990275541962092341162602522202993782792835301376"},
+ "6c386a4b26f73c802f34673f7248bb118f97424a": {"balance": "1606938044258990275541962092341162602522202993782792835301376"},
+ "cd2a3d9f938e13cd947ec05abc7fe734df8dd826": {"balance": "1606938044258990275541962092341162602522202993782792835301376"},
+ "2ef47100e0787b915105fd5e3f4ff6752079d5cb": {"balance": "1606938044258990275541962092341162602522202993782792835301376"},
+ "e6716f9544a56c530d868e4bfbacb172315bdead": {"balance": "1606938044258990275541962092341162602522202993782792835301376"},
+ "1a26338f0d905e295fccb71fa9ea849ffa12aaf4": {"balance": "1606938044258990275541962092341162602522202993782792835301376"},
+ "b0afc46d9ce366d06ab4952ca27db1d9557ae9fd": {"balance": "154162184000000000000000"},
+ "f6b1e9dc460d4d62cc22ec5f987d726929c0f9f0": {"balance": "102774789000000000000000"},
+ "cc45122d8b7fa0b1eaa6b29e0fb561422a9239d0": {"balance": "51387394000000000000000"},
+ "b7576e9d314df41ec5506494293afb1bd5d3f65d": {"balance": "69423399000000000000000"}
+}`)
diff --git a/core/helper_test.go b/core/helper_test.go
index 7b41b86f1..473576e3f 100644
--- a/core/helper_test.go
+++ b/core/helper_test.go
@@ -9,7 +9,6 @@ import (
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/ethutil"
"github.com/ethereum/go-ethereum/event"
- "github.com/ethereum/go-ethereum/p2p"
)
// Implement our EthTest Manager
@@ -54,13 +53,6 @@ func (tm *TestManager) TxPool() *TxPool {
func (tm *TestManager) EventMux() *event.TypeMux {
return tm.eventMux
}
-func (tm *TestManager) Broadcast(msgType p2p.Msg, data []interface{}) {
- fmt.Println("Broadcast not implemented")
-}
-
-func (tm *TestManager) ClientIdentity() p2p.ClientIdentity {
- return nil
-}
func (tm *TestManager) KeyManager() *crypto.KeyManager {
return nil
}
diff --git a/core/manager.go b/core/manager.go
index 4671573b1..bb039d063 100644
--- a/core/manager.go
+++ b/core/manager.go
@@ -7,16 +7,14 @@ import (
"github.com/ethereum/go-ethereum/p2p"
)
-type EthManager interface {
+type Backend interface {
BlockProcessor() *BlockProcessor
ChainManager() *ChainManager
TxPool() *TxPool
PeerCount() int
- IsMining() bool
IsListening() bool
Peers() []*p2p.Peer
KeyManager() *crypto.KeyManager
- ClientIdentity() p2p.ClientIdentity
Db() ethutil.Database
EventMux() *event.TypeMux
}
diff --git a/core/state_transition.go b/core/state_transition.go
index 33dd45f02..36ffa23d9 100644
--- a/core/state_transition.go
+++ b/core/state_transition.go
@@ -138,8 +138,8 @@ func (self *StateTransition) preCheck() (err error) {
)
// Make sure this transaction's nonce is correct
- if sender.Nonce != msg.Nonce() {
- return NonceError(msg.Nonce(), sender.Nonce)
+ if sender.Nonce() != msg.Nonce() {
+ return NonceError(msg.Nonce(), sender.Nonce())
}
// Pre-pay gas / Buy gas of the coinbase account
@@ -166,7 +166,8 @@ func (self *StateTransition) TransitionState() (ret []byte, err error) {
defer self.RefundGas()
// Increment the nonce for the next transaction
- sender.Nonce += 1
+ self.state.SetNonce(sender.Address(), sender.Nonce()+1)
+ //sender.Nonce += 1
// Transaction gas
if err = self.UseGas(vm.GasTx); err != nil {
@@ -241,7 +242,7 @@ func MakeContract(msg Message, state *state.StateDB) *state.StateObject {
addr := AddressFromMessage(msg)
contract := state.GetOrNewStateObject(addr)
- contract.InitCode = msg.Data()
+ contract.SetInitCode(msg.Data())
return contract
}
diff --git a/core/transaction_pool.go b/core/transaction_pool.go
index 7a901fcae..050cff3d8 100644
--- a/core/transaction_pool.go
+++ b/core/transaction_pool.go
@@ -3,6 +3,7 @@ package core
import (
"errors"
"fmt"
+ "sync"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/ethutil"
@@ -35,6 +36,7 @@ type TxProcessor interface {
// guarantee a non blocking pool we use a queue channel which can be
// independently read without needing access to the actual pool.
type TxPool struct {
+ mu sync.RWMutex
// Queueing channel for reading and writing incoming
// transactions to
queueChan chan *types.Transaction
@@ -97,7 +99,7 @@ func (self *TxPool) addTx(tx *types.Transaction) {
self.txs[string(tx.Hash())] = tx
}
-func (self *TxPool) Add(tx *types.Transaction) error {
+func (self *TxPool) add(tx *types.Transaction) error {
if self.txs[string(tx.Hash())] != nil {
return fmt.Errorf("Known transaction (%x)", tx.Hash()[0:4])
}
@@ -128,17 +130,28 @@ func (self *TxPool) Size() int {
return len(self.txs)
}
+func (self *TxPool) Add(tx *types.Transaction) error {
+ self.mu.Lock()
+ defer self.mu.Unlock()
+ return self.add(tx)
+}
func (self *TxPool) AddTransactions(txs []*types.Transaction) {
+ self.mu.Lock()
+ defer self.mu.Unlock()
+
for _, tx := range txs {
- if err := self.Add(tx); err != nil {
- txplogger.Infoln(err)
+ if err := self.add(tx); err != nil {
+ txplogger.Debugln(err)
} else {
- txplogger.Infof("tx %x\n", tx.Hash()[0:4])
+ txplogger.Debugf("tx %x\n", tx.Hash()[0:4])
}
}
}
func (self *TxPool) GetTransactions() (txs types.Transactions) {
+ self.mu.RLock()
+ defer self.mu.RUnlock()
+
txs = make(types.Transactions, self.Size())
i := 0
for _, tx := range self.txs {
@@ -150,30 +163,32 @@ func (self *TxPool) GetTransactions() (txs types.Transactions) {
}
func (pool *TxPool) RemoveInvalid(query StateQuery) {
+ pool.mu.Lock()
+
var removedTxs types.Transactions
for _, tx := range pool.txs {
sender := query.GetAccount(tx.From())
err := pool.ValidateTransaction(tx)
- fmt.Println(err, sender.Nonce, tx.Nonce())
- if err != nil || sender.Nonce >= tx.Nonce() {
+ if err != nil || sender.Nonce() >= tx.Nonce() {
removedTxs = append(removedTxs, tx)
}
}
+ pool.mu.Unlock()
pool.RemoveSet(removedTxs)
}
func (self *TxPool) RemoveSet(txs types.Transactions) {
+ self.mu.Lock()
+ defer self.mu.Unlock()
+
for _, tx := range txs {
delete(self.txs, string(tx.Hash()))
}
}
-func (pool *TxPool) Flush() []*types.Transaction {
- txList := pool.GetTransactions()
+func (pool *TxPool) Flush() {
pool.txs = make(map[string]*types.Transaction)
-
- return txList
}
func (pool *TxPool) Start() {
diff --git a/core/types/block.go b/core/types/block.go
index a334c512e..d57de1311 100644
--- a/core/types/block.go
+++ b/core/types/block.go
@@ -6,6 +6,7 @@ import (
"math/big"
"sort"
"time"
+
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethutil"
"github.com/ethereum/go-ethereum/rlp"
@@ -175,6 +176,7 @@ func (self *Block) RlpDataForStorage() interface{} {
// Header accessors (add as you need them)
func (self *Block) Number() *big.Int { return self.header.Number }
func (self *Block) NumberU64() uint64 { return self.header.Number.Uint64() }
+func (self *Block) Nonce() []byte { return self.header.Nonce }
func (self *Block) Bloom() []byte { return self.header.Bloom }
func (self *Block) Coinbase() []byte { return self.header.Coinbase }
func (self *Block) Time() int64 { return int64(self.header.Time) }
@@ -183,6 +185,18 @@ func (self *Block) GasUsed() *big.Int { return self.header.GasUsed }
func (self *Block) Root() []byte { return self.header.Root }
func (self *Block) SetRoot(root []byte) { self.header.Root = root }
func (self *Block) Size() ethutil.StorageSize { return ethutil.StorageSize(len(ethutil.Encode(self))) }
+func (self *Block) GetTransaction(i int) *Transaction {
+ if len(self.transactions) > i {
+ return self.transactions[i]
+ }
+ return nil
+}
+func (self *Block) GetUncle(i int) *Header {
+ if len(self.uncles) > i {
+ return self.uncles[i]
+ }
+ return nil
+}
// Implement pow.Block
func (self *Block) Difficulty() *big.Int { return self.header.Difficulty }
@@ -207,6 +221,7 @@ func (self *Block) ParentHash() []byte {
func (self *Block) String() string {
return fmt.Sprintf(`BLOCK(%x): Size: %v TD: %v {
+NoNonce: %x
Header:
[
%v
@@ -216,7 +231,7 @@ Transactions:
Uncles:
%v
}
-`, self.header.Hash(), self.Size(), self.Td, self.header, self.transactions, self.uncles)
+`, self.header.Hash(), self.Size(), self.Td, self.header.HashNoNonce(), self.header, self.transactions, self.uncles)
}
func (self *Header) String() string {
diff --git a/core/types/receipt.go b/core/types/receipt.go
index bac64e41d..49e68e233 100644
--- a/core/types/receipt.go
+++ b/core/types/receipt.go
@@ -17,7 +17,7 @@ type Receipt struct {
}
func NewReceipt(root []byte, cumalativeGasUsed *big.Int) *Receipt {
- return &Receipt{PostState: ethutil.CopyBytes(root), CumulativeGasUsed: cumalativeGasUsed}
+ return &Receipt{PostState: ethutil.CopyBytes(root), CumulativeGasUsed: new(big.Int).Set(cumalativeGasUsed)}
}
func NewRecieptFromValue(val *ethutil.Value) *Receipt {