aboutsummaryrefslogtreecommitdiffstats
path: root/core
diff options
context:
space:
mode:
Diffstat (limited to 'core')
-rw-r--r--core/block_manager.go125
-rw-r--r--core/chain_manager.go234
-rw-r--r--core/chain_manager_test.go126
-rw-r--r--core/events.go3
-rw-r--r--core/execution.go45
-rw-r--r--core/filter.go13
-rw-r--r--core/filter_test.go6
-rw-r--r--core/genesis.go65
-rw-r--r--core/helper_test.go6
-rw-r--r--core/state_transition.go157
-rw-r--r--core/transaction_pool.go75
-rw-r--r--core/types/block.go499
-rw-r--r--core/types/block_test.go23
-rw-r--r--core/types/derive_sha.go8
-rw-r--r--core/types/transaction.go160
-rw-r--r--core/vm_env.go26
16 files changed, 832 insertions, 739 deletions
diff --git a/core/block_manager.go b/core/block_manager.go
index f6c73bc2c..8a5455306 100644
--- a/core/block_manager.go
+++ b/core/block_manager.go
@@ -2,7 +2,6 @@ package core
import (
"bytes"
- "container/list"
"errors"
"fmt"
"math/big"
@@ -14,10 +13,11 @@ import (
"github.com/ethereum/go-ethereum/ethutil"
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/logger"
+ "github.com/ethereum/go-ethereum/p2p"
"github.com/ethereum/go-ethereum/pow"
"github.com/ethereum/go-ethereum/pow/ezp"
"github.com/ethereum/go-ethereum/state"
- "github.com/ethereum/go-ethereum/wire"
+ "gopkg.in/fatih/set.v0"
)
var statelogger = logger.NewLogger("BLOCK")
@@ -38,13 +38,12 @@ type EthManager interface {
BlockManager() *BlockManager
ChainManager() *ChainManager
TxPool() *TxPool
- Broadcast(msgType wire.MsgType, data []interface{})
PeerCount() int
IsMining() bool
IsListening() bool
- Peers() *list.List
+ Peers() []*p2p.Peer
KeyManager() *crypto.KeyManager
- ClientIdentity() wire.ClientIdentity
+ ClientIdentity() p2p.ClientIdentity
Db() ethutil.Database
EventMux() *event.TypeMux
}
@@ -58,8 +57,8 @@ type BlockManager struct {
mem map[string]*big.Int
// Proof of work used for validating
Pow pow.PoW
- // The ethereum manager interface
- eth EthManager
+
+ txpool *TxPool
// The last attempted block is mainly used for debugging purposes
// This does not have to be a valid block and will be set during
@@ -71,21 +70,21 @@ type BlockManager struct {
eventMux *event.TypeMux
}
-func NewBlockManager(ethereum EthManager) *BlockManager {
+func NewBlockManager(txpool *TxPool, chainManager *ChainManager, eventMux *event.TypeMux) *BlockManager {
sm := &BlockManager{
mem: make(map[string]*big.Int),
Pow: ezp.New(),
- eth: ethereum,
- bc: ethereum.ChainManager(),
- eventMux: ethereum.EventMux(),
+ bc: chainManager,
+ eventMux: eventMux,
+ txpool: txpool,
}
return sm
}
func (sm *BlockManager) TransitionState(statedb *state.StateDB, parent, block *types.Block) (receipts types.Receipts, err error) {
- coinbase := statedb.GetOrNewStateObject(block.Coinbase)
- coinbase.SetGasPool(block.CalcGasLimit(parent))
+ coinbase := statedb.GetOrNewStateObject(block.Header().Coinbase)
+ coinbase.SetGasPool(CalcGasLimit(parent, block))
// Process the transactions on to current block
receipts, _, _, _, err = sm.ApplyTransactions(coinbase, statedb, block, block.Transactions(), false)
@@ -111,11 +110,11 @@ done:
// If we are mining this block and validating we want to set the logs back to 0
state.EmptyLogs()
- txGas := new(big.Int).Set(tx.Gas)
+ txGas := new(big.Int).Set(tx.Gas())
cb := state.GetStateObject(coinbase.Address())
st := NewStateTransition(cb, tx, state, block)
- err = st.TransitionState()
+ _, err = st.TransitionState()
if err != nil {
switch {
case IsNonceErr(err):
@@ -129,12 +128,11 @@ done:
statelogger.Infoln(err)
erroneous = append(erroneous, tx)
err = nil
- continue
}
}
txGas.Sub(txGas, st.gas)
- cumulativeSum.Add(cumulativeSum, new(big.Int).Mul(txGas, tx.GasPrice))
+ cumulativeSum.Add(cumulativeSum, new(big.Int).Mul(txGas, tx.GasPrice()))
// Update the state with pending changes
state.Update(txGas)
@@ -143,6 +141,7 @@ done:
receipt := types.NewReceipt(state.Root(), cumulative)
receipt.SetLogs(state.Logs())
receipt.Bloom = types.CreateBloom(types.Receipts{receipt})
+ chainlogger.Debugln(receipt)
// Notify all subscribers
if !transientProcess {
@@ -158,7 +157,7 @@ done:
}
block.Reward = cumulativeSum
- block.GasUsed = totalUsedGas
+ block.Header().GasUsed = totalUsedGas
return receipts, handled, unhandled, erroneous, err
}
@@ -168,14 +167,15 @@ func (sm *BlockManager) Process(block *types.Block) (td *big.Int, msgs state.Mes
sm.mutex.Lock()
defer sm.mutex.Unlock()
- if sm.bc.HasBlock(block.Hash()) {
- return nil, nil, &KnownBlockError{block.Number, block.Hash()}
+ header := block.Header()
+ if sm.bc.HasBlock(header.Hash()) {
+ return nil, nil, &KnownBlockError{header.Number, header.Hash()}
}
- if !sm.bc.HasBlock(block.PrevHash) {
- return nil, nil, ParentError(block.PrevHash)
+ if !sm.bc.HasBlock(header.ParentHash) {
+ return nil, nil, ParentError(header.ParentHash)
}
- parent := sm.bc.GetBlock(block.PrevHash)
+ parent := sm.bc.GetBlock(header.ParentHash)
return sm.ProcessWithParent(block, parent)
}
@@ -183,13 +183,7 @@ func (sm *BlockManager) Process(block *types.Block) (td *big.Int, msgs state.Mes
func (sm *BlockManager) ProcessWithParent(block, parent *types.Block) (td *big.Int, messages state.Messages, err error) {
sm.lastAttemptedBlock = block
- state := parent.State().Copy()
-
- // Defer the Undo on the Trie. If the block processing happened
- // we don't want to undo but since undo only happens on dirty
- // nodes this won't happen because Commit would have been called
- // before that.
- defer state.Reset()
+ state := state.New(parent.Trie().Copy())
// Block validation
if err = sm.ValidateBlock(block, parent); err != nil {
@@ -201,21 +195,24 @@ func (sm *BlockManager) ProcessWithParent(block, parent *types.Block) (td *big.I
return
}
+ header := block.Header()
+
rbloom := types.CreateBloom(receipts)
- if bytes.Compare(rbloom, block.LogsBloom) != 0 {
+ if bytes.Compare(rbloom, header.Bloom) != 0 {
err = fmt.Errorf("unable to replicate block's bloom=%x", rbloom)
return
}
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)
+ if bytes.Compare(txSha, header.TxHash) != 0 {
+ err = fmt.Errorf("validating transaction root. received=%x got=%x", header.TxHash, txSha)
return
}
receiptSha := types.DeriveSha(receipts)
- if bytes.Compare(receiptSha, block.ReceiptSha) != 0 {
- err = fmt.Errorf("validating receipt root. received=%x got=%x", block.ReceiptSha, receiptSha)
+ if bytes.Compare(receiptSha, header.ReceiptHash) != 0 {
+ fmt.Println("receipts", receipts)
+ err = fmt.Errorf("validating receipt root. received=%x got=%x", header.ReceiptHash, receiptSha)
return
}
@@ -225,8 +222,8 @@ func (sm *BlockManager) ProcessWithParent(block, parent *types.Block) (td *big.I
state.Update(ethutil.Big0)
- if !block.State().Cmp(state) {
- err = fmt.Errorf("invalid merkle root. received=%x got=%x", block.Root(), state.Root())
+ if !bytes.Equal(header.Root, state.Root()) {
+ err = fmt.Errorf("invalid merkle root. received=%x got=%x", header.Root, state.Root())
return
}
@@ -238,9 +235,9 @@ func (sm *BlockManager) ProcessWithParent(block, parent *types.Block) (td *big.I
messages := state.Manifest().Messages
state.Manifest().Reset()
- chainlogger.Infof("Processed block #%d (%x...)\n", block.Number, block.Hash()[0:4])
+ chainlogger.Infof("Processed block #%d (%x...)\n", header.Number, block.Hash()[0:4])
- sm.eth.TxPool().RemoveSet(block.Transactions())
+ sm.txpool.RemoveSet(block.Transactions())
return td, messages, nil
} else {
@@ -250,18 +247,18 @@ func (sm *BlockManager) ProcessWithParent(block, parent *types.Block) (td *big.I
func (sm *BlockManager) CalculateTD(block *types.Block) (*big.Int, bool) {
uncleDiff := new(big.Int)
- for _, uncle := range block.Uncles {
+ for _, uncle := range block.Uncles() {
uncleDiff = uncleDiff.Add(uncleDiff, uncle.Difficulty)
}
// TD(genesis_block) = 0 and TD(B) = TD(B.parent) + sum(u.difficulty for u in B.uncles) + B.difficulty
td := new(big.Int)
- td = td.Add(sm.bc.TD, uncleDiff)
- td = td.Add(td, block.Difficulty)
+ td = td.Add(sm.bc.Td(), uncleDiff)
+ td = td.Add(td, block.Header().Difficulty)
// The new TD will only be accepted if the new difficulty is
// is greater than the previous.
- if td.Cmp(sm.bc.TD) > 0 {
+ if td.Cmp(sm.bc.Td()) > 0 {
return td, true
}
@@ -273,13 +270,13 @@ func (sm *BlockManager) CalculateTD(block *types.Block) (*big.Int, bool) {
// Validation validates easy over difficult (dagger takes longer time = difficult)
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)
+ if expd.Cmp(block.Header().Difficulty) < 0 {
+ return fmt.Errorf("Difficulty check failed for block %v, %v", block.Header().Difficulty, expd)
}
- diff := block.Time - parent.Time
+ diff := block.Header().Time - parent.Header().Time
if diff < 0 {
- return ValidationError("Block timestamp less then prev block %v (%v - %v)", diff, block.Time, sm.bc.CurrentBlock.Time)
+ return ValidationError("Block timestamp less then prev block %v (%v - %v)", diff, block.Header().Time, sm.bc.CurrentBlock().Header().Time)
}
/* XXX
@@ -291,7 +288,7 @@ func (sm *BlockManager) ValidateBlock(block, parent *types.Block) error {
// Verify the nonce of the block. Return an error if it's not valid
if !sm.Pow.Verify(block /*block.HashNoNonce(), block.Difficulty, block.Nonce*/) {
- return ValidationError("Block's nonce is invalid (= %v)", ethutil.Bytes2Hex(block.Nonce))
+ return ValidationError("Block's nonce is invalid (= %v)", ethutil.Bytes2Hex(block.Header().Nonce))
}
return nil
@@ -300,24 +297,28 @@ func (sm *BlockManager) ValidateBlock(block, parent *types.Block) error {
func (sm *BlockManager) AccumelateRewards(statedb *state.StateDB, block, parent *types.Block) error {
reward := new(big.Int).Set(BlockReward)
- knownUncles := ethutil.Set(parent.Uncles)
- nonces := ethutil.NewSet(block.Nonce)
- for _, uncle := range block.Uncles {
+ knownUncles := set.New()
+ for _, uncle := range parent.Uncles() {
+ knownUncles.Add(string(uncle.Hash()))
+ }
+
+ nonces := ethutil.NewSet(block.Header().Nonce)
+ for _, uncle := range block.Uncles() {
if nonces.Include(uncle.Nonce) {
// Error not unique
return UncleError("Uncle not unique")
}
- uncleParent := sm.bc.GetBlock(uncle.PrevHash)
+ uncleParent := sm.bc.GetBlock(uncle.ParentHash)
if uncleParent == nil {
- return UncleError(fmt.Sprintf("Uncle's parent unknown (%x)", uncle.PrevHash[0:4]))
+ return UncleError(fmt.Sprintf("Uncle's parent unknown (%x)", uncle.ParentHash[0:4]))
}
- if uncleParent.Number.Cmp(new(big.Int).Sub(parent.Number, big.NewInt(6))) < 0 {
+ if uncleParent.Header().Number.Cmp(new(big.Int).Sub(parent.Header().Number, big.NewInt(6))) < 0 {
return UncleError("Uncle too old")
}
- if knownUncles.Include(uncle.Hash()) {
+ if knownUncles.Has(string(uncle.Hash())) {
return UncleError("Uncle in chain")
}
@@ -333,15 +334,15 @@ func (sm *BlockManager) AccumelateRewards(statedb *state.StateDB, block, parent
}
// Get the account associated with the coinbase
- account := statedb.GetAccount(block.Coinbase)
+ account := statedb.GetAccount(block.Header().Coinbase)
// Reward amount of ether to the coinbase address
account.AddAmount(reward)
statedb.Manifest().AddMessage(&state.Message{
- To: block.Coinbase,
+ To: block.Header().Coinbase,
Input: nil,
Origin: nil,
- Block: block.Hash(), Timestamp: block.Time, Coinbase: block.Coinbase, Number: block.Number,
+ Block: block.Hash(), Timestamp: int64(block.Header().Time), Coinbase: block.Header().Coinbase, Number: block.Header().Number,
Value: new(big.Int).Add(reward, block.Reward),
})
@@ -349,15 +350,15 @@ func (sm *BlockManager) AccumelateRewards(statedb *state.StateDB, block, parent
}
func (sm *BlockManager) GetMessages(block *types.Block) (messages []*state.Message, err error) {
- if !sm.bc.HasBlock(block.PrevHash) {
- return nil, ParentError(block.PrevHash)
+ if !sm.bc.HasBlock(block.Header().ParentHash) {
+ return nil, ParentError(block.Header().ParentHash)
}
sm.lastAttemptedBlock = block
var (
- parent = sm.bc.GetBlock(block.PrevHash)
- state = parent.State().Copy()
+ parent = sm.bc.GetBlock(block.Header().ParentHash)
+ state = state.New(parent.Trie().Copy())
)
defer state.Reset()
diff --git a/core/chain_manager.go b/core/chain_manager.go
index 3e48579b9..485c195d5 100644
--- a/core/chain_manager.go
+++ b/core/chain_manager.go
@@ -1,18 +1,22 @@
package core
import (
+ "bytes"
"fmt"
"math/big"
+ "sync"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/ethutil"
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/logger"
+ "github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum/go-ethereum/state"
)
var chainlogger = logger.NewLogger("CHAIN")
+/*
func AddTestNetFunds(block *types.Block) {
for _, addr := range []string{
"51ba59315b3a95761d0863b05ccc7a7f54703d99",
@@ -30,39 +34,87 @@ func AddTestNetFunds(block *types.Block) {
block.State().UpdateStateObject(account)
}
}
+*/
func CalcDifficulty(block, parent *types.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)
+ bh, ph := block.Header(), parent.Header()
+ adjust := new(big.Int).Rsh(ph.Difficulty, 10)
+ if bh.Time >= ph.Time+5 {
+ diff.Sub(ph.Difficulty, adjust)
} else {
- diff.Add(parent.Difficulty, adjust)
+ diff.Add(ph.Difficulty, adjust)
}
return diff
}
+func CalcGasLimit(parent, block *types.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)
+}
+
type ChainManager struct {
//eth EthManager
processor types.BlockProcessor
eventMux *event.TypeMux
genesisBlock *types.Block
// Last known total difficulty
- TD *big.Int
+ mu sync.RWMutex
+ td *big.Int
+ lastBlockNumber uint64
+ currentBlock *types.Block
+ lastBlockHash []byte
+
+ transState *state.StateDB
+}
- LastBlockNumber uint64
+func (self *ChainManager) Td() *big.Int {
+ self.mu.RLock()
+ defer self.mu.RUnlock()
- CurrentBlock *types.Block
- LastBlockHash []byte
+ return self.td
+}
- transState *state.StateDB
+func (self *ChainManager) LastBlockNumber() uint64 {
+ self.mu.RLock()
+ defer self.mu.RUnlock()
+
+ return self.lastBlockNumber
+}
+
+func (self *ChainManager) LastBlockHash() []byte {
+ self.mu.RLock()
+ defer self.mu.RUnlock()
+
+ return self.lastBlockHash
+}
+
+func (self *ChainManager) CurrentBlock() *types.Block {
+ self.mu.RLock()
+ defer self.mu.RUnlock()
+
+ return self.currentBlock
}
func NewChainManager(mux *event.TypeMux) *ChainManager {
bc := &ChainManager{}
- bc.genesisBlock = types.NewBlockFromBytes(ethutil.Encode(Genesis))
+ bc.genesisBlock = GenesisBlock()
bc.eventMux = mux
bc.setLastBlock()
@@ -72,12 +124,19 @@ func NewChainManager(mux *event.TypeMux) *ChainManager {
return bc
}
+func (self *ChainManager) Status() (td *big.Int, currentBlock []byte, genesisBlock []byte) {
+ self.mu.RLock()
+ defer self.mu.RUnlock()
+
+ return self.td, self.currentBlock.Hash(), self.Genesis().Hash()
+}
+
func (self *ChainManager) SetProcessor(proc types.BlockProcessor) {
self.processor = proc
}
func (self *ChainManager) State() *state.StateDB {
- return self.CurrentBlock.State()
+ return state.New(self.CurrentBlock().Trie())
}
func (self *ChainManager) TransState() *state.StateDB {
@@ -87,46 +146,48 @@ func (self *ChainManager) TransState() *state.StateDB {
func (bc *ChainManager) setLastBlock() {
data, _ := ethutil.Config.Db.Get([]byte("LastBlock"))
if len(data) != 0 {
- // Prep genesis
- AddTestNetFunds(bc.genesisBlock)
-
- block := types.NewBlockFromBytes(data)
- bc.CurrentBlock = block
- bc.LastBlockHash = block.Hash()
- bc.LastBlockNumber = block.Number.Uint64()
+ var block types.Block
+ 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(ethutil.Config.Db.LastKnownTD())
+ bc.td = ethutil.BigD(ethutil.Config.Db.LastKnownTD())
} else {
bc.Reset()
}
- chainlogger.Infof("Last block (#%d) %x\n", bc.LastBlockNumber, bc.CurrentBlock.Hash())
+ chainlogger.Infof("Last block (#%d) %x\n", bc.lastBlockNumber, bc.currentBlock.Hash())
}
// Block creation & chain handling
func (bc *ChainManager) NewBlock(coinbase []byte) *types.Block {
- var root interface{}
- hash := ZeroHash256
+ bc.mu.RLock()
+ defer bc.mu.RUnlock()
+
+ var root []byte
+ parentHash := ZeroHash256
if bc.CurrentBlock != nil {
- root = bc.CurrentBlock.Root()
- hash = bc.LastBlockHash
+ root = bc.currentBlock.Header().Root
+ parentHash = bc.lastBlockHash
}
- block := types.CreateBlock(
- root,
- hash,
+ block := types.NewBlock(
+ parentHash,
coinbase,
+ root,
ethutil.BigPow(2, 32),
nil,
"")
- parent := bc.CurrentBlock
+ parent := bc.currentBlock
if parent != nil {
- block.Difficulty = CalcDifficulty(block, parent)
- block.Number = new(big.Int).Add(bc.CurrentBlock.Number, ethutil.Big1)
- block.GasLimit = block.CalcGasLimit(bc.CurrentBlock)
+ header := block.Header()
+ header.Difficulty = CalcDifficulty(block, parent)
+ header.Number = new(big.Int).Add(parent.Header().Number, ethutil.Big1)
+ header.GasLimit = CalcGasLimit(parent, block)
}
@@ -134,41 +195,46 @@ func (bc *ChainManager) NewBlock(coinbase []byte) *types.Block {
}
func (bc *ChainManager) Reset() {
- AddTestNetFunds(bc.genesisBlock)
+ bc.mu.Lock()
+ defer bc.mu.Unlock()
+
+ for block := bc.currentBlock; block != nil; block = bc.GetBlock(block.Header().ParentHash) {
+ ethutil.Config.Db.Delete(block.Hash())
+ }
- bc.genesisBlock.Trie().Sync()
// Prepare the genesis block
bc.write(bc.genesisBlock)
bc.insert(bc.genesisBlock)
- bc.CurrentBlock = bc.genesisBlock
-
- bc.SetTotalDifficulty(ethutil.Big("0"))
+ bc.currentBlock = bc.genesisBlock
- // Set the last know difficulty (might be 0x0 as initial value, Genesis)
- bc.TD = ethutil.BigD(ethutil.Config.Db.LastKnownTD())
+ bc.setTotalDifficulty(ethutil.Big("0"))
}
func (self *ChainManager) Export() []byte {
- chainlogger.Infoln("exporting", self.CurrentBlock.Number, "blocks")
+ self.mu.RLock()
+ defer self.mu.RUnlock()
- blocks := make(types.Blocks, int(self.CurrentBlock.Number.Int64())+1)
- for block := self.CurrentBlock; block != nil; block = self.GetBlock(block.PrevHash) {
- blocks[block.Number.Int64()] = block
+ chainlogger.Infof("exporting %v blocks...\n", self.currentBlock.Header().Number)
+
+ blocks := make([]*types.Block, int(self.currentBlock.NumberU64())+1)
+ for block := self.currentBlock; block != nil; block = self.GetBlock(block.Header().ParentHash) {
+ blocks[block.NumberU64()] = block
}
+
return ethutil.Encode(blocks)
}
func (bc *ChainManager) insert(block *types.Block) {
- encodedBlock := block.RlpEncode()
+ encodedBlock := ethutil.Encode(block)
ethutil.Config.Db.Put([]byte("LastBlock"), encodedBlock)
- bc.CurrentBlock = block
- bc.LastBlockHash = block.Hash()
+ bc.currentBlock = block
+ bc.lastBlockHash = block.Hash()
}
func (bc *ChainManager) write(block *types.Block) {
bc.writeBlockInfo(block)
- encodedBlock := block.RlpEncode()
+ encodedBlock := ethutil.Encode(block)
ethutil.Config.Db.Put(block.Hash(), encodedBlock)
}
@@ -183,7 +249,7 @@ func (bc *ChainManager) HasBlock(hash []byte) bool {
return len(data) != 0
}
-func (self *ChainManager) GetChainHashesFromHash(hash []byte, max uint64) (chain [][]byte) {
+func (self *ChainManager) GetBlockHashesFromHash(hash []byte, max uint64) (chain [][]byte) {
block := self.GetBlock(hash)
if block == nil {
return
@@ -193,11 +259,11 @@ func (self *ChainManager) GetChainHashesFromHash(hash []byte, max uint64) (chain
for i := uint64(0); i < max; i++ {
chain = append(chain, block.Hash())
- if block.Number.Cmp(ethutil.Big0) <= 0 {
+ if block.Header().Number.Cmp(ethutil.Big0) <= 0 {
break
}
- block = self.GetBlock(block.PrevHash)
+ block = self.GetBlock(block.Header().ParentHash)
}
return
@@ -208,65 +274,61 @@ func (self *ChainManager) GetBlock(hash []byte) *types.Block {
if len(data) == 0 {
return nil
}
+ var block types.Block
+ if err := rlp.Decode(bytes.NewReader(data), &block); err != nil {
+ fmt.Println(err)
+ return nil
+ }
- return types.NewBlockFromBytes(data)
+ return &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 {
+ self.mu.RLock()
+ defer self.mu.RUnlock()
+
+ block := self.currentBlock
+ for ; block != nil; block = self.GetBlock(block.Header().ParentHash) {
+ if block.Header().Number.Uint64() == num {
break
}
}
- if block != nil && block.Number.Uint64() == 0 && num != 0 {
+ if block != nil && block.Header().Number.Uint64() == 0 && num != 0 {
return nil
}
return block
}
-func (bc *ChainManager) SetTotalDifficulty(td *big.Int) {
+func (bc *ChainManager) setTotalDifficulty(td *big.Int) {
ethutil.Config.Db.Put([]byte("LTD"), td.Bytes())
- bc.TD = td
+ bc.td = td
}
func (self *ChainManager) CalcTotalDiff(block *types.Block) (*big.Int, error) {
- parent := self.GetBlock(block.PrevHash)
+ parent := self.GetBlock(block.Header().ParentHash)
if parent == nil {
- return nil, fmt.Errorf("Unable to calculate total diff without known parent %x", block.PrevHash)
+ return nil, fmt.Errorf("Unable to calculate total diff without known parent %x", block.Header().ParentHash)
}
- parentTd := parent.BlockInfo().TD
+ parentTd := parent.Td
uncleDiff := new(big.Int)
- for _, uncle := range block.Uncles {
+ 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)
+ td = td.Add(td, block.Header().Difficulty)
return td, nil
}
-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)
-
- return bi
-}
-
// Unexported method for writing extra non-essential block info to the db
func (bc *ChainManager) writeBlockInfo(block *types.Block) {
- bc.LastBlockNumber++
- 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())
+ bc.lastBlockNumber++
}
func (bc *ChainManager) Stop() {
@@ -283,23 +345,29 @@ func (self *ChainManager) InsertChain(chain types.Blocks) error {
continue
}
- chainlogger.Infof("block #%v process failed (%x)\n", block.Number, block.Hash()[:4])
+ h := block.Header()
+ chainlogger.Infof("block #%v process failed (%x)\n", h.Number, h.Hash()[:4])
chainlogger.Infoln(block)
chainlogger.Infoln(err)
return err
}
- self.write(block)
- if td.Cmp(self.TD) > 0 {
- if block.Number.Cmp(new(big.Int).Add(self.CurrentBlock.Number, ethutil.Big1)) < 0 {
- chainlogger.Infof("Split detected. New head #%v (%x), was #%v (%x)\n", block.Number, block.Hash()[:4], self.CurrentBlock.Number, self.CurrentBlock.Hash()[:4])
+ self.mu.Lock()
+ {
+ self.write(block)
+ cblock := self.currentBlock
+ 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), was #%v (%x)\n", block.Header().Number, block.Hash()[:4], cblock.Header().Number, cblock.Hash()[:4])
+ }
+
+ self.setTotalDifficulty(td)
+ self.insert(block)
+ self.transState = state.New(cblock.Trie().Copy())
}
- self.SetTotalDifficulty(td)
- self.insert(block)
- self.transState = self.State().Copy()
- //sm.eth.TxPool().RemoveSet(block.Transactions())
}
+ self.mu.Unlock()
self.eventMux.Post(NewBlockEvent{block})
self.eventMux.Post(messages)
diff --git a/core/chain_manager_test.go b/core/chain_manager_test.go
index a84e3ff3b..108718901 100644
--- a/core/chain_manager_test.go
+++ b/core/chain_manager_test.go
@@ -2,18 +2,138 @@ package core
import (
"fmt"
+ "os"
"path"
+ "reflect"
+ "runtime"
+ "strconv"
"testing"
+ "github.com/ethereum/go-ethereum/core/types"
+ "github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/ethutil"
+ "github.com/ethereum/go-ethereum/event"
+ "github.com/ethereum/go-ethereum/rlp"
)
+//var Logger logpkg.LogSystem
+
+//var Log = logpkg.NewLogger("TEST")
+
+func init() {
+ runtime.GOMAXPROCS(runtime.NumCPU())
+ //Logger = logpkg.NewStdLogSystem(os.Stdout, log.LstdFlags, logpkg.DebugLevel)
+ //logpkg.AddLogSystem(Logger)
+
+ ethutil.ReadConfig("/tmp/ethtest", "/tmp/ethtest", "ETH")
+
+ db, err := ethdb.NewMemDatabase()
+ if err != nil {
+ panic("Could not create mem-db, failing")
+ }
+ ethutil.Config.Db = db
+}
+
+func loadChain(fn string, t *testing.T) (types.Blocks, error) {
+ fh, err := os.OpenFile(path.Join("..", "_data", fn), os.O_RDONLY, os.ModePerm)
+ if err != nil {
+ return nil, err
+ }
+ defer fh.Close()
+
+ var chain types.Blocks
+ if err := rlp.Decode(fh, &chain); err != nil {
+ return nil, err
+ }
+
+ return chain, nil
+}
+
+func insertChain(done chan bool, chainMan *ChainManager, chain types.Blocks, t *testing.T) {
+ err := chainMan.InsertChain(chain)
+ done <- true
+ if err != nil {
+ fmt.Println(err)
+ t.FailNow()
+ }
+}
+
func TestChainInsertions(t *testing.T) {
- c1, err := ethutil.ReadAllFile(path.Join("..", "_data", "chain1"))
+ chain1, err := loadChain("valid1", t)
+ if err != nil {
+ fmt.Println(err)
+ t.FailNow()
+ }
+ fmt.Println(len(chain1))
+
+ chain2, err := loadChain("valid2", t)
if err != nil {
fmt.Println(err)
t.FailNow()
}
- data1, _ := ethutil.Decode([]byte(c1), 0)
- fmt.Println(data1)
+
+ var eventMux event.TypeMux
+ chainMan := NewChainManager(&eventMux)
+ txPool := NewTxPool(chainMan, &eventMux)
+ blockMan := NewBlockManager(txPool, chainMan, &eventMux)
+ chainMan.SetProcessor(blockMan)
+
+ const max = 2
+ done := make(chan bool, max)
+
+ go insertChain(done, chainMan, chain1, t)
+ go insertChain(done, chainMan, chain2, t)
+
+ for i := 0; i < max; i++ {
+ <-done
+ }
+
+ if reflect.DeepEqual(chain2[len(chain2)-1], chainMan.CurrentBlock()) {
+ t.Error("chain2 is canonical and shouldn't be")
+ }
+
+ if !reflect.DeepEqual(chain1[len(chain1)-1], chainMan.CurrentBlock()) {
+ t.Error("chain1 isn't canonical and should be")
+ }
+}
+
+func TestChainMultipleInsertions(t *testing.T) {
+ const max = 4
+ chains := make([]types.Blocks, max)
+ var longest int
+ for i := 0; i < max; i++ {
+ var err error
+ name := "valid" + strconv.Itoa(i+1)
+ chains[i], err = loadChain(name, t)
+ if len(chains[i]) >= len(chains[longest]) {
+ longest = i
+ }
+ fmt.Println("loaded", name, "with a length of", len(chains[i]))
+ if err != nil {
+ fmt.Println(err)
+ t.FailNow()
+ }
+ }
+
+ var eventMux event.TypeMux
+ chainMan := NewChainManager(&eventMux)
+ txPool := NewTxPool(chainMan, &eventMux)
+ blockMan := NewBlockManager(txPool, chainMan, &eventMux)
+ chainMan.SetProcessor(blockMan)
+ done := make(chan bool, max)
+ for i, chain := range chains {
+ var i int = i
+ go func() {
+ insertChain(done, chainMan, chain, t)
+ fmt.Println(i, "done")
+ }()
+ }
+
+ for i := 0; i < max; i++ {
+ <-done
+ }
+
+ if !reflect.DeepEqual(chains[longest][len(chains[longest])-1], chainMan.CurrentBlock()) {
+ t.Error("Invalid canonical chain")
+ }
}
diff --git a/core/events.go b/core/events.go
index deeba3e98..fe106da49 100644
--- a/core/events.go
+++ b/core/events.go
@@ -10,3 +10,6 @@ type TxPostEvent struct{ Tx *types.Transaction }
// NewBlockEvent is posted when a block has been imported.
type NewBlockEvent struct{ Block *types.Block }
+
+// NewMinedBlockEvent is posted when a block has been imported.
+type NewMinedBlockEvent struct{ Block *types.Block }
diff --git a/core/execution.go b/core/execution.go
index 58d46c509..b7eead0dd 100644
--- a/core/execution.go
+++ b/core/execution.go
@@ -3,22 +3,21 @@ package core
import (
"fmt"
"math/big"
+ "time"
- "github.com/ethereum/go-ethereum/ethutil"
"github.com/ethereum/go-ethereum/state"
"github.com/ethereum/go-ethereum/vm"
)
type Execution struct {
- vm vm.VirtualMachine
+ env vm.Environment
address, input []byte
Gas, price, value *big.Int
- object *state.StateObject
SkipTransfer bool
}
-func NewExecution(vm vm.VirtualMachine, address, input []byte, gas, gasPrice, value *big.Int) *Execution {
- return &Execution{vm: vm, address: address, input: input, Gas: gas, price: gasPrice, value: value}
+func NewExecution(env vm.Environment, address, input []byte, gas, gasPrice, value *big.Int) *Execution {
+ return &Execution{env: env, address: address, input: input, Gas: gas, price: gasPrice, value: value}
}
func (self *Execution) Addr() []byte {
@@ -27,14 +26,19 @@ func (self *Execution) Addr() []byte {
func (self *Execution) Call(codeAddr []byte, caller vm.ClosureRef) ([]byte, error) {
// Retrieve the executing code
- code := self.vm.Env().State().GetCode(codeAddr)
+ code := self.env.State().GetCode(codeAddr)
return self.exec(code, codeAddr, caller)
}
func (self *Execution) exec(code, contextAddr []byte, caller vm.ClosureRef) (ret []byte, err error) {
- env := self.vm.Env()
- chainlogger.Debugf("pre state %x\n", env.State().Root())
+ env := self.env
+ evm := vm.New(env, vm.DebugVmTy)
+
+ if env.Depth() == vm.MaxCallDepth {
+ // Consume all gas (by not returning it) and return a depth error
+ return nil, vm.DepthError{}
+ }
from, to := env.State().GetStateObject(caller.Address()), env.State().GetOrNewStateObject(self.address)
// Skipping transfer is used on testing for the initial call
@@ -49,32 +53,19 @@ func (self *Execution) exec(code, contextAddr []byte, caller vm.ClosureRef) (ret
}
snapshot := env.State().Copy()
- defer func() {
- if vm.IsDepthErr(err) || vm.IsOOGErr(err) {
- env.State().Set(snapshot)
- }
- chainlogger.Debugf("post state %x\n", env.State().Root())
- }()
-
- self.object = to
- // Pre-compiled contracts (address.go) 1, 2 & 3.
- naddr := ethutil.BigD(contextAddr).Uint64()
- if p := vm.Precompiled[naddr]; p != nil {
- if self.Gas.Cmp(p.Gas(len(self.input))) >= 0 {
- ret = p.Call(self.input)
- self.vm.Printf("NATIVE_FUNC(%x) => %x", naddr, ret)
- self.vm.Endl()
- }
- } else {
- ret, err = self.vm.Run(to, caller, code, self.value, self.Gas, self.price, self.input)
+ start := time.Now()
+ ret, err = evm.Run(to, caller, code, self.value, self.Gas, self.price, self.input)
+ if err != nil {
+ env.State().Set(snapshot)
}
+ chainlogger.Debugf("vm took %v\n", time.Since(start))
return
}
func (self *Execution) Create(caller vm.ClosureRef) (ret []byte, err error, account *state.StateObject) {
ret, err = self.exec(self.input, nil, caller)
- account = self.vm.Env().State().GetStateObject(self.address)
+ account = self.env.State().GetStateObject(self.address)
return
}
diff --git a/core/filter.go b/core/filter.go
index fe3665bf3..7c34748df 100644
--- a/core/filter.go
+++ b/core/filter.go
@@ -76,13 +76,14 @@ func (self *Filter) SetSkip(skip int) {
// Run filters messages with the current parameters set
func (self *Filter) Find() []*state.Message {
+ earliestBlock := self.eth.ChainManager().CurrentBlock()
var earliestBlockNo uint64 = uint64(self.earliest)
if self.earliest == -1 {
- earliestBlockNo = self.eth.ChainManager().CurrentBlock.Number.Uint64()
+ earliestBlockNo = earliestBlock.NumberU64()
}
var latestBlockNo uint64 = uint64(self.latest)
if self.latest == -1 {
- latestBlockNo = self.eth.ChainManager().CurrentBlock.Number.Uint64()
+ latestBlockNo = earliestBlock.NumberU64()
}
var (
@@ -93,7 +94,7 @@ func (self *Filter) Find() []*state.Message {
for i := 0; !quit && block != nil; i++ {
// Quit on latest
switch {
- case block.Number.Uint64() == earliestBlockNo, block.Number.Uint64() == 0:
+ case block.NumberU64() == earliestBlockNo, block.NumberU64() == 0:
quit = true
case self.max <= len(messages):
break
@@ -113,7 +114,7 @@ func (self *Filter) Find() []*state.Message {
messages = append(messages, self.FilterMessages(msgs)...)
}
- block = self.eth.ChainManager().GetBlock(block.PrevHash)
+ block = self.eth.ChainManager().GetBlock(block.ParentHash())
}
skip := int(math.Min(float64(len(messages)), float64(self.skip)))
@@ -176,7 +177,7 @@ func (self *Filter) bloomFilter(block *types.Block) bool {
var fromIncluded, toIncluded bool
if len(self.from) > 0 {
for _, from := range self.from {
- if types.BloomLookup(block.LogsBloom, from) || bytes.Equal(block.Coinbase, from) {
+ if types.BloomLookup(block.Bloom(), from) || bytes.Equal(block.Coinbase(), from) {
fromIncluded = true
break
}
@@ -187,7 +188,7 @@ func (self *Filter) bloomFilter(block *types.Block) bool {
if len(self.to) > 0 {
for _, to := range self.to {
- if types.BloomLookup(block.LogsBloom, ethutil.U256(new(big.Int).Add(ethutil.Big1, ethutil.BigD(to))).Bytes()) || bytes.Equal(block.Coinbase, to) {
+ if types.BloomLookup(block.Bloom(), ethutil.U256(new(big.Int).Add(ethutil.Big1, ethutil.BigD(to))).Bytes()) || bytes.Equal(block.Coinbase(), to) {
toIncluded = true
break
}
diff --git a/core/filter_test.go b/core/filter_test.go
index d53b835b7..9a8bc9592 100644
--- a/core/filter_test.go
+++ b/core/filter_test.go
@@ -1,7 +1 @@
package core
-
-// import "testing"
-
-// func TestFilter(t *testing.T) {
-// NewFilter(NewTestManager())
-// }
diff --git a/core/genesis.go b/core/genesis.go
index 707154759..10b40516f 100644
--- a/core/genesis.go
+++ b/core/genesis.go
@@ -3,8 +3,10 @@ package core
import (
"math/big"
+ "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethutil"
+ "github.com/ethereum/go-ethereum/state"
)
/*
@@ -17,36 +19,35 @@ var ZeroHash512 = make([]byte, 64)
var EmptyShaList = crypto.Sha3(ethutil.Encode([]interface{}{}))
var EmptyListRoot = crypto.Sha3(ethutil.Encode(""))
-var GenesisHeader = []interface{}{
- // Previous hash (none)
- ZeroHash256,
- // Empty uncles
- EmptyShaList,
- // Coinbase
- ZeroHash160,
- // Root state
- EmptyShaList,
- // tx root
- EmptyListRoot,
- // receipt root
- EmptyListRoot,
- // bloom
- ZeroHash512,
- // Difficulty
- //ethutil.BigPow(2, 22),
- big.NewInt(131072),
- // Number
- ethutil.Big0,
- // Block upper gas bound
- big.NewInt(1000000),
- // Block gas used
- ethutil.Big0,
- // Time
- ethutil.Big0,
- // Extra
- nil,
- // Nonce
- crypto.Sha3(big.NewInt(42).Bytes()),
-}
+func GenesisBlock() *types.Block {
+ genesis := types.NewBlock(ZeroHash256, ZeroHash160, nil, big.NewInt(131072), crypto.Sha3(big.NewInt(42).Bytes()), "")
+ genesis.Header().Number = ethutil.Big0
+ genesis.Header().GasLimit = big.NewInt(1000000)
+ genesis.Header().GasUsed = ethutil.Big0
+ genesis.Header().Time = 0
+
+ genesis.SetUncles([]*types.Header{})
+ genesis.SetTransactions(types.Transactions{})
+ genesis.SetReceipts(types.Receipts{})
-var Genesis = []interface{}{GenesisHeader, []interface{}{}, []interface{}{}}
+ statedb := state.New(genesis.Trie())
+ for _, addr := range []string{
+ "51ba59315b3a95761d0863b05ccc7a7f54703d99",
+ "e4157b34ea9615cfbde6b4fda419828124b70c78",
+ "b9c015918bdaba24b4ff057a92a3873d6eb201be",
+ "6c386a4b26f73c802f34673f7248bb118f97424a",
+ "cd2a3d9f938e13cd947ec05abc7fe734df8dd826",
+ "2ef47100e0787b915105fd5e3f4ff6752079d5cb",
+ "e6716f9544a56c530d868e4bfbacb172315bdead",
+ "1a26338f0d905e295fccb71fa9ea849ffa12aaf4",
+ } {
+ codedAddr := ethutil.Hex2Bytes(addr)
+ account := statedb.GetAccount(codedAddr)
+ account.SetBalance(ethutil.Big("1606938044258990275541962092341162602522202993782792835301376")) //ethutil.BigPow(2, 200)
+ statedb.UpdateStateObject(account)
+ }
+ statedb.Sync()
+ genesis.Header().Root = statedb.Root()
+
+ return genesis
+}
diff --git a/core/helper_test.go b/core/helper_test.go
index b340144fd..b8bf254d7 100644
--- a/core/helper_test.go
+++ b/core/helper_test.go
@@ -9,7 +9,7 @@ import (
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/ethutil"
"github.com/ethereum/go-ethereum/event"
- "github.com/ethereum/go-ethereum/wire"
+ "github.com/ethereum/go-ethereum/p2p"
)
// Implement our EthTest Manager
@@ -54,11 +54,11 @@ func (tm *TestManager) TxPool() *TxPool {
func (tm *TestManager) EventMux() *event.TypeMux {
return tm.eventMux
}
-func (tm *TestManager) Broadcast(msgType wire.MsgType, data []interface{}) {
+func (tm *TestManager) Broadcast(msgType p2p.Msg, data []interface{}) {
fmt.Println("Broadcast not implemented")
}
-func (tm *TestManager) ClientIdentity() wire.ClientIdentity {
+func (tm *TestManager) ClientIdentity() p2p.ClientIdentity {
return nil
}
func (tm *TestManager) KeyManager() *crypto.KeyManager {
diff --git a/core/state_transition.go b/core/state_transition.go
index 820ba66e6..7b7026c29 100644
--- a/core/state_transition.go
+++ b/core/state_transition.go
@@ -5,6 +5,8 @@ import (
"math/big"
"github.com/ethereum/go-ethereum/core/types"
+ "github.com/ethereum/go-ethereum/crypto"
+ "github.com/ethereum/go-ethereum/ethutil"
"github.com/ethereum/go-ethereum/state"
"github.com/ethereum/go-ethereum/vm"
)
@@ -27,48 +29,69 @@ import (
*/
type StateTransition struct {
coinbase, receiver []byte
- tx *types.Transaction
+ msg Message
gas, gasPrice *big.Int
+ initialGas *big.Int
value *big.Int
data []byte
state *state.StateDB
block *types.Block
cb, rec, sen *state.StateObject
+
+ Env vm.Environment
}
-func NewStateTransition(coinbase *state.StateObject, tx *types.Transaction, state *state.StateDB, block *types.Block) *StateTransition {
- return &StateTransition{coinbase.Address(), tx.Recipient, tx, new(big.Int), new(big.Int).Set(tx.GasPrice), tx.Value, tx.Data, state, block, coinbase, nil, nil}
+type Message interface {
+ Hash() []byte
+
+ From() []byte
+ To() []byte
+
+ GasPrice() *big.Int
+ Gas() *big.Int
+ Value() *big.Int
+
+ Nonce() uint64
+ Data() []byte
}
-func (self *StateTransition) Coinbase() *state.StateObject {
- if self.cb != nil {
- return self.cb
- }
+func AddressFromMessage(msg Message) []byte {
+ // Generate a new address
+ return crypto.Sha3(ethutil.NewValue([]interface{}{msg.From(), msg.Nonce()}).Encode())[12:]
+}
- self.cb = self.state.GetOrNewStateObject(self.coinbase)
- return self.cb
+func MessageCreatesContract(msg Message) bool {
+ return len(msg.To()) == 0
}
-func (self *StateTransition) Sender() *state.StateObject {
- if self.sen != nil {
- return self.sen
- }
- self.sen = self.state.GetOrNewStateObject(self.tx.Sender())
+func MessageGasValue(msg Message) *big.Int {
+ return new(big.Int).Mul(msg.Gas(), msg.GasPrice())
+}
- return self.sen
+func NewStateTransition(coinbase *state.StateObject, msg Message, state *state.StateDB, block *types.Block) *StateTransition {
+ return &StateTransition{coinbase.Address(), msg.To(), msg, new(big.Int), new(big.Int).Set(msg.GasPrice()), new(big.Int), msg.Value(), msg.Data(), state, block, coinbase, nil, nil, nil}
}
-func (self *StateTransition) Receiver() *state.StateObject {
- if self.tx != nil && self.tx.CreatesContract() {
- return nil
- }
- if self.rec != nil {
- return self.rec
+func (self *StateTransition) VmEnv() vm.Environment {
+ if self.Env == nil {
+ self.Env = NewEnv(self.state, self.msg, self.block)
}
- self.rec = self.state.GetOrNewStateObject(self.tx.Recipient)
- return self.rec
+ return self.Env
+}
+
+func (self *StateTransition) Coinbase() *state.StateObject {
+ return self.state.GetOrNewStateObject(self.coinbase)
+}
+func (self *StateTransition) From() *state.StateObject {
+ return self.state.GetOrNewStateObject(self.msg.From())
+}
+func (self *StateTransition) To() *state.StateObject {
+ if self.msg != nil && MessageCreatesContract(self.msg) {
+ return nil
+ }
+ return self.state.GetOrNewStateObject(self.msg.To())
}
func (self *StateTransition) UseGas(amount *big.Int) error {
@@ -87,41 +110,33 @@ func (self *StateTransition) AddGas(amount *big.Int) {
func (self *StateTransition) BuyGas() error {
var err error
- sender := self.Sender()
- if sender.Balance().Cmp(self.tx.GasValue()) < 0 {
- return fmt.Errorf("Insufficient funds to pre-pay gas. Req %v, has %v", self.tx.GasValue(), sender.Balance())
+ sender := self.From()
+ if sender.Balance().Cmp(MessageGasValue(self.msg)) < 0 {
+ return fmt.Errorf("insufficient ETH for gas (%x). Req %v, has %v", sender.Address()[:4], MessageGasValue(self.msg), sender.Balance())
}
coinbase := self.Coinbase()
- err = coinbase.BuyGas(self.tx.Gas, self.tx.GasPrice)
+ err = coinbase.BuyGas(self.msg.Gas(), self.msg.GasPrice())
if err != nil {
return err
}
- self.AddGas(self.tx.Gas)
- sender.SubAmount(self.tx.GasValue())
+ self.AddGas(self.msg.Gas())
+ self.initialGas.Set(self.msg.Gas())
+ sender.SubAmount(MessageGasValue(self.msg))
return nil
}
-func (self *StateTransition) RefundGas() {
- coinbase, sender := self.Coinbase(), self.Sender()
- coinbase.RefundGas(self.gas, self.tx.GasPrice)
-
- // Return remaining gas
- remaining := new(big.Int).Mul(self.gas, self.tx.GasPrice)
- sender.AddAmount(remaining)
-}
-
func (self *StateTransition) preCheck() (err error) {
var (
- tx = self.tx
- sender = self.Sender()
+ msg = self.msg
+ sender = self.From()
)
// Make sure this transaction's nonce is correct
- if sender.Nonce != tx.Nonce {
- return NonceError(tx.Nonce, sender.Nonce)
+ if sender.Nonce != msg.Nonce() {
+ return NonceError(msg.Nonce(), sender.Nonce)
}
// Pre-pay gas / Buy gas of the coinbase account
@@ -132,8 +147,8 @@ func (self *StateTransition) preCheck() (err error) {
return nil
}
-func (self *StateTransition) TransitionState() (err error) {
- statelogger.Debugf("(~) %x\n", self.tx.Hash())
+func (self *StateTransition) TransitionState() (ret []byte, err error) {
+ statelogger.Debugf("(~) %x\n", self.msg.Hash())
// XXX Transactions after this point are considered valid.
if err = self.preCheck(); err != nil {
@@ -141,8 +156,8 @@ func (self *StateTransition) TransitionState() (err error) {
}
var (
- tx = self.tx
- sender = self.Sender()
+ msg = self.msg
+ sender = self.From()
)
defer self.RefundGas()
@@ -168,30 +183,56 @@ func (self *StateTransition) TransitionState() (err error) {
return
}
- var ret []byte
- vmenv := NewEnv(self.state, self.tx, self.block)
+ vmenv := self.VmEnv()
var ref vm.ClosureRef
- if tx.CreatesContract() {
- self.rec = MakeContract(tx, self.state)
-
- ret, err, ref = vmenv.Create(sender, self.rec.Address(), self.tx.Data, self.gas, self.gasPrice, self.value)
- ref.SetCode(ret)
+ if MessageCreatesContract(msg) {
+ contract := MakeContract(msg, self.state)
+ ret, err, ref = vmenv.Create(sender, contract.Address(), self.msg.Data(), self.gas, self.gasPrice, self.value)
+ if err == nil {
+ dataGas := big.NewInt(int64(len(ret)))
+ dataGas.Mul(dataGas, vm.GasCreateByte)
+ if err = self.UseGas(dataGas); err == nil {
+ //self.state.SetCode(ref.Address(), ret)
+ ref.SetCode(ret)
+ }
+ }
} else {
- ret, err = vmenv.Call(self.Sender(), self.Receiver().Address(), self.tx.Data, self.gas, self.gasPrice, self.value)
+ ret, err = vmenv.Call(self.From(), self.To().Address(), self.msg.Data(), self.gas, self.gasPrice, self.value)
}
+
if err != nil {
- statelogger.Debugln(err)
+ self.UseGas(self.gas)
}
return
}
// Converts an transaction in to a state object
-func MakeContract(tx *types.Transaction, state *state.StateDB) *state.StateObject {
- addr := tx.CreationAddress(state)
+func MakeContract(msg Message, state *state.StateDB) *state.StateObject {
+ addr := AddressFromMessage(msg)
contract := state.GetOrNewStateObject(addr)
- contract.InitCode = tx.Data
+ contract.InitCode = msg.Data()
return contract
}
+
+func (self *StateTransition) RefundGas() {
+ coinbase, sender := self.Coinbase(), self.From()
+ // Return remaining gas
+ remaining := new(big.Int).Mul(self.gas, self.msg.GasPrice())
+ sender.AddAmount(remaining)
+
+ uhalf := new(big.Int).Div(self.GasUsed(), ethutil.Big2)
+ for addr, ref := range self.state.Refunds() {
+ refund := ethutil.BigMin(uhalf, ref)
+ self.gas.Add(self.gas, refund)
+ self.state.AddBalance([]byte(addr), refund.Mul(refund, self.msg.GasPrice()))
+ }
+
+ coinbase.RefundGas(self.gas, self.msg.GasPrice())
+}
+
+func (self *StateTransition) GasUsed() *big.Int {
+ return new(big.Int).Sub(self.initialGas, self.gas)
+}
diff --git a/core/transaction_pool.go b/core/transaction_pool.go
index 7166d35e8..1149d4cfb 100644
--- a/core/transaction_pool.go
+++ b/core/transaction_pool.go
@@ -8,9 +8,9 @@ import (
"sync"
"github.com/ethereum/go-ethereum/core/types"
+ "github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/logger"
"github.com/ethereum/go-ethereum/state"
- "github.com/ethereum/go-ethereum/wire"
)
var txplogger = logger.NewLogger("TXP")
@@ -18,7 +18,9 @@ var txplogger = logger.NewLogger("TXP")
const txPoolQueueSize = 50
type TxPoolHook chan *types.Transaction
-type TxMsgTy byte
+type TxMsg struct {
+ Tx *types.Transaction
+}
const (
minGasPrice = 1000000
@@ -26,11 +28,6 @@ const (
var MinGasPrice = big.NewInt(10000000000000)
-type TxMsg struct {
- Tx *types.Transaction
- Type TxMsgTy
-}
-
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.(*types.Transaction), e) {
@@ -61,7 +58,6 @@ type TxProcessor interface {
// pool is being drained or synced for whatever reason the transactions
// will simple queue up and handled when the mutex is freed.
type TxPool struct {
- Ethereum EthManager
// The mutex for accessing the Tx pool.
mutex sync.Mutex
// Queueing channel for reading and writing incoming
@@ -75,14 +71,18 @@ type TxPool struct {
SecondaryProcessor TxProcessor
subscribers []chan TxMsg
+
+ chainManager *ChainManager
+ eventMux *event.TypeMux
}
-func NewTxPool(ethereum EthManager) *TxPool {
+func NewTxPool(chainManager *ChainManager, eventMux *event.TypeMux) *TxPool {
return &TxPool{
- pool: list.New(),
- queueChan: make(chan *types.Transaction, txPoolQueueSize),
- quit: make(chan bool),
- Ethereum: ethereum,
+ pool: list.New(),
+ queueChan: make(chan *types.Transaction, txPoolQueueSize),
+ quit: make(chan bool),
+ chainManager: chainManager,
+ eventMux: eventMux,
}
}
@@ -94,20 +94,20 @@ func (pool *TxPool) addTransaction(tx *types.Transaction) {
pool.pool.PushBack(tx)
// Broadcast the transaction to the rest of the peers
- pool.Ethereum.Broadcast(wire.MsgTxTy, []interface{}{tx.RlpData()})
+ pool.eventMux.Post(TxPreEvent{tx})
}
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
+ block := pool.chainManager.CurrentBlock
// Something has gone horribly wrong if this happens
if block == nil {
return fmt.Errorf("No last block on the block chain")
}
- if len(tx.Recipient) != 0 && len(tx.Recipient) != 20 {
- return fmt.Errorf("Invalid recipient. len = %d", len(tx.Recipient))
+ if len(tx.To()) != 0 && len(tx.To()) != 20 {
+ return fmt.Errorf("Invalid recipient. len = %d", len(tx.To()))
}
v, _, _ := tx.Curve()
@@ -116,19 +116,17 @@ func (pool *TxPool) ValidateTransaction(tx *types.Transaction) error {
}
// Get the sender
- sender := pool.Ethereum.ChainManager().State().GetAccount(tx.Sender())
+ senderAddr := tx.From()
+ if senderAddr == nil {
+ return fmt.Errorf("invalid sender")
+ }
+ sender := pool.chainManager.State().GetAccount(senderAddr)
- totAmount := new(big.Int).Set(tx.Value)
+ totAmount := new(big.Int).Set(tx.Value())
// Make sure there's enough in the sender's account. Having insufficient
// funds won't invalidate this transaction but simple ignores it.
if sender.Balance().Cmp(totAmount) < 0 {
- return fmt.Errorf("Insufficient amount in sender's (%x) account", tx.Sender())
- }
-
- if tx.IsContract() {
- if tx.GasPrice.Cmp(big.NewInt(minGasPrice)) < 0 {
- return fmt.Errorf("Gasprice too low, %s given should be at least %d.", tx.GasPrice, minGasPrice)
- }
+ return fmt.Errorf("Insufficient amount in sender's (%x) account", tx.From())
}
// Increment the nonce making each tx valid only once to prevent replay
@@ -154,13 +152,10 @@ func (self *TxPool) Add(tx *types.Transaction) error {
self.addTransaction(tx)
- tmp := make([]byte, 4)
- copy(tmp, tx.Recipient)
-
- txplogger.Debugf("(t) %x => %x (%v) %x\n", tx.Sender()[:4], tmp, tx.Value, tx.Hash())
+ txplogger.Debugf("(t) %x => %x (%v) %x\n", tx.From()[:4], tx.To()[:4], tx.Value, tx.Hash())
// Notify the subscribers
- go self.Ethereum.EventMux().Post(TxPreEvent{tx})
+ go self.eventMux.Post(TxPreEvent{tx})
return nil
}
@@ -169,7 +164,17 @@ func (self *TxPool) Size() int {
return self.pool.Len()
}
-func (pool *TxPool) CurrentTransactions() []*types.Transaction {
+func (self *TxPool) AddTransactions(txs []*types.Transaction) {
+ for _, tx := range txs {
+ if err := self.Add(tx); err != nil {
+ txplogger.Infoln(err)
+ } else {
+ txplogger.Infof("tx %x\n", tx.Hash()[0:4])
+ }
+ }
+}
+
+func (pool *TxPool) GetTransactions() []*types.Transaction {
pool.mutex.Lock()
defer pool.mutex.Unlock()
@@ -192,9 +197,9 @@ func (pool *TxPool) RemoveInvalid(state *state.StateDB) {
for e := pool.pool.Front(); e != nil; e = e.Next() {
tx := e.Value.(*types.Transaction)
- sender := state.GetAccount(tx.Sender())
+ sender := state.GetAccount(tx.From())
err := pool.ValidateTransaction(tx)
- if err != nil || sender.Nonce >= tx.Nonce {
+ if err != nil || sender.Nonce >= tx.Nonce() {
pool.pool.Remove(e)
}
}
@@ -216,7 +221,7 @@ func (self *TxPool) RemoveSet(txs types.Transactions) {
}
func (pool *TxPool) Flush() []*types.Transaction {
- txList := pool.CurrentTransactions()
+ txList := pool.GetTransactions()
// Recreate a new list all together
// XXX Is this the fastest way?
diff --git a/core/types/block.go b/core/types/block.go
index 0108bd586..7b4695f73 100644
--- a/core/types/block.go
+++ b/core/types/block.go
@@ -9,408 +9,259 @@ import (
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethutil"
+ "github.com/ethereum/go-ethereum/ptrie"
+ "github.com/ethereum/go-ethereum/rlp"
"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 {
+type Header struct {
// Hash to the previous block
- PrevHash ethutil.Bytes
+ ParentHash ethutil.Bytes
// Uncles of this block
- Uncles Blocks
- UncleSha []byte
+ UncleHash []byte
// The coin base address
Coinbase []byte
// Block Trie state
- //state *ethutil.Trie
- state *state.StateDB
+ Root []byte
+ // Tx sha
+ TxHash []byte
+ // Receipt sha
+ ReceiptHash []byte
+ // Bloom
+ Bloom []byte
// Difficulty for the current block
Difficulty *big.Int
- // Creation time
- Time int64
// The block number
Number *big.Int
// Gas limit
GasLimit *big.Int
// Gas used
GasUsed *big.Int
+ // Creation time
+ Time uint64
// 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
-
- Reward *big.Int
}
-func NewBlockFromBytes(raw []byte) *Block {
- block := &Block{}
- block.RlpDecode(raw)
+func (self *Header) rlpData(withNonce bool) []interface{} {
+ fields := []interface{}{self.ParentHash, self.UncleHash, self.Coinbase, self.Root, self.TxHash, self.ReceiptHash, self.Bloom, self.Difficulty, self.Number, self.GasLimit, self.GasUsed, self.Time, self.Extra}
+ if withNonce {
+ fields = append(fields, self.Nonce)
+ }
- return block
+ return fields
}
-// New block takes a raw encoded string
-func NewBlockFromRlpValue(rlpValue *ethutil.Value) *Block {
- block := &Block{}
- block.RlpValueDecode(rlpValue)
+func (self *Header) RlpData() interface{} {
+ return self.rlpData(true)
+}
- return block
+func (self *Header) Hash() []byte {
+ return crypto.Sha3(ethutil.Encode(self.rlpData(true)))
}
-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(),
+func (self *Header) HashNoNonce() []byte {
+ return crypto.Sha3(ethutil.Encode(self.rlpData(false)))
+}
+
+type Block struct {
+ header *Header
+ uncles []*Header
+ transactions Transactions
+ Td *big.Int
+
+ receipts Receipts
+ Reward *big.Int
+}
+
+func NewBlock(parentHash []byte, coinbase []byte, root []byte, difficulty *big.Int, nonce []byte, extra string) *Block {
+ header := &Header{
+ Root: root,
+ ParentHash: parentHash,
+ Coinbase: coinbase,
+ Difficulty: difficulty,
+ Nonce: nonce,
+ Time: uint64(time.Now().Unix()),
Extra: extra,
- UncleSha: nil,
GasUsed: new(big.Int),
GasLimit: new(big.Int),
}
- block.SetUncles([]*Block{})
- block.state = state.New(trie.New(ethutil.Config.Db, root))
+ block := &Block{header: header, Reward: new(big.Int)}
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.StateDB {
- return block.state
+func NewBlockWithHeader(header *Header) *Block {
+ return &Block{header: header}
}
-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)
+func (self *Block) DecodeRLP(s *rlp.Stream) error {
+ if _, err := s.List(); err != nil {
+ return err
}
- // ((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
- }
+ var header Header
+ if err := s.Decode(&header); err != nil {
+ return err
}
- 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()
+ var transactions []*Transaction
+ if err := s.Decode(&transactions); err != nil {
+ return err
}
- return encR
-}
+ var uncleHeaders []*Header
+ if err := s.Decode(&uncleHeaders); err != nil {
+ return err
+ }
-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()
+ var tdBytes []byte
+ if err := s.Decode(&tdBytes); err != nil {
+ // If this block comes from the network that's fine. If loaded from disk it should be there
+ // Blocks don't store their Td when propagated over the network
+ } else {
+ self.Td = ethutil.BigD(tdBytes)
}
- return uncles
-}
+ if err := s.ListEnd(); err != nil {
+ return err
+ }
-func (block *Block) SetUncles(uncles []*Block) {
- block.Uncles = uncles
- block.UncleSha = crypto.Sha3(ethutil.Encode(block.rlpUncles()))
-}
+ self.header = &header
+ self.uncles = uncleHeaders
+ self.transactions = transactions
-func (self *Block) SetReceipts(receipts Receipts) {
- self.receipts = receipts
- self.ReceiptSha = DeriveSha(receipts)
- self.LogsBloom = CreateBloom(receipts)
+ return nil
}
-func (self *Block) SetTransactions(txs Transactions) {
- self.transactions = txs
- self.TxSha = DeriveSha(txs)
+func (self *Block) Header() *Header {
+ return self.header
}
-func (block *Block) Value() *ethutil.Value {
- return ethutil.NewValue([]interface{}{block.header(), block.transactions, block.rlpUncles()})
+func (self *Block) Uncles() []*Header {
+ return self.uncles
}
-func (block *Block) RlpEncode() []byte {
- // Encode a slice interface which contains the header and the list of
- // transactions.
- return block.Value().Encode()
+func (self *Block) SetUncles(uncleHeaders []*Header) {
+ self.uncles = uncleHeaders
+ self.header.UncleHash = crypto.Sha3(ethutil.Encode(uncleHeaders))
}
-func (block *Block) RlpDecode(data []byte) {
- rlpValue := ethutil.NewValueFromBytes(data)
- block.RlpValueDecode(rlpValue)
+func (self *Block) Transactions() Transactions {
+ return self.transactions
}
-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) Transaction(hash []byte) *Transaction {
+ for _, transaction := range self.transactions {
+ if bytes.Equal(hash, transaction.Hash()) {
+ return transaction
}
}
-
+ return nil
}
-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.GasLimit = header.Get(9).BigInt()
- self.GasUsed = header.Get(10).BigInt()
- self.Time = int64(header.Get(11).BigInt().Uint64())
- self.Extra = header.Get(12).Str()
- self.Nonce = header.Get(13).Bytes()
+func (self *Block) SetTransactions(transactions Transactions) {
+ self.transactions = transactions
+ self.header.TxHash = DeriveSha(transactions)
}
-func NewUncleBlockFromValue(header *ethutil.Value) *Block {
- block := &Block{}
- block.setHeader(header)
-
- return block
+func (self *Block) Receipts() Receipts {
+ return self.receipts
}
-func (block *Block) Trie() *trie.Trie {
- return block.state.Trie
+func (self *Block) SetReceipts(receipts Receipts) {
+ self.receipts = receipts
+ self.header.ReceiptHash = DeriveSha(receipts)
+ self.header.Bloom = CreateBloom(receipts)
}
-func (block *Block) Root() interface{} {
- return block.state.Root()
+func (self *Block) RlpData() interface{} {
+ return []interface{}{self.header, self.transactions, self.uncles}
+}
+
+func (self *Block) RlpDataForStorage() interface{} {
+ return []interface{}{self.header, self.transactions, self.uncles, self.Td /* TODO receipts */}
+}
+
+// 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) ParentHash() []byte { return self.header.ParentHash }
+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) }
+func (self *Block) GasLimit() *big.Int { return self.header.GasLimit }
+func (self *Block) GasUsed() *big.Int { return self.header.GasUsed }
+func (self *Block) Hash() []byte { return self.header.Hash() }
+func (self *Block) Trie() *ptrie.Trie { return ptrie.New(self.header.Root, ethutil.Config.Db) }
+func (self *Block) State() *state.StateDB { return state.New(self.Trie()) }
+func (self *Block) Size() ethutil.StorageSize { return ethutil.StorageSize(len(ethutil.Encode(self))) }
+func (self *Block) SetRoot(root []byte) { self.header.Root = root }
+
+// Implement block.Pow
+func (self *Block) Difficulty() *big.Int { return self.header.Difficulty }
+func (self *Block) N() []byte { return self.header.Nonce }
+func (self *Block) HashNoNonce() []byte {
+ return crypto.Sha3(ethutil.Encode(self.header.rlpData(false)))
+}
+
+func (self *Block) String() string {
+ return fmt.Sprintf(`BLOCK(%x): Size: %v {
+Header:
+[
+%v
+]
+Transactions:
+%v
+Uncles:
+%v
+}
+`, self.header.Hash(), self.Size(), self.header, self.transactions, self.uncles)
+}
+
+func (self *Header) String() string {
+ return fmt.Sprintf(`
+ ParentHash: %x
+ UncleHash: %x
+ Coinbase: %x
+ Root: %x
+ TxSha %x
+ ReceiptSha: %x
+ Bloom: %x
+ Difficulty: %v
+ Number: %v
+ GasLimit: %v
+ GasUsed: %v
+ Time: %v
+ Extra: %v
+ Nonce: %x
+`, self.ParentHash, self.UncleHash, self.Coinbase, self.Root, self.TxHash, self.ReceiptHash, self.Bloom, self.Difficulty, self.Number, self.GasLimit, self.GasUsed, self.Time, self.Extra, self.Nonce)
}
-func (block *Block) Diff() *big.Int {
- return block.Difficulty
-}
+type Blocks []*Block
-func (self *Block) Receipts() []*Receipt {
- return self.receipts
-}
+type BlockBy func(b1, b2 *Block) bool
-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 upper gas bound
- block.GasLimit,
- // Block gas used
- block.GasUsed,
- // Time the block was found?
- block.Time,
- // Extra data
- block.Extra,
+func (self BlockBy) Sort(blocks Blocks) {
+ bs := blockSorter{
+ blocks: blocks,
+ by: self,
}
+ sort.Sort(bs)
}
-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
- 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.GasLimit,
- block.GasUsed,
- block.Time,
- block.Extra,
- block.Nonce,
- len(block.transactions),
- )
-}
-
-func (self *Block) Size() ethutil.StorageSize {
- return ethutil.StorageSize(len(self.RlpEncode()))
+type blockSorter struct {
+ blocks Blocks
+ by func(b1, b2 *Block) bool
}
-// Implement RlpEncodable
-func (self *Block) RlpData() interface{} {
- return self.Value().Val
+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]) }
-// Implement pow.Block
-func (self *Block) N() []byte { return self.Nonce }
+func Number(b1, b2 *Block) bool { return b1.Header().Number.Cmp(b2.Header().Number) < 0 }
diff --git a/core/types/block_test.go b/core/types/block_test.go
new file mode 100644
index 000000000..c85708975
--- /dev/null
+++ b/core/types/block_test.go
@@ -0,0 +1,23 @@
+package types
+
+import (
+ "bytes"
+ "testing"
+
+ "github.com/ethereum/go-ethereum/ethdb"
+ "github.com/ethereum/go-ethereum/ethutil"
+ "github.com/ethereum/go-ethereum/rlp"
+)
+
+func init() {
+ ethutil.ReadConfig(".ethtest", "/tmp/ethtest", "")
+ ethutil.Config.Db, _ = ethdb.NewMemDatabase()
+}
+
+func TestNewBlock(t *testing.T) {
+ block := GenesisBlock()
+ data := ethutil.Encode(block)
+
+ var genesis Block
+ err := rlp.Decode(bytes.NewReader(data), &genesis)
+}
diff --git a/core/types/derive_sha.go b/core/types/derive_sha.go
index 1897ff198..0beb19670 100644
--- a/core/types/derive_sha.go
+++ b/core/types/derive_sha.go
@@ -2,7 +2,7 @@ package types
import (
"github.com/ethereum/go-ethereum/ethutil"
- "github.com/ethereum/go-ethereum/trie"
+ "github.com/ethereum/go-ethereum/ptrie"
)
type DerivableList interface {
@@ -11,10 +11,10 @@ type DerivableList interface {
}
func DeriveSha(list DerivableList) []byte {
- trie := trie.New(ethutil.Config.Db, "")
+ trie := ptrie.New(nil, ethutil.Config.Db)
for i := 0; i < list.Len(); i++ {
- trie.Update(string(ethutil.NewValue(i).Encode()), string(list.GetRlp(i)))
+ trie.Update(ethutil.Encode(i), list.GetRlp(i))
}
- return trie.GetRoot()
+ return trie.Root()
}
diff --git a/core/types/transaction.go b/core/types/transaction.go
index 63edef756..59244adc3 100644
--- a/core/types/transaction.go
+++ b/core/types/transaction.go
@@ -1,42 +1,37 @@
package types
import (
+ "bytes"
"fmt"
"math/big"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethutil"
- "github.com/ethereum/go-ethereum/state"
+ "github.com/ethereum/go-ethereum/rlp"
"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
+ AccountNonce uint64
+ Price *big.Int
+ GasLimit *big.Int
+ Recipient []byte
+ Amount *big.Int
+ Payload []byte
+ V uint64
+ R, S []byte
}
-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 NewContractCreationTx(Amount, gasAmount, price *big.Int, data []byte) *Transaction {
+ return NewTransactionMessage(nil, Amount, gasAmount, price, data)
}
-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 NewTransactionMessage(to []byte, Amount, gasAmount, price *big.Int, data []byte) *Transaction {
+ return &Transaction{Recipient: to, Amount: Amount, Price: price, GasLimit: gasAmount, Payload: data}
}
func NewTransactionFromBytes(data []byte) *Transaction {
@@ -46,46 +41,55 @@ func NewTransactionFromBytes(data []byte) *Transaction {
return tx
}
-func NewTransactionFromValue(val *ethutil.Value) *Transaction {
+func NewTransactionFromAmount(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 (tx *Transaction) Hash() []byte {
+ data := []interface{}{tx.AccountNonce, tx.Price, tx.GasLimit, tx.Recipient, tx.Amount, tx.Payload}
+
+ return crypto.Sha3(ethutil.Encode(data))
+}
+
+func (self *Transaction) Data() []byte {
+ return self.Payload
}
-func (self *Transaction) TotalValue() *big.Int {
- v := self.GasValue()
- return v.Add(v, self.Value)
+func (self *Transaction) Gas() *big.Int {
+ return self.GasLimit
}
-func (tx *Transaction) Hash() []byte {
- data := []interface{}{tx.Nonce, tx.GasPrice, tx.Gas, tx.Recipient, tx.Value, tx.Data}
+func (self *Transaction) GasPrice() *big.Int {
+ return self.Price
+}
- return crypto.Sha3(ethutil.NewValue(data).Encode())
+func (self *Transaction) Value() *big.Int {
+ return self.Amount
}
-func (tx *Transaction) CreatesContract() bool {
- return tx.contractCreation
+func (self *Transaction) Nonce() uint64 {
+ return self.AccountNonce
}
-/* Deprecated */
-func (tx *Transaction) IsContract() bool {
- return tx.CreatesContract()
+func (self *Transaction) SetNonce(AccountNonce uint64) {
+ self.AccountNonce = AccountNonce
}
-func (tx *Transaction) CreationAddress(state *state.StateDB) []byte {
- // Generate a new address
- return crypto.Sha3(ethutil.NewValue([]interface{}{tx.Sender(), tx.Nonce}).Encode())[12:]
+func (self *Transaction) From() []byte {
+ return self.sender()
+}
+
+func (self *Transaction) To() []byte {
+ return self.Recipient
}
func (tx *Transaction) Curve() (v byte, r []byte, s []byte) {
- v = tx.v
- r = ethutil.LeftPadBytes(tx.r, 32)
- s = ethutil.LeftPadBytes(tx.s, 32)
+ v = byte(tx.V)
+ r = ethutil.LeftPadBytes(tx.R, 32)
+ s = ethutil.LeftPadBytes(tx.S, 32)
return
}
@@ -106,18 +110,18 @@ func (tx *Transaction) PublicKey() []byte {
sig := append(r, s...)
sig = append(sig, v-27)
- pubkey := crypto.Ecrecover(append(hash, sig...))
- //pubkey, _ := secp256k1.RecoverPubkey(hash, sig)
+ //pubkey := crypto.Ecrecover(append(hash, sig...))
+ pubkey, _ := secp256k1.RecoverPubkey(hash, sig)
return pubkey
}
-func (tx *Transaction) Sender() []byte {
+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 {
+ if len(pubkey) == 0 || pubkey[0] != 4 {
return nil
}
@@ -128,48 +132,37 @@ 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
+ tx.R = sig[:32]
+ tx.S = sig[32:64]
+ tx.V = uint64(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())
-}
+ data := []interface{}{tx.AccountNonce, tx.Price, tx.GasLimit, tx.Recipient, tx.Amount, tx.Payload}
-func (tx *Transaction) RlpValue() *ethutil.Value {
- return ethutil.NewValue(tx.RlpData())
+ return append(data, tx.V, new(big.Int).SetBytes(tx.R).Bytes(), new(big.Int).SetBytes(tx.S).Bytes())
}
func (tx *Transaction) RlpEncode() []byte {
- return tx.RlpValue().Encode()
+ return ethutil.Encode(tx)
}
func (tx *Transaction) RlpDecode(data []byte) {
- tx.RlpValueDecode(ethutil.NewValueFromBytes(data))
+ rlp.Decode(bytes.NewReader(data), tx)
}
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.AccountNonce = decoder.Get(0).Uint()
+ tx.Price = decoder.Get(1).BigInt()
+ tx.GasLimit = 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
- }
+ tx.Amount = decoder.Get(4).BigInt()
+ tx.Payload = decoder.Get(5).Bytes()
+ tx.V = decoder.Get(6).Uint()
+ tx.R = decoder.Get(7).Bytes()
+ tx.S = decoder.Get(8).Bytes()
}
func (tx *Transaction) String() string {
@@ -180,25 +173,28 @@ func (tx *Transaction) String() string {
To: %x
Nonce: %v
GasPrice: %v
- Gas: %v
+ GasLimit %v
Value: %v
Data: 0x%x
V: 0x%x
R: 0x%x
S: 0x%x
- `,
+ Hex: %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)
+ tx.From(),
+ tx.To(),
+ tx.AccountNonce,
+ tx.Price,
+ tx.GasLimit,
+ tx.Amount,
+ tx.Payload,
+ tx.V,
+ tx.R,
+ tx.S,
+ ethutil.Encode(tx),
+ )
}
// Transaction slice type for basic sorting
@@ -221,5 +217,5 @@ func (s Transactions) GetRlp(i int) []byte { return ethutil.Rlp(s[i]) }
type TxByNonce struct{ Transactions }
func (s TxByNonce) Less(i, j int) bool {
- return s.Transactions[i].Nonce < s.Transactions[j].Nonce
+ return s.Transactions[i].AccountNonce < s.Transactions[j].AccountNonce
}
diff --git a/core/vm_env.go b/core/vm_env.go
index 9e1815188..209115eab 100644
--- a/core/vm_env.go
+++ b/core/vm_env.go
@@ -11,28 +11,28 @@ import (
type VMEnv struct {
state *state.StateDB
block *types.Block
- tx *types.Transaction
+ msg Message
depth int
}
-func NewEnv(state *state.StateDB, tx *types.Transaction, block *types.Block) *VMEnv {
+func NewEnv(state *state.StateDB, msg Message, block *types.Block) *VMEnv {
return &VMEnv{
state: state,
block: block,
- tx: tx,
+ msg: msg,
}
}
-func (self *VMEnv) Origin() []byte { return self.tx.Sender() }
-func (self *VMEnv) BlockNumber() *big.Int { return self.block.Number }
-func (self *VMEnv) PrevHash() []byte { return self.block.PrevHash }
-func (self *VMEnv) Coinbase() []byte { return self.block.Coinbase }
-func (self *VMEnv) Time() int64 { return self.block.Time }
-func (self *VMEnv) Difficulty() *big.Int { return self.block.Difficulty }
+func (self *VMEnv) Origin() []byte { return self.msg.From() }
+func (self *VMEnv) BlockNumber() *big.Int { return self.block.Number() }
+func (self *VMEnv) PrevHash() []byte { return self.block.ParentHash() }
+func (self *VMEnv) Coinbase() []byte { return self.block.Coinbase() }
+func (self *VMEnv) Time() int64 { return self.block.Time() }
+func (self *VMEnv) Difficulty() *big.Int { return self.block.Difficulty() }
func (self *VMEnv) BlockHash() []byte { return self.block.Hash() }
-func (self *VMEnv) Value() *big.Int { return self.tx.Value }
+func (self *VMEnv) GasLimit() *big.Int { return self.block.GasLimit() }
+func (self *VMEnv) Value() *big.Int { return self.msg.Value() }
func (self *VMEnv) State() *state.StateDB { return self.state }
-func (self *VMEnv) GasLimit() *big.Int { return self.block.GasLimit }
func (self *VMEnv) Depth() int { return self.depth }
func (self *VMEnv) SetDepth(i int) { self.depth = i }
func (self *VMEnv) AddLog(log state.Log) {
@@ -43,9 +43,7 @@ func (self *VMEnv) Transfer(from, to vm.Account, amount *big.Int) error {
}
func (self *VMEnv) vm(addr, data []byte, gas, price, value *big.Int) *Execution {
- evm := vm.New(self, vm.DebugVmTy)
-
- return NewExecution(evm, addr, data, gas, price, value)
+ return NewExecution(self, addr, data, gas, price, value)
}
func (self *VMEnv) Call(me vm.ClosureRef, addr, data []byte, gas, price, value *big.Int) ([]byte, error) {