aboutsummaryrefslogtreecommitdiffstats
path: root/core
diff options
context:
space:
mode:
authorTaylor Gerring <taylor.gerring@gmail.com>2014-12-22 01:42:32 +0800
committerTaylor Gerring <taylor.gerring@gmail.com>2014-12-22 01:42:32 +0800
commit1360f027d9e365242466ca346b2b56f421729d91 (patch)
treea30ff7292e87583781b682b47d851d0f6e1925fc /core
parentb3629c6f62bd3774eb8858819a8ee07dfb775b73 (diff)
parent795b14330ad4399ef292835eac452d258dcd7464 (diff)
downloadgo-tangerine-1360f027d9e365242466ca346b2b56f421729d91.tar.gz
go-tangerine-1360f027d9e365242466ca346b2b56f421729d91.tar.zst
go-tangerine-1360f027d9e365242466ca346b2b56f421729d91.zip
Merge pull request #216 from ethereum/develop
Update tests branch from develop
Diffstat (limited to 'core')
-rw-r--r--core/block_manager.go122
-rw-r--r--core/chain_manager.go145
-rw-r--r--core/chain_manager_test.go131
-rw-r--r--core/dagger.go85
-rw-r--r--core/execution.go57
-rw-r--r--core/filter.go4
-rw-r--r--core/filter_test.go6
-rw-r--r--core/simple_pow.go1
-rw-r--r--core/state_transition.go157
-rw-r--r--core/transaction_pool.go55
-rw-r--r--core/types/block.go5
-rw-r--r--core/types/bloom9.go12
-rw-r--r--core/types/common.go5
-rw-r--r--core/types/receipt.go13
-rw-r--r--core/types/transaction.go109
-rw-r--r--core/vm_env.go14
16 files changed, 439 insertions, 482 deletions
diff --git a/core/block_manager.go b/core/block_manager.go
index c2ffc7ae0..2567e39c4 100644
--- a/core/block_manager.go
+++ b/core/block_manager.go
@@ -14,6 +14,8 @@ import (
"github.com/ethereum/go-ethereum/ethutil"
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/logger"
+ "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"
)
@@ -55,17 +57,9 @@ type BlockManager struct {
// non-persistent key/value memory storage
mem map[string]*big.Int
// Proof of work used for validating
- Pow PoW
- // The ethereum manager interface
- eth EthManager
- // The managed states
- // Transiently state. The trans state isn't ever saved, validated and
- // it could be used for setting account nonces without effecting
- // the main states.
- transState *state.StateDB
- // Mining state. The mining state is used purely and solely by the mining
- // operation.
- miningState *state.StateDB
+ Pow pow.PoW
+
+ 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
@@ -73,57 +67,28 @@ type BlockManager struct {
lastAttemptedBlock *types.Block
events event.Subscription
+
+ 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: &EasyPow{},
- eth: ethereum,
- bc: ethereum.ChainManager(),
+ mem: make(map[string]*big.Int),
+ Pow: ezp.New(),
+ bc: chainManager,
+ eventMux: eventMux,
+ txpool: txpool,
}
- sm.transState = ethereum.ChainManager().CurrentBlock.State().Copy()
- sm.miningState = ethereum.ChainManager().CurrentBlock.State().Copy()
return sm
}
-func (self *BlockManager) Start() {
- statelogger.Debugln("Starting block manager")
-}
-
-func (self *BlockManager) Stop() {
- statelogger.Debugln("Stopping state manager")
-}
-
-func (sm *BlockManager) CurrentState() *state.StateDB {
- return sm.eth.ChainManager().CurrentBlock.State()
-}
-
-func (sm *BlockManager) TransState() *state.StateDB {
- return sm.transState
-}
-
-func (sm *BlockManager) MiningState() *state.StateDB {
- return sm.miningState
-}
-
-func (sm *BlockManager) NewMiningState() *state.StateDB {
- sm.miningState = sm.eth.ChainManager().CurrentBlock.State().Copy()
-
- return sm.miningState
-}
-
-func (sm *BlockManager) ChainManager() *ChainManager {
- return sm.bc
-}
-
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))
// Process the transactions on to current block
- receipts, _, _, _, err = sm.ProcessTransactions(coinbase, statedb, block, parent, block.Transactions())
+ receipts, _, _, _, err = sm.ApplyTransactions(coinbase, statedb, block, block.Transactions(), false)
if err != nil {
return nil, err
}
@@ -131,7 +96,7 @@ func (sm *BlockManager) TransitionState(statedb *state.StateDB, parent, block *t
return receipts, nil
}
-func (self *BlockManager) ProcessTransactions(coinbase *state.StateObject, state *state.StateDB, block, parent *types.Block, txs types.Transactions) (types.Receipts, types.Transactions, types.Transactions, types.Transactions, error) {
+func (self *BlockManager) ApplyTransactions(coinbase *state.StateObject, state *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
@@ -146,11 +111,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):
@@ -164,12 +129,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)
@@ -178,9 +142,12 @@ done:
receipt := types.NewReceipt(state.Root(), cumulative)
receipt.SetLogs(state.Logs())
receipt.Bloom = types.CreateBloom(types.Receipts{receipt})
+ chainlogger.Debugln(receipt)
// Notify all subscribers
- go self.eth.EventMux().Post(TxPostEvent{tx})
+ if !transientProcess {
+ go self.eventMux.Post(TxPostEvent{tx})
+ }
receipts = append(receipts, receipt)
handled = append(handled, tx)
@@ -229,38 +196,35 @@ func (sm *BlockManager) ProcessWithParent(block, parent *types.Block) (td *big.I
return
}
- _, err = sm.TransitionState(state, parent, block)
+ receipts, err := sm.TransitionState(state, parent, block)
if err != nil {
return
}
+ rbloom := types.CreateBloom(receipts)
+ if bytes.Compare(rbloom, block.LogsBloom) != 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)
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)
- return
- }
- */
+ receiptSha := types.DeriveSha(receipts)
+ if bytes.Compare(receiptSha, block.ReceiptSha) != 0 {
+ //chainlogger.Debugf("validating receipt root. received=%x got=%x", block.ReceiptSha, receiptSha)
+ fmt.Printf("%x\n", ethutil.Encode(receipts))
+ err = fmt.Errorf("validating receipt root. received=%x got=%x", block.ReceiptSha, receiptSha)
+ return
+ }
if err = sm.AccumelateRewards(state, block, parent); err != nil {
return
}
- /*
- //block.receipts = receipts // although this isn't necessary it be in the future
- rbloom := types.CreateBloom(receipts)
- if bytes.Compare(rbloom, block.LogsBloom) != 0 {
- err = fmt.Errorf("unable to replicate block's bloom=%x", rbloom)
- return
- }
- */
-
state.Update(ethutil.Big0)
if !block.State().Cmp(state) {
@@ -278,9 +242,7 @@ func (sm *BlockManager) ProcessWithParent(block, parent *types.Block) (td *big.I
chainlogger.Infof("Processed block #%d (%x...)\n", block.Number, block.Hash()[0:4])
- sm.transState = state.Copy()
-
- sm.eth.TxPool().RemoveSet(block.Transactions())
+ sm.txpool.RemoveSet(block.Transactions())
return td, messages, nil
} else {
@@ -296,12 +258,12 @@ func (sm *BlockManager) CalculateTD(block *types.Block) (*big.Int, bool) {
// 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(sm.bc.Td(), uncleDiff)
td = td.Add(td, block.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
}
@@ -319,7 +281,7 @@ func (sm *BlockManager) ValidateBlock(block, parent *types.Block) error {
diff := block.Time - parent.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.Time, sm.bc.CurrentBlock().Time)
}
/* XXX
@@ -330,7 +292,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.HashNoNonce(), block.Difficulty, block.Nonce) {
+ if !sm.Pow.Verify(block /*block.HashNoNonce(), block.Difficulty, block.Nonce*/) {
return ValidationError("Block's nonce is invalid (= %v)", ethutil.Bytes2Hex(block.Nonce))
}
@@ -378,7 +340,7 @@ func (sm *BlockManager) AccumelateRewards(statedb *state.StateDB, block, parent
account.AddAmount(reward)
statedb.Manifest().AddMessage(&state.Message{
- To: block.Coinbase, From: block.Coinbase,
+ To: block.Coinbase,
Input: nil,
Origin: nil,
Block: block.Hash(), Timestamp: block.Time, Coinbase: block.Coinbase, Number: block.Number,
diff --git a/core/chain_manager.go b/core/chain_manager.go
index 7acd171ec..794ae0011 100644
--- a/core/chain_manager.go
+++ b/core/chain_manager.go
@@ -3,11 +3,13 @@ package core
import (
"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/state"
)
var chainlogger = logger.NewLogger("CHAIN")
@@ -49,12 +51,41 @@ type ChainManager struct {
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
- LastBlockNumber uint64
+ transState *state.StateDB
+}
+
+func (self *ChainManager) Td() *big.Int {
+ self.mu.RLock()
+ defer self.mu.RUnlock()
+
+ return self.td
+}
+
+func (self *ChainManager) LastBlockNumber() uint64 {
+ self.mu.RLock()
+ defer self.mu.RUnlock()
- CurrentBlock *types.Block
- LastBlockHash []byte
+ 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 {
@@ -64,6 +95,8 @@ func NewChainManager(mux *event.TypeMux) *ChainManager {
bc.setLastBlock()
+ bc.transState = bc.State().Copy()
+
return bc
}
@@ -71,6 +104,14 @@ func (self *ChainManager) SetProcessor(proc types.BlockProcessor) {
self.processor = proc
}
+func (self *ChainManager) State() *state.StateDB {
+ return self.CurrentBlock().State()
+}
+
+func (self *ChainManager) TransState() *state.StateDB {
+ return self.transState
+}
+
func (bc *ChainManager) setLastBlock() {
data, _ := ethutil.Config.Db.Get([]byte("LastBlock"))
if len(data) != 0 {
@@ -78,27 +119,30 @@ func (bc *ChainManager) setLastBlock() {
AddTestNetFunds(bc.genesisBlock)
block := types.NewBlockFromBytes(data)
- bc.CurrentBlock = block
- bc.LastBlockHash = block.Hash()
- bc.LastBlockNumber = block.Number.Uint64()
+ bc.currentBlock = block
+ bc.lastBlockHash = block.Hash()
+ bc.lastBlockNumber = block.Number.Uint64()
// Set the last know difficulty (might be 0x0 as initial value, Genesis)
- bc.TD = ethutil.BigD(ethutil.Config.Db.LastKnownTD())
+ 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 {
+ bc.mu.RLock()
+ defer bc.mu.RUnlock()
+
var root interface{}
hash := ZeroHash256
if bc.CurrentBlock != nil {
- root = bc.CurrentBlock.Root()
- hash = bc.LastBlockHash
+ root = bc.currentBlock.Root()
+ hash = bc.lastBlockHash
}
block := types.CreateBlock(
@@ -109,11 +153,11 @@ func (bc *ChainManager) NewBlock(coinbase []byte) *types.Block {
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)
+ block.Number = new(big.Int).Add(bc.currentBlock.Number, ethutil.Big1)
+ block.GasLimit = block.CalcGasLimit(bc.currentBlock)
}
@@ -121,31 +165,49 @@ func (bc *ChainManager) NewBlock(coinbase []byte) *types.Block {
}
func (bc *ChainManager) Reset() {
+ bc.mu.Lock()
+ defer bc.mu.Unlock()
+
AddTestNetFunds(bc.genesisBlock)
bc.genesisBlock.Trie().Sync()
// Prepare the genesis block
- bc.add(bc.genesisBlock)
- bc.CurrentBlock = bc.genesisBlock
+ bc.write(bc.genesisBlock)
+ bc.insert(bc.genesisBlock)
+ bc.currentBlock = bc.genesisBlock
- bc.SetTotalDifficulty(ethutil.Big("0"))
+ bc.setTotalDifficulty(ethutil.Big("0"))
// 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())
}
-// Add a block to the chain and record addition information
-func (bc *ChainManager) add(block *types.Block) {
- bc.writeBlockInfo(block)
+func (self *ChainManager) Export() []byte {
+ self.mu.RLock()
+ defer self.mu.RUnlock()
- bc.CurrentBlock = block
- bc.LastBlockHash = block.Hash()
+ chainlogger.Infof("exporting %v blocks...\n", self.currentBlock.Number)
+ blocks := make([]*types.Block, int(self.currentBlock.Number.Int64())+1)
+ for block := self.currentBlock; block != nil; block = self.GetBlock(block.PrevHash) {
+ blocks[block.Number.Int64()] = block
+ }
+
+ return ethutil.Encode(blocks)
+}
+
+func (bc *ChainManager) insert(block *types.Block) {
encodedBlock := block.RlpEncode()
- ethutil.Config.Db.Put(block.Hash(), encodedBlock)
ethutil.Config.Db.Put([]byte("LastBlock"), encodedBlock)
+ bc.currentBlock = block
+ bc.lastBlockHash = block.Hash()
+}
+
+func (bc *ChainManager) write(block *types.Block) {
+ bc.writeBlockInfo(block)
- //chainlogger.Infof("Imported block #%d (%x...)\n", block.Number, block.Hash()[0:4])
+ encodedBlock := block.RlpEncode()
+ ethutil.Config.Db.Put(block.Hash(), encodedBlock)
}
// Accessors
@@ -167,7 +229,6 @@ func (self *ChainManager) GetChainHashesFromHash(hash []byte, max uint64) (chain
// XXX Could be optimised by using a different database which only holds hashes (i.e., linked list)
for i := uint64(0); i < max; i++ {
-
chain = append(chain, block.Hash())
if block.Number.Cmp(ethutil.Big0) <= 0 {
@@ -190,7 +251,10 @@ func (self *ChainManager) GetBlock(hash []byte) *types.Block {
}
func (self *ChainManager) GetBlockByNumber(num uint64) *types.Block {
- block := self.CurrentBlock
+ self.mu.RLock()
+ defer self.mu.RUnlock()
+
+ block := self.currentBlock
for ; block != nil; block = self.GetBlock(block.PrevHash) {
if block.Number.Uint64() == num {
break
@@ -204,9 +268,9 @@ func (self *ChainManager) GetBlockByNumber(num uint64) *types.Block {
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) {
@@ -239,8 +303,8 @@ func (bc *ChainManager) BlockInfo(block *types.Block) types.BlockInfo {
// 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}
+ 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())
@@ -266,8 +330,23 @@ func (self *ChainManager) InsertChain(chain types.Blocks) error {
return err
}
- self.add(block)
- self.SetTotalDifficulty(td)
+ self.mu.Lock()
+ {
+
+ 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.setTotalDifficulty(td)
+ self.insert(block)
+ self.transState = self.currentBlock.State().Copy()
+ }
+
+ }
+ 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 ab43c511d..52be8b0ea 100644
--- a/core/chain_manager_test.go
+++ b/core/chain_manager_test.go
@@ -2,115 +2,76 @@ package core
import (
"fmt"
- "math/big"
+ "path"
+ "runtime"
"testing"
- "time"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/ethutil"
- "github.com/ethereum/go-ethereum/state"
+ "github.com/ethereum/go-ethereum/event"
+ //logpkg "github.com/ethereum/go-ethereum/logger"
)
-var TD *big.Int
+//var Logger logpkg.LogSystem
+//var Log = logpkg.NewLogger("TEST")
func init() {
- ethutil.ReadConfig(".ethtest", "/tmp/ethtest", "")
- ethutil.Config.Db, _ = ethdb.NewMemDatabase()
-}
-
-type fakeproc struct {
-}
+ runtime.GOMAXPROCS(runtime.NumCPU())
+ //Logger = logpkg.NewStdLogSystem(os.Stdout, log.LstdFlags, logpkg.InfoLevel)
+ //logpkg.AddLogSystem(Logger)
-func (self fakeproc) ProcessWithParent(a, b *types.Block) (*big.Int, state.Messages, error) {
- TD = new(big.Int).Add(TD, big.NewInt(1))
- return TD, nil, nil
-}
-
-func makechain(cman *ChainManager, max int) *BlockChain {
- blocks := make(types.Blocks, max)
- for i := 0; i < max; i++ {
- addr := ethutil.LeftPadBytes([]byte{byte(i)}, 20)
- block := cman.NewBlock(addr)
- if i != 0 {
- cman.CurrentBlock = blocks[i-1]
- }
- blocks[i] = block
- }
- return NewChain(blocks)
-}
-
-func TestLongerFork(t *testing.T) {
- cman := NewChainManager()
- cman.SetProcessor(fakeproc{})
-
- TD = big.NewInt(1)
- chainA := makechain(cman, 5)
-
- TD = big.NewInt(1)
- chainB := makechain(cman, 10)
-
- td, err := cman.TestChain(chainA)
- if err != nil {
- t.Error("unable to create new TD from chainA:", err)
- }
- cman.TD = td
+ ethutil.ReadConfig("/tmp/ethtest", "/tmp/ethtest", "ETH")
- _, err = cman.TestChain(chainB)
+ db, err := ethdb.NewMemDatabase()
if err != nil {
- t.Error("expected chainB not to give errors:", err)
+ panic("Could not create mem-db, failing")
}
+ ethutil.Config.Db = db
}
-func TestEqualFork(t *testing.T) {
- cman := NewChainManager()
- cman.SetProcessor(fakeproc{})
-
- TD = big.NewInt(1)
- chainA := makechain(cman, 5)
-
- TD = big.NewInt(2)
- chainB := makechain(cman, 5)
-
- td, err := cman.TestChain(chainA)
+func loadChain(fn string, t *testing.T) types.Blocks {
+ c1, err := ethutil.ReadAllFile(path.Join("..", "_data", fn))
if err != nil {
- t.Error("unable to create new TD from chainA:", err)
+ fmt.Println(err)
+ t.FailNow()
}
- cman.TD = td
-
- _, err = cman.TestChain(chainB)
- if err != nil {
- t.Error("expected chainB not to give errors:", err)
+ value := ethutil.NewValueFromBytes([]byte(c1))
+ blocks := make(types.Blocks, value.Len())
+ it := value.NewIterator()
+ for it.Next() {
+ blocks[it.Idx()] = types.NewBlockFromRlpValue(it.Value())
}
-}
-func TestBrokenChain(t *testing.T) {
- cman := NewChainManager()
- cman.SetProcessor(fakeproc{})
-
- TD = big.NewInt(1)
- chain := makechain(cman, 5)
- chain.Remove(chain.Front())
+ return blocks
+}
- _, err := cman.TestChain(chain)
- if err == nil {
- t.Error("expected broken chain to return error")
+func insertChain(done chan bool, chainMan *ChainManager, chain types.Blocks, t *testing.T) {
+ err := chainMan.InsertChain(chain)
+ if err != nil {
+ fmt.Println(err)
+ t.FailNow()
}
+ done <- true
}
-func BenchmarkChainTesting(b *testing.B) {
- const chainlen = 1000
+func TestChainInsertions(t *testing.T) {
+ chain1 := loadChain("chain1", t)
+ chain2 := loadChain("chain2", t)
+ var eventMux event.TypeMux
+ chainMan := NewChainManager(&eventMux)
+ txPool := NewTxPool(chainMan, nil, &eventMux)
+ blockMan := NewBlockManager(txPool, chainMan, &eventMux)
+ chainMan.SetProcessor(blockMan)
- ethutil.ReadConfig(".ethtest", "/tmp/ethtest", "")
- ethutil.Config.Db, _ = ethdb.NewMemDatabase()
+ const max = 2
+ done := make(chan bool, max)
- cman := NewChainManager()
- cman.SetProcessor(fakeproc{})
+ go insertChain(done, chainMan, chain1, t)
+ go insertChain(done, chainMan, chain2, t)
- TD = big.NewInt(1)
- chain := makechain(cman, chainlen)
-
- stime := time.Now()
- cman.TestChain(chain)
- fmt.Println(chainlen, "took", time.Since(stime))
+ for i := 0; i < max; i++ {
+ <-done
+ }
+ fmt.Println(chainMan.CurrentBlock())
}
diff --git a/core/dagger.go b/core/dagger.go
index 8a042b34f..3039d8995 100644
--- a/core/dagger.go
+++ b/core/dagger.go
@@ -6,8 +6,6 @@ import (
"math/rand"
"time"
- "github.com/ethereum/go-ethereum/core/types"
- "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethutil"
"github.com/ethereum/go-ethereum/logger"
"github.com/obscuren/sha3"
@@ -15,89 +13,6 @@ import (
var powlogger = logger.NewLogger("POW")
-type PoW interface {
- Search(block *types.Block, stop <-chan struct{}) []byte
- Verify(hash []byte, diff *big.Int, nonce []byte) bool
- GetHashrate() int64
- Turbo(bool)
-}
-
-type EasyPow struct {
- hash *big.Int
- HashRate int64
- turbo bool
-}
-
-func (pow *EasyPow) GetHashrate() int64 {
- return pow.HashRate
-}
-
-func (pow *EasyPow) Turbo(on bool) {
- pow.turbo = on
-}
-
-func (pow *EasyPow) Search(block *types.Block, stop <-chan struct{}) []byte {
- r := rand.New(rand.NewSource(time.Now().UnixNano()))
- hash := block.HashNoNonce()
- diff := block.Difficulty
- i := int64(0)
- start := time.Now().UnixNano()
- t := time.Now()
-
- for {
- select {
- case <-stop:
- powlogger.Infoln("Breaking from mining")
- pow.HashRate = 0
- return nil
- default:
- i++
-
- if time.Since(t) > (1 * time.Second) {
- elapsed := time.Now().UnixNano() - start
- hashes := ((float64(1e9) / float64(elapsed)) * float64(i)) / 1000
- pow.HashRate = int64(hashes)
- powlogger.Infoln("Hashing @", pow.HashRate, "khash")
-
- t = time.Now()
- }
-
- sha := crypto.Sha3(big.NewInt(r.Int63()).Bytes())
- if pow.Verify(hash, diff, sha) {
- return sha
- }
- }
-
- if !pow.turbo {
- time.Sleep(20 * time.Microsecond)
- }
- }
-
- return nil
-}
-
-func (pow *EasyPow) Verify(hash []byte, diff *big.Int, nonce []byte) bool {
- sha := sha3.NewKeccak256()
-
- d := append(hash, nonce...)
- sha.Write(d)
-
- verification := new(big.Int).Div(ethutil.BigPow(2, 256), diff)
- res := ethutil.U256(ethutil.BigD(sha.Sum(nil)))
-
- /*
- fmt.Printf("hash w/o nonce %x\n", hash)
- fmt.Printf("2**256 / %v = %v\n", diff, verification)
- fmt.Printf("%v <= %v\n", res, verification)
- fmt.Printf("vlen: %d rlen: %d\n", len(verification.Bytes()), len(res.Bytes()))
- */
-
- return res.Cmp(verification) <= 0
-}
-
-func (pow *EasyPow) SetHash(hash *big.Int) {
-}
-
type Dagger struct {
hash *big.Int
xn *big.Int
diff --git a/core/execution.go b/core/execution.go
index 9f9d9a5d9..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,54 +26,46 @@ 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, caddr []byte, caller vm.ClosureRef) (ret []byte, err error) {
- env := self.vm.Env()
+func (self *Execution) exec(code, contextAddr []byte, caller vm.ClosureRef) (ret []byte, err error) {
+ env := self.env
+ evm := vm.New(env, vm.DebugVmTy)
- chainlogger.Debugf("pre state %x\n", env.State().Root())
- 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())
- }()
+ 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
if !self.SkipTransfer {
err = env.Transfer(from, to, self.value)
+ if err != nil {
+ caller.ReturnGas(self.Gas, self.price)
+
+ err = fmt.Errorf("Insufficient funds to transfer value. Req %v, has %v", self.value, from.Balance)
+ return
+ }
}
+ snapshot := env.State().Copy()
+ start := time.Now()
+ ret, err = evm.Run(to, caller, code, self.value, self.Gas, self.price, self.input)
if err != nil {
- caller.ReturnGas(self.Gas, self.price)
-
- err = fmt.Errorf("Insufficient funds to transfer value. Req %v, has %v", self.value, from.Balance)
- } else {
- self.object = to
- // Pre-compiled contracts (address.go) 1, 2 & 3.
- naddr := ethutil.BigD(caddr).Uint64()
- if p := vm.Precompiled[naddr]; p != nil {
- if self.Gas.Cmp(p.Gas) >= 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)
- }
+ 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..fb992782d 100644
--- a/core/filter.go
+++ b/core/filter.go
@@ -78,11 +78,11 @@ func (self *Filter) SetSkip(skip int) {
func (self *Filter) Find() []*state.Message {
var earliestBlockNo uint64 = uint64(self.earliest)
if self.earliest == -1 {
- earliestBlockNo = self.eth.ChainManager().CurrentBlock.Number.Uint64()
+ earliestBlockNo = self.eth.ChainManager().CurrentBlock().Number.Uint64()
}
var latestBlockNo uint64 = uint64(self.latest)
if self.latest == -1 {
- latestBlockNo = self.eth.ChainManager().CurrentBlock.Number.Uint64()
+ latestBlockNo = self.eth.ChainManager().CurrentBlock().Number.Uint64()
}
var (
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/simple_pow.go b/core/simple_pow.go
new file mode 100644
index 000000000..9a8bc9592
--- /dev/null
+++ b/core/simple_pow.go
@@ -0,0 +1 @@
+package core
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 abacb14f1..58c2255a4 100644
--- a/core/transaction_pool.go
+++ b/core/transaction_pool.go
@@ -8,6 +8,7 @@ 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"
@@ -61,7 +62,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 +75,20 @@ type TxPool struct {
SecondaryProcessor TxProcessor
subscribers []chan TxMsg
+
+ broadcaster types.Broadcaster
+ chainManager *ChainManager
+ eventMux *event.TypeMux
}
-func NewTxPool(ethereum EthManager) *TxPool {
+func NewTxPool(chainManager *ChainManager, broadcaster types.Broadcaster, 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,
+ broadcaster: broadcaster,
}
}
@@ -94,20 +100,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.broadcaster.Broadcast(wire.MsgTxTy, []interface{}{tx.RlpData()})
}
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()
@@ -115,24 +121,14 @@ func (pool *TxPool) ValidateTransaction(tx *types.Transaction) error {
return fmt.Errorf("tx.v != (28 || 27)")
}
- if tx.GasPrice.Cmp(MinGasPrice) < 0 {
- return fmt.Errorf("Gas price to low. Require %v > Got %v", MinGasPrice, tx.GasPrice)
- }
-
// Get the sender
- sender := pool.Ethereum.BlockManager().CurrentState().GetAccount(tx.Sender())
+ sender := pool.chainManager.State().GetAccount(tx.Sender())
- 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
@@ -158,17 +154,18 @@ 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
- self.Ethereum.EventMux().Post(TxPreEvent{tx})
+ go self.eventMux.Post(TxPreEvent{tx})
return nil
}
+func (self *TxPool) Size() int {
+ return self.pool.Len()
+}
+
func (pool *TxPool) CurrentTransactions() []*types.Transaction {
pool.mutex.Lock()
defer pool.mutex.Unlock()
@@ -194,7 +191,7 @@ func (pool *TxPool) RemoveInvalid(state *state.StateDB) {
tx := e.Value.(*types.Transaction)
sender := state.GetAccount(tx.Sender())
err := pool.ValidateTransaction(tx)
- if err != nil || sender.Nonce >= tx.Nonce {
+ if err != nil || sender.Nonce >= tx.Nonce() {
pool.pool.Remove(e)
}
}
diff --git a/core/types/block.go b/core/types/block.go
index 55ce1fb9b..2d889f35f 100644
--- a/core/types/block.go
+++ b/core/types/block.go
@@ -409,5 +409,8 @@ func (self *Block) Size() ethutil.StorageSize {
// Implement RlpEncodable
func (self *Block) RlpData() interface{} {
- return self.Value().Val
+ return []interface{}{self.header(), self.transactions, self.rlpUncles()}
}
+
+// Implement pow.Block
+func (self *Block) N() []byte { return self.Nonce }
diff --git a/core/types/bloom9.go b/core/types/bloom9.go
index d04656b0d..c1841e553 100644
--- a/core/types/bloom9.go
+++ b/core/types/bloom9.go
@@ -20,18 +20,16 @@ func CreateBloom(receipts Receipts) []byte {
func LogsBloom(logs state.Logs) *big.Int {
bin := new(big.Int)
for _, log := range logs {
- data := [][]byte{log.Address()}
- for _, topic := range log.Topics() {
- data = append(data, topic)
+ data := make([][]byte, len(log.Topics())+1)
+ data[0] = log.Address()
+
+ for i, topic := range log.Topics() {
+ data[i+1] = topic
}
for _, b := range data {
bin.Or(bin, ethutil.BigD(bloom9(crypto.Sha3(b)).Bytes()))
}
-
- //if log.Data != nil {
- // data = append(data, log.Data)
- //}
}
return bin
diff --git a/core/types/common.go b/core/types/common.go
index ba88b77e1..89cb5f498 100644
--- a/core/types/common.go
+++ b/core/types/common.go
@@ -4,8 +4,13 @@ import (
"math/big"
"github.com/ethereum/go-ethereum/state"
+ "github.com/ethereum/go-ethereum/wire"
)
type BlockProcessor interface {
Process(*Block) (*big.Int, state.Messages, error)
}
+
+type Broadcaster interface {
+ Broadcast(wire.MsgType, []interface{})
+}
diff --git a/core/types/receipt.go b/core/types/receipt.go
index 25fa8fb07..bac64e41d 100644
--- a/core/types/receipt.go
+++ b/core/types/receipt.go
@@ -64,5 +64,18 @@ func (self *Receipt) String() string {
type Receipts []*Receipt
+func (self Receipts) RlpData() interface{} {
+ data := make([]interface{}, len(self))
+ for i, receipt := range self {
+ data[i] = receipt.RlpData()
+ }
+
+ return data
+}
+
+func (self Receipts) RlpEncode() []byte {
+ return ethutil.Encode(self.RlpData())
+}
+
func (self Receipts) Len() int { return len(self) }
func (self Receipts) GetRlp(i int) []byte { return ethutil.Rlp(self[i]) }
diff --git a/core/types/transaction.go b/core/types/transaction.go
index 63edef756..f6ad0774b 100644
--- a/core/types/transaction.go
+++ b/core/types/transaction.go
@@ -6,37 +6,30 @@ import (
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethutil"
- "github.com/ethereum/go-ethereum/state"
"github.com/obscuren/secp256k1-go"
)
-var ContractAddr = []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
-
func IsContractAddr(addr []byte) bool {
return len(addr) == 0
- //return bytes.Compare(addr, ContractAddr) == 0
}
type Transaction struct {
- Nonce uint64
- Recipient []byte
- Value *big.Int
- Gas *big.Int
- GasPrice *big.Int
- Data []byte
+ nonce uint64
+ recipient []byte
+ value *big.Int
+ gas *big.Int
+ gasPrice *big.Int
+ data []byte
v byte
r, s []byte
-
- // Indicates whether this tx is a contract creation transaction
- contractCreation bool
}
func NewContractCreationTx(value, gas, gasPrice *big.Int, script []byte) *Transaction {
- return &Transaction{Recipient: nil, Value: value, Gas: gas, GasPrice: gasPrice, Data: script, contractCreation: true}
+ return &Transaction{recipient: nil, value: value, gas: gas, gasPrice: gasPrice, data: script}
}
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)}
+ return &Transaction{recipient: to, value: value, gasPrice: gasPrice, gas: gas, data: data}
}
func NewTransactionFromBytes(data []byte) *Transaction {
@@ -53,33 +46,42 @@ func NewTransactionFromValue(val *ethutil.Value) *Transaction {
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.nonce, tx.gasPrice, tx.gas, tx.recipient, tx.value, tx.data}
+
+ return crypto.Sha3(ethutil.NewValue(data).Encode())
}
-func (self *Transaction) TotalValue() *big.Int {
- v := self.GasValue()
- return v.Add(v, self.Value)
+func (self *Transaction) Data() []byte {
+ return self.data
}
-func (tx *Transaction) Hash() []byte {
- data := []interface{}{tx.Nonce, tx.GasPrice, tx.Gas, tx.Recipient, tx.Value, tx.Data}
+func (self *Transaction) Gas() *big.Int {
+ return self.gas
+}
- return crypto.Sha3(ethutil.NewValue(data).Encode())
+func (self *Transaction) GasPrice() *big.Int {
+ return self.gasPrice
}
-func (tx *Transaction) CreatesContract() bool {
- return tx.contractCreation
+func (self *Transaction) Value() *big.Int {
+ return self.value
}
-/* Deprecated */
-func (tx *Transaction) IsContract() bool {
- return tx.CreatesContract()
+func (self *Transaction) Nonce() uint64 {
+ return self.nonce
}
-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) SetNonce(nonce uint64) {
+ self.nonce = nonce
+}
+
+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) {
@@ -106,8 +108,8 @@ 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
}
@@ -136,9 +138,7 @@ func (tx *Transaction) Sign(privk []byte) error {
}
func (tx *Transaction) RlpData() interface{} {
- data := []interface{}{tx.Nonce, tx.GasPrice, tx.Gas, tx.Recipient, tx.Value, tx.Data}
-
- // TODO Remove prefixing zero's
+ data := []interface{}{tx.nonce, tx.gasPrice, tx.gas, tx.recipient, tx.value, tx.data}
return append(data, tx.v, new(big.Int).SetBytes(tx.r).Bytes(), new(big.Int).SetBytes(tx.s).Bytes())
}
@@ -156,20 +156,16 @@ func (tx *Transaction) RlpDecode(data []byte) {
}
func (tx *Transaction) RlpValueDecode(decoder *ethutil.Value) {
- tx.Nonce = decoder.Get(0).Uint()
- tx.GasPrice = decoder.Get(1).BigInt()
- tx.Gas = decoder.Get(2).BigInt()
- tx.Recipient = decoder.Get(3).Bytes()
- tx.Value = decoder.Get(4).BigInt()
- tx.Data = decoder.Get(5).Bytes()
+ tx.nonce = decoder.Get(0).Uint()
+ tx.gasPrice = decoder.Get(1).BigInt()
+ tx.gas = decoder.Get(2).BigInt()
+ tx.recipient = decoder.Get(3).Bytes()
+ tx.value = decoder.Get(4).BigInt()
+ tx.data = decoder.Get(5).Bytes()
tx.v = byte(decoder.Get(6).Uint())
tx.r = decoder.Get(7).Bytes()
tx.s = decoder.Get(8).Bytes()
-
- if IsContractAddr(tx.Recipient) {
- tx.contractCreation = true
- }
}
func (tx *Transaction) String() string {
@@ -186,19 +182,22 @@ func (tx *Transaction) String() string {
V: 0x%x
R: 0x%x
S: 0x%x
+ Hex: %x
`,
tx.Hash(),
- len(tx.Recipient) == 0,
+ len(tx.recipient) == 0,
tx.Sender(),
- tx.Recipient,
- tx.Nonce,
- tx.GasPrice,
- tx.Gas,
- tx.Value,
- tx.Data,
+ tx.recipient,
+ tx.nonce,
+ tx.gasPrice,
+ tx.gas,
+ tx.value,
+ tx.data,
tx.v,
tx.r,
- tx.s)
+ tx.s,
+ ethutil.Encode(tx),
+ )
}
// Transaction slice type for basic sorting
@@ -221,5 +220,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].nonce < s.Transactions[j].nonce
}
diff --git a/core/vm_env.go b/core/vm_env.go
index 9e1815188..ad63ecf9c 100644
--- a/core/vm_env.go
+++ b/core/vm_env.go
@@ -11,26 +11,26 @@ 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) Origin() []byte { return self.msg.From() }
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) BlockHash() []byte { return self.block.Hash() }
-func (self *VMEnv) Value() *big.Int { return self.tx.Value }
+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 }
@@ -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) {