Merge branch 'release/poc5-rc7'

This commit is contained in:
obscuren 2014-05-20 17:09:44 +02:00
commit 4b13f93a3e
23 changed files with 380 additions and 281 deletions

View File

@ -6,7 +6,7 @@ Ethereum
Ethereum Go Development package (C) Jeffrey Wilcke Ethereum Go Development package (C) Jeffrey Wilcke
Ethereum is currently in its testing phase. The current state is "Proof Ethereum is currently in its testing phase. The current state is "Proof
of Concept 5.0 RC6". For build instructions see the [Wiki](https://github.com/ethereum/go-ethereum/wiki/Building-Ethereum(Go)). of Concept 5.0 RC7". For build instructions see the [Wiki](https://github.com/ethereum/go-ethereum/wiki/Building-Ethereum(Go)).
Ethereum Go is split up in several sub packages Please refer to each Ethereum Go is split up in several sub packages Please refer to each
individual package for more information. individual package for more information.

View File

@ -4,6 +4,7 @@ import (
"fmt" "fmt"
"github.com/ethereum/eth-go/ethutil" "github.com/ethereum/eth-go/ethutil"
"math/big" "math/big"
"strconv"
"time" "time"
) )
@ -40,6 +41,14 @@ type Block struct {
Difficulty *big.Int Difficulty *big.Int
// Creation time // Creation time
Time int64 Time int64
// The block number
Number *big.Int
// Minimum Gas Price
MinGasPrice *big.Int
// Gas limit
GasLimit *big.Int
// Gas used
GasUsed *big.Int
// Extra data // Extra data
Extra string Extra string
// Block Nonce for verification // Block Nonce for verification
@ -122,7 +131,7 @@ func (block *Block) Transactions() []*Transaction {
} }
func (block *Block) PayFee(addr []byte, fee *big.Int) bool { func (block *Block) PayFee(addr []byte, fee *big.Int) bool {
contract := block.state.GetContract(addr) contract := block.state.GetStateObject(addr)
// If we can't pay the fee return // If we can't pay the fee return
if contract == nil || contract.Amount.Cmp(fee) < 0 /* amount < fee */ { if contract == nil || contract.Amount.Cmp(fee) < 0 /* amount < fee */ {
fmt.Println("Contract has insufficient funds", contract.Amount, fee) fmt.Println("Contract has insufficient funds", contract.Amount, fee)
@ -206,7 +215,12 @@ func (block *Block) SetUncles(uncles []*Block) {
func (block *Block) SetTransactions(txs []*Transaction) { func (block *Block) SetTransactions(txs []*Transaction) {
block.transactions = txs block.transactions = txs
block.TxSha = ethutil.Sha3Bin(ethutil.Encode(block.rlpTxs())) trie := ethutil.NewTrie(ethutil.Config.Db, "")
for i, tx := range txs {
trie.Update(strconv.Itoa(i), string(tx.RlpEncode()))
}
block.TxSha = trie.Root.([]byte)
} }
func (block *Block) Value() *ethutil.Value { func (block *Block) Value() *ethutil.Value {
@ -233,9 +247,13 @@ func (block *Block) RlpValueDecode(decoder *ethutil.Value) {
block.state = NewState(ethutil.NewTrie(ethutil.Config.Db, header.Get(3).Val)) block.state = NewState(ethutil.NewTrie(ethutil.Config.Db, header.Get(3).Val))
block.TxSha = header.Get(4).Bytes() block.TxSha = header.Get(4).Bytes()
block.Difficulty = header.Get(5).BigInt() block.Difficulty = header.Get(5).BigInt()
block.Time = int64(header.Get(6).BigInt().Uint64()) block.Number = header.Get(6).BigInt()
block.Extra = header.Get(7).Str() block.MinGasPrice = header.Get(7).BigInt()
block.Nonce = header.Get(8).Bytes() block.GasLimit = header.Get(8).BigInt()
block.GasUsed = header.Get(9).BigInt()
block.Time = int64(header.Get(10).BigInt().Uint64())
block.Extra = header.Get(11).Str()
block.Nonce = header.Get(12).Bytes()
block.contractStates = make(map[string]*ethutil.Trie) block.contractStates = make(map[string]*ethutil.Trie)
// Tx list might be empty if this is an uncle. Uncles only have their // Tx list might be empty if this is an uncle. Uncles only have their
@ -270,21 +288,21 @@ func NewUncleBlockFromValue(header *ethutil.Value) *Block {
block.state = NewState(ethutil.NewTrie(ethutil.Config.Db, header.Get(3).Val)) block.state = NewState(ethutil.NewTrie(ethutil.Config.Db, header.Get(3).Val))
block.TxSha = header.Get(4).Bytes() block.TxSha = header.Get(4).Bytes()
block.Difficulty = header.Get(5).BigInt() block.Difficulty = header.Get(5).BigInt()
block.Time = int64(header.Get(6).BigInt().Uint64()) block.Number = header.Get(6).BigInt()
block.Extra = header.Get(7).Str() block.MinGasPrice = header.Get(7).BigInt()
block.Nonce = header.Get(8).Bytes() block.GasLimit = header.Get(8).BigInt()
block.GasUsed = header.Get(9).BigInt()
block.Time = int64(header.Get(10).BigInt().Uint64())
block.Extra = header.Get(11).Str()
block.Nonce = header.Get(12).Bytes()
return block return block
} }
func (block *Block) String() string {
return fmt.Sprintf("Block(%x):\nPrevHash:%x\nUncleSha:%x\nCoinbase:%x\nRoot:%x\nTxSha:%x\nDiff:%v\nTime:%d\nNonce:%x\nTxs:%d\n", block.Hash(), block.PrevHash, block.UncleSha, block.Coinbase, block.state.trie.Root, block.TxSha, block.Difficulty, block.Time, block.Nonce, len(block.transactions))
}
func (block *Block) GetRoot() interface{} { func (block *Block) GetRoot() interface{} {
return block.state.trie.Root return block.state.trie.Root
} }
//////////// UNEXPORTED /////////////////
func (block *Block) header() []interface{} { func (block *Block) header() []interface{} {
return []interface{}{ return []interface{}{
// Sha of the previous block // Sha of the previous block
@ -299,6 +317,14 @@ func (block *Block) header() []interface{} {
block.TxSha, block.TxSha,
// Current block Difficulty // Current block Difficulty
block.Difficulty, block.Difficulty,
// The block number
block.Number,
// Block minimum gas price
block.MinGasPrice,
// Block upper gas bound
block.GasLimit,
// Block gas used
block.GasUsed,
// Time the block was found? // Time the block was found?
block.Time, block.Time,
// Extra data // Extra data
@ -307,3 +333,36 @@ func (block *Block) header() []interface{} {
block.Nonce, block.Nonce,
} }
} }
func (block *Block) String() string {
return fmt.Sprintf(`
BLOCK(%x):
PrevHash: %x
UncleSha: %x
Coinbase: %x
Root: %x
TxSha: %x
Difficulty: %v
Number: %v
MinGas: %v
MaxLimit: %v
GasUsed: %v
Time: %v
Extra: %v
Nonce: %x
`,
block.Hash(),
block.PrevHash,
block.UncleSha,
block.Coinbase,
block.state.trie.Root,
block.TxSha,
block.Difficulty,
block.Number,
block.MinGasPrice,
block.GasLimit,
block.GasUsed,
block.Time,
block.Extra,
block.Nonce)
}

View File

@ -70,6 +70,22 @@ func (bc *BlockChain) NewBlock(coinbase []byte, txs []*Transaction) *Block {
diff.Mul(diff, mul) diff.Mul(diff, mul)
diff.Add(diff, bc.CurrentBlock.Difficulty) diff.Add(diff, bc.CurrentBlock.Difficulty)
block.Difficulty = diff block.Difficulty = diff
block.Number = new(big.Int).Add(bc.CurrentBlock.Number, ethutil.Big1)
// max(10000, (parent gas limit * (1024 - 1) + (parent gas used * 6 / 5)) / 1024)
base := new(big.Int)
base2 := new(big.Int)
parentGL := bc.CurrentBlock.GasLimit
parentUsed := bc.CurrentBlock.GasUsed
base.Mul(parentGL, big.NewInt(1024-1))
base2.Mul(parentUsed, big.NewInt(6))
base2.Div(base2, big.NewInt(5))
base.Add(base, base2)
base.Div(base, big.NewInt(1024))
block.GasLimit = ethutil.BigMax(big.NewInt(10000), base)
} }
return block return block
@ -127,7 +143,6 @@ func (bc *BlockChain) FindCanonicalChain(blocks []*Block, commonBlockHash []byte
log.Println("[CHAIN] We have found the common parent block, breaking") log.Println("[CHAIN] We have found the common parent block, breaking")
break break
} }
log.Println("Checking incoming blocks:")
chainDifficulty.Add(chainDifficulty, bc.CalculateBlockTD(block)) chainDifficulty.Add(chainDifficulty, bc.CalculateBlockTD(block))
} }
@ -182,6 +197,7 @@ func (bc *BlockChain) ResetTillBlockHash(hash []byte) error {
// XXX Why are we resetting? This is the block chain, it has nothing to do with states // XXX Why are we resetting? This is the block chain, it has nothing to do with states
//bc.Ethereum.StateManager().PrepareDefault(returnTo) //bc.Ethereum.StateManager().PrepareDefault(returnTo)
// Manually reset the last sync block
err := ethutil.Config.Db.Delete(lastBlock.Hash()) err := ethutil.Config.Db.Delete(lastBlock.Hash())
if err != nil { if err != nil {
return err return err
@ -261,13 +277,14 @@ func AddTestNetFunds(block *Block) {
"1e12515ce3e0f817a4ddef9ca55788a1d66bd2df", // Vit "1e12515ce3e0f817a4ddef9ca55788a1d66bd2df", // Vit
"1a26338f0d905e295fccb71fa9ea849ffa12aaf4", // Alex "1a26338f0d905e295fccb71fa9ea849ffa12aaf4", // Alex
"2ef47100e0787b915105fd5e3f4ff6752079d5cb", // Maran "2ef47100e0787b915105fd5e3f4ff6752079d5cb", // Maran
"cd2a3d9f938e13cd947ec05abc7fe734df8dd826", // Roman
} { } {
//log.Println("2^200 Wei to", addr)
codedAddr := ethutil.FromHex(addr) codedAddr := ethutil.FromHex(addr)
account := block.state.GetAccount(codedAddr) account := block.state.GetAccount(codedAddr)
account.Amount = ethutil.BigPow(2, 200) account.Amount = ethutil.BigPow(2, 200)
block.state.UpdateStateObject(account) block.state.UpdateStateObject(account)
} }
log.Printf("%x\n", block.RlpEncode())
} }
func (bc *BlockChain) setLastBlock() { func (bc *BlockChain) setLastBlock() {
@ -279,7 +296,7 @@ func (bc *BlockChain) setLastBlock() {
bc.LastBlockHash = block.Hash() bc.LastBlockHash = block.Hash()
bc.LastBlockNumber = info.Number bc.LastBlockNumber = info.Number
log.Printf("[CHAIN] Last known block height #%d\n", bc.LastBlockNumber) ethutil.Config.Log.Infof("[CHAIN] Last known block height #%d\n", bc.LastBlockNumber)
} else { } else {
AddTestNetFunds(bc.genesisBlock) AddTestNetFunds(bc.genesisBlock)
@ -294,7 +311,7 @@ func (bc *BlockChain) setLastBlock() {
// Set the last know difficulty (might be 0x0 as initial value, Genesis) // 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())
log.Printf("Last block: %x\n", bc.CurrentBlock.Hash()) ethutil.Config.Log.Infof("Last block: %x\n", bc.CurrentBlock.Hash())
} }
func (bc *BlockChain) SetTotalDifficulty(td *big.Int) { func (bc *BlockChain) SetTotalDifficulty(td *big.Int) {

View File

@ -18,6 +18,18 @@ type TestManager struct {
Blocks []*Block Blocks []*Block
} }
func (s *TestManager) IsListening() bool {
return false
}
func (s *TestManager) IsMining() bool {
return false
}
func (s *TestManager) PeerCount() int {
return 0
}
func (s *TestManager) BlockChain() *BlockChain { func (s *TestManager) BlockChain() *BlockChain {
return s.blockChain return s.blockChain
} }
@ -38,7 +50,7 @@ func (tm *TestManager) Broadcast(msgType ethwire.MsgType, data []interface{}) {
} }
func NewTestManager() *TestManager { func NewTestManager() *TestManager {
ethutil.ReadConfig(".ethtest") ethutil.ReadConfig(".ethtest", ethutil.LogStd)
db, err := ethdb.NewMemDatabase() db, err := ethdb.NewMemDatabase()
if err != nil { if err != nil {
@ -62,8 +74,7 @@ func NewTestManager() *TestManager {
func (tm *TestManager) AddFakeBlock(blk []byte) error { func (tm *TestManager) AddFakeBlock(blk []byte) error {
block := NewBlockFromBytes(blk) block := NewBlockFromBytes(blk)
tm.Blocks = append(tm.Blocks, block) tm.Blocks = append(tm.Blocks, block)
tm.StateManager().PrepareDefault(block) err := tm.StateManager().ProcessBlock(tm.StateManager().CurrentState(), block, false)
err := tm.StateManager().ProcessBlock(block, false)
return err return err
} }
func (tm *TestManager) CreateChain1() error { func (tm *TestManager) CreateChain1() error {

View File

@ -29,14 +29,14 @@ func (pow *EasyPow) Search(block *Block, reactChan chan ethutil.React) []byte {
for { for {
select { select {
case <-reactChan: case <-reactChan:
log.Println("[POW] Received reactor event; breaking out.") ethutil.Config.Log.Infoln("[POW] Received reactor event; breaking out.")
return nil return nil
default: default:
i++ i++
if i%1234567 == 0 { if i%1234567 == 0 {
elapsed := time.Now().UnixNano() - start elapsed := time.Now().UnixNano() - start
hashes := ((float64(1e9) / float64(elapsed)) * float64(i)) / 1000 hashes := ((float64(1e9) / float64(elapsed)) * float64(i)) / 1000
log.Println("[POW] Hashing @", int64(hashes), "khash") ethutil.Config.Log.Infoln("[POW] Hashing @", int64(hashes), "khash")
} }
sha := ethutil.Sha3Bin(big.NewInt(r.Int63()).Bytes()) sha := ethutil.Sha3Bin(big.NewInt(r.Int63()).Bytes())

View File

@ -15,7 +15,6 @@ var EmptyShaList = ethutil.Sha3Bin(ethutil.Encode([]interface{}{}))
var GenesisHeader = []interface{}{ var GenesisHeader = []interface{}{
// Previous hash (none) // Previous hash (none)
//"",
ZeroHash256, ZeroHash256,
// Sha of uncles // Sha of uncles
ethutil.Sha3Bin(ethutil.Encode([]interface{}{})), ethutil.Sha3Bin(ethutil.Encode([]interface{}{})),
@ -23,15 +22,22 @@ var GenesisHeader = []interface{}{
ZeroHash160, ZeroHash160,
// Root state // Root state
"", "",
// Sha of transactions // tx sha
//EmptyShaList, ZeroHash256,
ethutil.Sha3Bin(ethutil.Encode([]interface{}{})),
// Difficulty // Difficulty
ethutil.BigPow(2, 22), ethutil.BigPow(2, 22),
// Number
ethutil.Big0,
// Block minimum gas price
ethutil.Big0,
// Block upper gas bound
big.NewInt(1000000),
// Block gas used
ethutil.Big0,
// Time // Time
int64(0), ethutil.Big0,
// Extra // Extra
"", nil,
// Nonce // Nonce
ethutil.Sha3Bin(big.NewInt(42).Bytes()), ethutil.Sha3Bin(big.NewInt(42).Bytes()),
} }

View File

@ -49,28 +49,6 @@ func (s *State) Purge() int {
return s.trie.NewIterator().Purge() return s.trie.NewIterator().Purge()
} }
// XXX Deprecated
func (s *State) GetContract(addr []byte) *StateObject {
data := s.trie.Get(string(addr))
if data == "" {
return nil
}
// build contract
contract := NewStateObjectFromBytes(addr, []byte(data))
// Check if there's a cached state for this contract
cachedState := s.states[string(addr)]
if cachedState != nil {
contract.state = cachedState
} else {
// If it isn't cached, cache the state
s.states[string(addr)] = contract.state
}
return contract
}
func (s *State) GetStateObject(addr []byte) *StateObject { func (s *State) GetStateObject(addr []byte) *StateObject {
data := s.trie.Get(string(addr)) data := s.trie.Get(string(addr))
if data == "" { if data == "" {
@ -91,6 +69,21 @@ func (s *State) GetStateObject(addr []byte) *StateObject {
return stateObject return stateObject
} }
// Updates any given state object
func (s *State) UpdateStateObject(object *StateObject) {
addr := object.Address()
if object.state != nil {
s.states[string(addr)] = object.state
}
ethutil.Config.Db.Put(ethutil.Sha3Bin(object.Script()), object.Script())
s.trie.Update(string(addr), string(object.RlpEncode()))
s.manifest.AddObjectChange(object)
}
func (s *State) SetStateObject(stateObject *StateObject) { func (s *State) SetStateObject(stateObject *StateObject) {
s.states[string(stateObject.address)] = stateObject.state s.states[string(stateObject.address)] = stateObject.state
@ -116,18 +109,6 @@ func (s *State) Copy() *State {
return NewState(s.trie.Copy()) return NewState(s.trie.Copy())
} }
// Updates any given state object
func (s *State) UpdateStateObject(object *StateObject) {
addr := object.Address()
if object.state != nil {
s.states[string(addr)] = object.state
}
s.trie.Update(string(addr), string(object.RlpEncode()))
s.manifest.AddObjectChange(object)
}
func (s *State) Put(key, object []byte) { func (s *State) Put(key, object []byte) {
s.trie.Update(string(key), string(object)) s.trie.Update(string(key), string(object))
} }

View File

@ -39,20 +39,13 @@ type StateManager struct {
// The ethereum manager interface // The ethereum manager interface
Ethereum EthManager Ethereum EthManager
// The managed states // The managed states
// Processor state. Anything processed will be applied to this
// state
procState *State
// Comparative state it used for comparing and validating end
// results
compState *State
// Transiently state. The trans state isn't ever saved, validated and // Transiently state. The trans state isn't ever saved, validated and
// it could be used for setting account nonces without effecting // it could be used for setting account nonces without effecting
// the main states. // the main states.
transState *State transState *State
// Manifest for keeping changes regarding state objects. See `notify` // Mining state. The mining state is used purely and solely by the mining
// XXX Should we move the manifest to the State object. Benefit: // operation.
// * All states can keep their own local changes miningState *State
//manifest *Manifest
} }
func NewStateManager(ethereum EthManager) *StateManager { func NewStateManager(ethereum EthManager) *StateManager {
@ -62,30 +55,39 @@ func NewStateManager(ethereum EthManager) *StateManager {
Pow: &EasyPow{}, Pow: &EasyPow{},
Ethereum: ethereum, Ethereum: ethereum,
bc: ethereum.BlockChain(), bc: ethereum.BlockChain(),
//manifest: NewManifest(),
} }
sm.procState = ethereum.BlockChain().CurrentBlock.State() sm.transState = ethereum.BlockChain().CurrentBlock.State().Copy()
sm.transState = sm.procState.Copy() sm.miningState = ethereum.BlockChain().CurrentBlock.State().Copy()
return sm return sm
} }
func (sm *StateManager) ProcState() *State { func (sm *StateManager) CurrentState() *State {
return sm.procState return sm.Ethereum.BlockChain().CurrentBlock.State()
} }
func (sm *StateManager) TransState() *State { func (sm *StateManager) TransState() *State {
return sm.transState return sm.transState
} }
func (sm *StateManager) MiningState() *State {
return sm.miningState
}
func (sm *StateManager) NewMiningState() *State {
sm.miningState = sm.Ethereum.BlockChain().CurrentBlock.State().Copy()
return sm.miningState
}
func (sm *StateManager) BlockChain() *BlockChain { func (sm *StateManager) BlockChain() *BlockChain {
return sm.bc return sm.bc
} }
func (sm *StateManager) MakeContract(tx *Transaction) *StateObject { func (sm *StateManager) MakeContract(state *State, tx *Transaction) *StateObject {
contract := MakeContract(tx, sm.procState) contract := MakeContract(tx, state)
if contract != nil { if contract != nil {
sm.procState.states[string(tx.Hash()[12:])] = contract.state state.states[string(tx.CreationAddress())] = contract.state
return contract return contract
} }
@ -95,7 +97,7 @@ func (sm *StateManager) MakeContract(tx *Transaction) *StateObject {
// Apply transactions uses the transaction passed to it and applies them onto // Apply transactions uses the transaction passed to it and applies them onto
// the current processing state. // the current processing state.
func (sm *StateManager) ApplyTransactions(block *Block, txs []*Transaction) { func (sm *StateManager) ApplyTransactions(state *State, block *Block, txs []*Transaction) {
// Process each transaction/contract // Process each transaction/contract
for _, tx := range txs { for _, tx := range txs {
// If there's no recipient, it's a contract // If there's no recipient, it's a contract
@ -104,9 +106,9 @@ func (sm *StateManager) ApplyTransactions(block *Block, txs []*Transaction) {
if tx.IsContract() { if tx.IsContract() {
err := sm.Ethereum.TxPool().ProcessTransaction(tx, block, false) err := sm.Ethereum.TxPool().ProcessTransaction(tx, block, false)
if err == nil { if err == nil {
contract := sm.MakeContract(tx) contract := sm.MakeContract(state, tx)
if contract != nil { if contract != nil {
sm.EvalScript(contract.Init(), contract, tx, block) sm.EvalScript(state, contract.Init(), contract, tx, block)
} else { } else {
ethutil.Config.Log.Infoln("[STATE] Unable to create contract") ethutil.Config.Log.Infoln("[STATE] Unable to create contract")
} }
@ -115,9 +117,10 @@ func (sm *StateManager) ApplyTransactions(block *Block, txs []*Transaction) {
} }
} else { } else {
err := sm.Ethereum.TxPool().ProcessTransaction(tx, block, false) err := sm.Ethereum.TxPool().ProcessTransaction(tx, block, false)
contract := sm.procState.GetContract(tx.Recipient) contract := state.GetStateObject(tx.Recipient)
ethutil.Config.Log.Debugf("contract recip %x\n", tx.Recipient)
if err == nil && len(contract.Script()) > 0 { if err == nil && len(contract.Script()) > 0 {
sm.EvalScript(contract.Script(), contract, tx, block) sm.EvalScript(state, contract.Script(), contract, tx, block)
} else if err != nil { } else if err != nil {
ethutil.Config.Log.Infoln("[STATE] process:", err) ethutil.Config.Log.Infoln("[STATE] process:", err)
} }
@ -125,20 +128,8 @@ func (sm *StateManager) ApplyTransactions(block *Block, txs []*Transaction) {
} }
} }
// The prepare function, prepares the state manager for the next
// "ProcessBlock" action.
func (sm *StateManager) Prepare(processor *State, comparative *State) {
sm.compState = comparative
sm.procState = processor
}
// Default prepare function
func (sm *StateManager) PrepareDefault(block *Block) {
sm.Prepare(sm.BlockChain().CurrentBlock.State(), block.State())
}
// Block processing and validating with a given (temporarily) state // Block processing and validating with a given (temporarily) state
func (sm *StateManager) ProcessBlock(block *Block, dontReact bool) error { func (sm *StateManager) ProcessBlock(state *State, block *Block, dontReact bool) error {
// Processing a blocks may never happen simultaneously // Processing a blocks may never happen simultaneously
sm.mutex.Lock() sm.mutex.Lock()
defer sm.mutex.Unlock() defer sm.mutex.Unlock()
@ -153,7 +144,7 @@ func (sm *StateManager) ProcessBlock(block *Block, dontReact bool) error {
// we don't want to undo but since undo only happens on dirty // we don't want to undo but since undo only happens on dirty
// nodes this won't happen because Commit would have been called // nodes this won't happen because Commit would have been called
// before that. // before that.
defer sm.bc.CurrentBlock.Undo() defer state.Reset()
// Check if we have the parent hash, if it isn't known we discard it // Check if we have the parent hash, if it isn't known we discard it
// Reasons might be catching up or simply an invalid block // Reasons might be catching up or simply an invalid block
@ -162,7 +153,7 @@ func (sm *StateManager) ProcessBlock(block *Block, dontReact bool) error {
} }
// Process the transactions on to current block // Process the transactions on to current block
sm.ApplyTransactions(sm.bc.CurrentBlock, block.Transactions()) sm.ApplyTransactions(state, sm.bc.CurrentBlock, block.Transactions())
// Block validation // Block validation
if err := sm.ValidateBlock(block); err != nil { if err := sm.ValidateBlock(block); err != nil {
@ -172,35 +163,35 @@ func (sm *StateManager) ProcessBlock(block *Block, dontReact bool) error {
// I'm not sure, but I don't know if there should be thrown // I'm not sure, but I don't know if there should be thrown
// any errors at this time. // any errors at this time.
if err := sm.AccumelateRewards(block); err != nil { if err := sm.AccumelateRewards(state, block); err != nil {
fmt.Println("[SM] Error accumulating reward", err) fmt.Println("[SM] Error accumulating reward", err)
return err return err
} }
if !sm.compState.Cmp(sm.procState) { //if !sm.compState.Cmp(state) {
return fmt.Errorf("Invalid merkle root. Expected %x, got %x", sm.compState.trie.Root, sm.procState.trie.Root) if !block.State().Cmp(state) {
return fmt.Errorf("Invalid merkle root. Expected %x, got %x", block.State().trie.Root, state.trie.Root)
} }
// Calculate the new total difficulty and sync back to the db // Calculate the new total difficulty and sync back to the db
if sm.CalculateTD(block) { if sm.CalculateTD(block) {
// Sync the current block's state to the database and cancelling out the deferred Undo // Sync the current block's state to the database and cancelling out the deferred Undo
sm.procState.Sync() state.Sync()
// Add the block to the chain // Add the block to the chain
sm.bc.Add(block) sm.bc.Add(block)
sm.notifyChanges(state)
ethutil.Config.Log.Infof("[STATE] Added block #%d (%x)\n", block.BlockInfo().Number, block.Hash()) ethutil.Config.Log.Infof("[STATE] Added block #%d (%x)\n", block.BlockInfo().Number, block.Hash())
if dontReact == false { if dontReact == false {
sm.Ethereum.Reactor().Post("newBlock", block) sm.Ethereum.Reactor().Post("newBlock", block)
sm.notifyChanges() state.manifest.Reset()
sm.procState.manifest.Reset()
} }
sm.Ethereum.Broadcast(ethwire.MsgBlockTy, []interface{}{block.Value().Val}) sm.Ethereum.Broadcast(ethwire.MsgBlockTy, []interface{}{block.Value().Val})
sm.Ethereum.TxPool().RemoveInvalid(sm.procState) sm.Ethereum.TxPool().RemoveInvalid(state)
} else { } else {
fmt.Println("total diff failed") fmt.Println("total diff failed")
} }
@ -276,21 +267,21 @@ func CalculateUncleReward(block *Block) *big.Int {
return UncleReward return UncleReward
} }
func (sm *StateManager) AccumelateRewards(block *Block) error { func (sm *StateManager) AccumelateRewards(state *State, block *Block) error {
// Get the account associated with the coinbase // Get the account associated with the coinbase
account := sm.procState.GetAccount(block.Coinbase) account := state.GetAccount(block.Coinbase)
// Reward amount of ether to the coinbase address // Reward amount of ether to the coinbase address
account.AddAmount(CalculateBlockReward(block, len(block.Uncles))) account.AddAmount(CalculateBlockReward(block, len(block.Uncles)))
addr := make([]byte, len(block.Coinbase)) addr := make([]byte, len(block.Coinbase))
copy(addr, block.Coinbase) copy(addr, block.Coinbase)
sm.procState.UpdateStateObject(account) state.UpdateStateObject(account)
for _, uncle := range block.Uncles { for _, uncle := range block.Uncles {
uncleAccount := sm.procState.GetAccount(uncle.Coinbase) uncleAccount := state.GetAccount(uncle.Coinbase)
uncleAccount.AddAmount(CalculateUncleReward(uncle)) uncleAccount.AddAmount(CalculateUncleReward(uncle))
sm.procState.UpdateStateObject(uncleAccount) state.UpdateStateObject(uncleAccount)
} }
return nil return nil
@ -300,8 +291,8 @@ func (sm *StateManager) Stop() {
sm.bc.Stop() sm.bc.Stop()
} }
func (sm *StateManager) EvalScript(script []byte, object *StateObject, tx *Transaction, block *Block) { func (sm *StateManager) EvalScript(state *State, script []byte, object *StateObject, tx *Transaction, block *Block) {
account := sm.procState.GetAccount(tx.Sender()) account := state.GetAccount(tx.Sender())
err := account.ConvertGas(tx.Gas, tx.GasPrice) err := account.ConvertGas(tx.Gas, tx.GasPrice)
if err != nil { if err != nil {
@ -309,8 +300,8 @@ func (sm *StateManager) EvalScript(script []byte, object *StateObject, tx *Trans
return return
} }
closure := NewClosure(account, object, script, sm.procState, tx.Gas, tx.GasPrice) closure := NewClosure(account, object, script, state, tx.Gas, tx.GasPrice)
vm := NewVm(sm.procState, sm, RuntimeVars{ vm := NewVm(state, sm, RuntimeVars{
Origin: account.Address(), Origin: account.Address(),
BlockNumber: block.BlockInfo().Number, BlockNumber: block.BlockInfo().Number,
PrevHash: block.PrevHash, PrevHash: block.PrevHash,
@ -323,16 +314,16 @@ func (sm *StateManager) EvalScript(script []byte, object *StateObject, tx *Trans
closure.Call(vm, tx.Data, nil) closure.Call(vm, tx.Data, nil)
// Update the account (refunds) // Update the account (refunds)
sm.procState.UpdateStateObject(account) state.UpdateStateObject(account)
sm.procState.UpdateStateObject(object) state.UpdateStateObject(object)
} }
func (sm *StateManager) notifyChanges() { func (sm *StateManager) notifyChanges(state *State) {
for addr, stateObject := range sm.procState.manifest.objectChanges { for addr, stateObject := range state.manifest.objectChanges {
sm.Ethereum.Reactor().Post("object:"+addr, stateObject) sm.Ethereum.Reactor().Post("object:"+addr, stateObject)
} }
for stateObjectAddr, mappedObjects := range sm.procState.manifest.storageChanges { for stateObjectAddr, mappedObjects := range state.manifest.storageChanges {
for addr, value := range mappedObjects { for addr, value := range mappedObjects {
sm.Ethereum.Reactor().Post("storage:"+stateObjectAddr+":"+addr, &StorageState{[]byte(stateObjectAddr), []byte(addr), value}) sm.Ethereum.Reactor().Post("storage:"+stateObjectAddr+":"+addr, &StorageState{[]byte(stateObjectAddr), []byte(addr), value})
} }

View File

@ -10,8 +10,9 @@ type StateObject struct {
// Address of the object // Address of the object
address []byte address []byte
// Shared attributes // Shared attributes
Amount *big.Int Amount *big.Int
Nonce uint64 ScriptHash []byte
Nonce uint64
// Contract related attributes // Contract related attributes
state *State state *State
script []byte script []byte
@ -22,12 +23,10 @@ type StateObject struct {
func MakeContract(tx *Transaction, state *State) *StateObject { func MakeContract(tx *Transaction, state *State) *StateObject {
// Create contract if there's no recipient // Create contract if there's no recipient
if tx.IsContract() { if tx.IsContract() {
// FIXME addr := tx.CreationAddress()
addr := tx.Hash()[12:]
value := tx.Value value := tx.Value
contract := NewContract(addr, value, []byte("")) contract := NewContract(addr, value, ZeroHash256)
state.UpdateStateObject(contract)
contract.script = tx.Data contract.script = tx.Data
contract.initScript = tx.Init contract.initScript = tx.Init
@ -146,9 +145,10 @@ func (c *StateObject) RlpEncode() []byte {
if c.state != nil { if c.state != nil {
root = c.state.trie.Root root = c.state.trie.Root
} else { } else {
root = nil root = ZeroHash256
} }
return ethutil.Encode([]interface{}{c.Amount, c.Nonce, root, c.script})
return ethutil.Encode([]interface{}{c.Amount, c.Nonce, root, ethutil.Sha3Bin(c.script)})
} }
func (c *StateObject) RlpDecode(data []byte) { func (c *StateObject) RlpDecode(data []byte) {
@ -157,7 +157,10 @@ func (c *StateObject) RlpDecode(data []byte) {
c.Amount = decoder.Get(0).BigInt() c.Amount = decoder.Get(0).BigInt()
c.Nonce = decoder.Get(1).Uint() c.Nonce = decoder.Get(1).Uint()
c.state = NewState(ethutil.NewTrie(ethutil.Config.Db, decoder.Get(2).Interface())) c.state = NewState(ethutil.NewTrie(ethutil.Config.Db, decoder.Get(2).Interface()))
c.script = decoder.Get(3).Bytes()
c.ScriptHash = decoder.Get(3).Bytes()
c.script, _ = ethutil.Config.Db.Get(c.ScriptHash)
} }
// Storage change object. Used by the manifest for notifying changes to // Storage change object. Used by the manifest for notifying changes to

View File

@ -0,0 +1,25 @@
package ethchain
import (
"fmt"
"github.com/ethereum/eth-go/ethdb"
"github.com/ethereum/eth-go/ethutil"
"testing"
)
func TestSync(t *testing.T) {
ethutil.ReadConfig("", ethutil.LogStd)
db, _ := ethdb.NewMemDatabase()
state := NewState(ethutil.NewTrie(db, ""))
contract := NewContract([]byte("aa"), ethutil.Big1, ZeroHash256)
contract.script = []byte{42}
state.UpdateStateObject(contract)
state.Sync()
object := state.GetStateObject([]byte("aa"))
fmt.Printf("%x\n", object.Script())
}

View File

@ -60,7 +60,7 @@ func (tx *Transaction) IsContract() bool {
} }
func (tx *Transaction) CreationAddress() []byte { func (tx *Transaction) CreationAddress() []byte {
return tx.Hash()[12:] return ethutil.Sha3Bin(ethutil.NewValue([]interface{}{tx.Sender(), tx.Nonce}).Encode())[12:]
} }
func (tx *Transaction) Signature(key []byte) []byte { func (tx *Transaction) Signature(key []byte) []byte {
@ -109,10 +109,8 @@ func (tx *Transaction) Sign(privk []byte) error {
return nil return nil
} }
// [ NONCE, VALUE, GASPRICE, GAS, TO, DATA, V, R, S ]
// [ NONCE, VALUE, GASPRICE, GAS, 0, CODE, INIT, V, R, S ]
func (tx *Transaction) RlpData() interface{} { func (tx *Transaction) RlpData() interface{} {
data := []interface{}{tx.Nonce, tx.Value, tx.GasPrice, tx.Gas, tx.Recipient, tx.Data} data := []interface{}{tx.Nonce, tx.GasPrice, tx.Gas, tx.Recipient, tx.Value, tx.Data}
if tx.contractCreation { if tx.contractCreation {
data = append(data, tx.Init) data = append(data, tx.Init)
@ -135,10 +133,10 @@ func (tx *Transaction) RlpDecode(data []byte) {
func (tx *Transaction) RlpValueDecode(decoder *ethutil.Value) { func (tx *Transaction) RlpValueDecode(decoder *ethutil.Value) {
tx.Nonce = decoder.Get(0).Uint() tx.Nonce = decoder.Get(0).Uint()
tx.Value = decoder.Get(1).BigInt() tx.GasPrice = decoder.Get(1).BigInt()
tx.GasPrice = decoder.Get(2).BigInt() tx.Gas = decoder.Get(2).BigInt()
tx.Gas = decoder.Get(3).BigInt() tx.Recipient = decoder.Get(3).Bytes()
tx.Recipient = decoder.Get(4).Bytes() tx.Value = decoder.Get(4).BigInt()
tx.Data = decoder.Get(5).Bytes() tx.Data = decoder.Get(5).Bytes()
// If the list is of length 10 it's a contract creation tx // If the list is of length 10 it's a contract creation tx

View File

@ -131,9 +131,10 @@ func (pool *TxPool) ProcessTransaction(tx *Transaction, block *Block, toContract
block.state.UpdateStateObject(sender) block.state.UpdateStateObject(sender)
log.Printf("[TXPL] Processed Tx %x\n", tx.Hash()) ethutil.Config.Log.Infof("[TXPL] Processed Tx %x\n", tx.Hash())
pool.notifySubscribers(TxPost, tx) // Notify all subscribers
pool.Ethereum.Reactor().Post("newTx:post", tx)
return return
} }
@ -148,7 +149,8 @@ func (pool *TxPool) ValidateTransaction(tx *Transaction) error {
} }
// Get the sender // Get the sender
sender := pool.Ethereum.StateManager().procState.GetAccount(tx.Sender()) //sender := pool.Ethereum.StateManager().procState.GetAccount(tx.Sender())
sender := pool.Ethereum.StateManager().CurrentState().GetAccount(tx.Sender())
totAmount := new(big.Int).Add(tx.Value, new(big.Int).Mul(TxFee, TxFeeRat)) totAmount := new(big.Int).Add(tx.Value, new(big.Int).Mul(TxFee, TxFeeRat))
// Make sure there's enough in the sender's account. Having insufficient // Make sure there's enough in the sender's account. Having insufficient
@ -188,10 +190,7 @@ out:
pool.addTransaction(tx) pool.addTransaction(tx)
// Notify the subscribers // Notify the subscribers
pool.Ethereum.Reactor().Post("newTx", tx) pool.Ethereum.Reactor().Post("newTx:pre", tx)
// Notify the subscribers
pool.notifySubscribers(TxPre, tx)
} }
case <-pool.quit: case <-pool.quit:
break out break out
@ -252,14 +251,3 @@ func (pool *TxPool) Stop() {
log.Println("[TXP] Stopped") log.Println("[TXP] Stopped")
} }
func (pool *TxPool) Subscribe(channel chan TxMsg) {
pool.subscribers = append(pool.subscribers, channel)
}
func (pool *TxPool) notifySubscribers(ty TxMsgTy, tx *Transaction) {
msg := TxMsg{Type: ty, Tx: tx}
for _, subscriber := range pool.subscribers {
subscriber <- msg
}
}

View File

@ -95,7 +95,6 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro
if ethutil.Config.Debug { if ethutil.Config.Debug {
ethutil.Config.Log.Debugf("# op\n") ethutil.Config.Log.Debugf("# op\n")
} }
fmt.Println(closure.Script)
for { for {
// The base for all big integer arithmetic // The base for all big integer arithmetic
@ -472,7 +471,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro
args := mem.Get(inOffset.Int64(), inSize.Int64()) args := mem.Get(inOffset.Int64(), inSize.Int64())
// Fetch the contract which will serve as the closure body // Fetch the contract which will serve as the closure body
contract := vm.state.GetContract(addr.Bytes()) contract := vm.state.GetStateObject(addr.Bytes())
if contract != nil { if contract != nil {
// Prepay for the gas // Prepay for the gas

View File

@ -12,7 +12,7 @@ import (
) )
func TestRun4(t *testing.T) { func TestRun4(t *testing.T) {
ethutil.ReadConfig("") ethutil.ReadConfig("", ethutil.LogStd)
db, _ := ethdb.NewMemDatabase() db, _ := ethdb.NewMemDatabase()
state := NewState(ethutil.NewTrie(db, "")) state := NewState(ethutil.NewTrie(db, ""))

View File

@ -222,7 +222,7 @@ func (s *Ethereum) ConnectToPeer(addr string) error {
if phost == chost { if phost == chost {
alreadyConnected = true alreadyConnected = true
ethutil.Config.Log.Debugf("[SERV] Peer %s already added.\n", chost) //ethutil.Config.Log.Debugf("[SERV] Peer %s already added.\n", chost)
return return
} }
}) })
@ -235,7 +235,7 @@ func (s *Ethereum) ConnectToPeer(addr string) error {
s.peers.PushBack(peer) s.peers.PushBack(peer)
log.Printf("[SERV] Adding peer %d / %d\n", s.peers.Len(), s.MaxPeers) ethutil.Config.Log.Infof("[SERV] Adding peer (%s) %d / %d\n", addr, s.peers.Len(), s.MaxPeers)
} }
return nil return nil

View File

@ -5,7 +5,6 @@ import (
"github.com/ethereum/eth-go/ethchain" "github.com/ethereum/eth-go/ethchain"
"github.com/ethereum/eth-go/ethutil" "github.com/ethereum/eth-go/ethutil"
"github.com/ethereum/eth-go/ethwire" "github.com/ethereum/eth-go/ethwire"
"log"
) )
type Miner struct { type Miner struct {
@ -26,7 +25,7 @@ func NewDefaultMiner(coinbase []byte, ethereum ethchain.EthManager) Miner {
quitChan := make(chan ethutil.React, 1) // This is the channel that can exit the miner thread quitChan := make(chan ethutil.React, 1) // This is the channel that can exit the miner thread
ethereum.Reactor().Subscribe("newBlock", reactChan) ethereum.Reactor().Subscribe("newBlock", reactChan)
ethereum.Reactor().Subscribe("newTx", reactChan) ethereum.Reactor().Subscribe("newTx:pre", reactChan)
// We need the quit chan to be a Reactor event. // We need the quit chan to be a Reactor event.
// The POW search method is actually blocking and if we don't // The POW search method is actually blocking and if we don't
@ -34,7 +33,7 @@ func NewDefaultMiner(coinbase []byte, ethereum ethchain.EthManager) Miner {
// The miner overseer will never get the reactor events themselves // The miner overseer will never get the reactor events themselves
// Only after the miner will find the sha // Only after the miner will find the sha
ethereum.Reactor().Subscribe("newBlock", quitChan) ethereum.Reactor().Subscribe("newBlock", quitChan)
ethereum.Reactor().Subscribe("newTx", quitChan) ethereum.Reactor().Subscribe("newTx:pre", quitChan)
miner := Miner{ miner := Miner{
pow: &ethchain.EasyPow{}, pow: &ethchain.EasyPow{},
@ -53,18 +52,18 @@ func NewDefaultMiner(coinbase []byte, ethereum ethchain.EthManager) Miner {
} }
func (miner *Miner) Start() { func (miner *Miner) Start() {
// Prepare inital block // Prepare inital block
miner.ethereum.StateManager().Prepare(miner.block.State(), miner.block.State()) //miner.ethereum.StateManager().Prepare(miner.block.State(), miner.block.State())
go func() { miner.listener() }() go miner.listener()
} }
func (miner *Miner) listener() { func (miner *Miner) listener() {
for { for {
select { select {
case chanMessage := <-miner.reactChan: case chanMessage := <-miner.reactChan:
if block, ok := chanMessage.Resource.(*ethchain.Block); ok { if block, ok := chanMessage.Resource.(*ethchain.Block); ok {
log.Println("[MINER] Got new block via Reactor") ethutil.Config.Log.Infoln("[MINER] Got new block via Reactor")
if bytes.Compare(miner.ethereum.BlockChain().CurrentBlock.Hash(), block.Hash()) == 0 { if bytes.Compare(miner.ethereum.BlockChain().CurrentBlock.Hash(), block.Hash()) == 0 {
// TODO: Perhaps continue mining to get some uncle rewards // TODO: Perhaps continue mining to get some uncle rewards
log.Println("[MINER] New top block found resetting state") ethutil.Config.Log.Infoln("[MINER] New top block found resetting state")
// Filter out which Transactions we have that were not in this block // Filter out which Transactions we have that were not in this block
var newtxs []*ethchain.Transaction var newtxs []*ethchain.Transaction
@ -86,15 +85,15 @@ func (miner *Miner) listener() {
} else { } else {
if bytes.Compare(block.PrevHash, miner.ethereum.BlockChain().CurrentBlock.PrevHash) == 0 { if bytes.Compare(block.PrevHash, miner.ethereum.BlockChain().CurrentBlock.PrevHash) == 0 {
log.Println("[MINER] Adding uncle block") ethutil.Config.Log.Infoln("[MINER] Adding uncle block")
miner.uncles = append(miner.uncles, block) miner.uncles = append(miner.uncles, block)
miner.ethereum.StateManager().Prepare(miner.block.State(), miner.block.State()) //miner.ethereum.StateManager().Prepare(miner.block.State(), miner.block.State())
} }
} }
} }
if tx, ok := chanMessage.Resource.(*ethchain.Transaction); ok { if tx, ok := chanMessage.Resource.(*ethchain.Transaction); ok {
//log.Println("[MINER] Got new transaction from Reactor", tx) //log.Infoln("[MINER] Got new transaction from Reactor", tx)
found := false found := false
for _, ctx := range miner.txs { for _, ctx := range miner.txs {
if found = bytes.Compare(ctx.Hash(), tx.Hash()) == 0; found { if found = bytes.Compare(ctx.Hash(), tx.Hash()) == 0; found {
@ -103,49 +102,37 @@ func (miner *Miner) listener() {
} }
if found == false { if found == false {
//log.Println("[MINER] We did not know about this transaction, adding") //log.Infoln("[MINER] We did not know about this transaction, adding")
miner.txs = append(miner.txs, tx) miner.txs = append(miner.txs, tx)
miner.block = miner.ethereum.BlockChain().NewBlock(miner.coinbase, miner.txs) miner.block = miner.ethereum.BlockChain().NewBlock(miner.coinbase, miner.txs)
miner.block.SetTransactions(miner.txs) miner.block.SetTransactions(miner.txs)
} else { } else {
//log.Println("[MINER] We already had this transaction, ignoring") //log.Infoln("[MINER] We already had this transaction, ignoring")
} }
} }
default: default:
log.Println("[MINER] Mining on block. Includes", len(miner.txs), "transactions") ethutil.Config.Log.Infoln("[MINER] Mining on block. Includes", len(miner.txs), "transactions")
// Apply uncles // Apply uncles
if len(miner.uncles) > 0 { if len(miner.uncles) > 0 {
miner.block.SetUncles(miner.uncles) miner.block.SetUncles(miner.uncles)
} }
// FIXME @ maranh, first block doesn't need this. Everything after the first block does.
// Please check and fix
miner.ethereum.StateManager().Prepare(miner.block.State(), miner.block.State())
// Apply all transactions to the block // Apply all transactions to the block
miner.ethereum.StateManager().ApplyTransactions(miner.block, miner.block.Transactions()) miner.ethereum.StateManager().ApplyTransactions(miner.block.State(), miner.block, miner.block.Transactions())
miner.ethereum.StateManager().AccumelateRewards(miner.block) miner.ethereum.StateManager().AccumelateRewards(miner.block.State(), miner.block)
// Search the nonce // Search the nonce
//log.Println("[MINER] Initialision complete, starting mining")
miner.block.Nonce = miner.pow.Search(miner.block, miner.quitChan) miner.block.Nonce = miner.pow.Search(miner.block, miner.quitChan)
if miner.block.Nonce != nil { if miner.block.Nonce != nil {
miner.ethereum.StateManager().PrepareDefault(miner.block) err := miner.ethereum.StateManager().ProcessBlock(miner.ethereum.StateManager().CurrentState(), miner.block, true)
err := miner.ethereum.StateManager().ProcessBlock(miner.block, true)
if err != nil { if err != nil {
log.Println(err) ethutil.Config.Log.Infoln(err)
miner.txs = []*ethchain.Transaction{} // Move this somewhere neat miner.txs = []*ethchain.Transaction{} // Move this somewhere neat
miner.block = miner.ethereum.BlockChain().NewBlock(miner.coinbase, miner.txs) miner.block = miner.ethereum.BlockChain().NewBlock(miner.coinbase, miner.txs)
} else { } else {
/*
// XXX @maranh This is already done in the state manager, why a 2nd time?
if !miner.ethereum.StateManager().Pow.Verify(miner.block.HashNoNonce(), miner.block.Difficulty, miner.block.Nonce) {
log.Printf("Second stage verification error: Block's nonce is invalid (= %v)\n", ethutil.Hex(miner.block.Nonce))
}
*/
miner.ethereum.Broadcast(ethwire.MsgBlockTy, []interface{}{miner.block.Value().Val}) miner.ethereum.Broadcast(ethwire.MsgBlockTy, []interface{}{miner.block.Value().Val})
log.Printf("[MINER] 🔨 Mined block %x\n", miner.block.Hash()) ethutil.Config.Log.Infof("[MINER] 🔨 Mined block %x\n", miner.block.Hash())
miner.txs = []*ethchain.Transaction{} // Move this somewhere neat miner.txs = []*ethchain.Transaction{} // Move this somewhere neat
miner.block = miner.ethereum.BlockChain().NewBlock(miner.coinbase, miner.txs) miner.block = miner.ethereum.BlockChain().NewBlock(miner.coinbase, miner.txs)

View File

@ -45,7 +45,7 @@ func (lib *PEthereum) GetKey() *PKey {
} }
func (lib *PEthereum) GetStateObject(address string) *PStateObject { func (lib *PEthereum) GetStateObject(address string) *PStateObject {
stateObject := lib.stateManager.ProcState().GetContract(ethutil.FromHex(address)) stateObject := lib.stateManager.CurrentState().GetStateObject(ethutil.FromHex(address))
if stateObject != nil { if stateObject != nil {
return NewPStateObject(stateObject) return NewPStateObject(stateObject)
} }
@ -160,8 +160,8 @@ func (lib *PEthereum) createTx(key, recipient, valueStr, gasStr, gasPriceStr, in
} }
acc := lib.stateManager.TransState().GetStateObject(keyPair.Address()) acc := lib.stateManager.TransState().GetStateObject(keyPair.Address())
//acc := lib.stateManager.GetAddrState(keyPair.Address())
tx.Nonce = acc.Nonce tx.Nonce = acc.Nonce
acc.Nonce += 1
lib.stateManager.TransState().SetStateObject(acc) lib.stateManager.TransState().SetStateObject(acc)
tx.Sign(keyPair.PrivateKey) tx.Sign(keyPair.PrivateKey)

View File

@ -112,6 +112,14 @@ func (c *PStateObject) IsContract() bool {
return false return false
} }
func (c *PStateObject) Script() string {
if c.object != nil {
return ethutil.Hex(c.object.Script())
}
return ""
}
type PStorageState struct { type PStorageState struct {
StateAddress string StateAddress string
Address string Address string

View File

@ -7,13 +7,13 @@ import (
// The different number of units // The different number of units
var ( var (
Ether = BigPow(10, 18) Ether = BigPow(10, 18)
Finney = BigPow(10, 15) Finney = BigPow(10, 15)
Szabo = BigPow(10, 12) Szabo = BigPow(10, 12)
Vita = BigPow(10, 9) Shannon = BigPow(10, 9)
Turing = BigPow(10, 6) Babbage = BigPow(10, 6)
Eins = BigPow(10, 3) Ada = BigPow(10, 3)
Wei = big.NewInt(1) Wei = big.NewInt(1)
) )
// Currency to string // Currency to string
@ -27,12 +27,12 @@ func CurrencyToString(num *big.Int) string {
return fmt.Sprintf("%v Finney", new(big.Int).Div(num, Finney)) return fmt.Sprintf("%v Finney", new(big.Int).Div(num, Finney))
case num.Cmp(Szabo) >= 0: case num.Cmp(Szabo) >= 0:
return fmt.Sprintf("%v Szabo", new(big.Int).Div(num, Szabo)) return fmt.Sprintf("%v Szabo", new(big.Int).Div(num, Szabo))
case num.Cmp(Vita) >= 0: case num.Cmp(Shannon) >= 0:
return fmt.Sprintf("%v Vita", new(big.Int).Div(num, Vita)) return fmt.Sprintf("%v Shannon", new(big.Int).Div(num, Shannon))
case num.Cmp(Turing) >= 0: case num.Cmp(Babbage) >= 0:
return fmt.Sprintf("%v Turing", new(big.Int).Div(num, Turing)) return fmt.Sprintf("%v Babbage", new(big.Int).Div(num, Babbage))
case num.Cmp(Eins) >= 0: case num.Cmp(Ada) >= 0:
return fmt.Sprintf("%v Eins", new(big.Int).Div(num, Eins)) return fmt.Sprintf("%v Ada", new(big.Int).Div(num, Ada))
} }
return fmt.Sprintf("%v Wei", num) return fmt.Sprintf("%v Wei", num)

View File

@ -26,15 +26,15 @@ func TestCommon(t *testing.T) {
t.Error("Got", szabo) t.Error("Got", szabo)
} }
if vito != "10 Vita" { if vito != "10 Shannon" {
t.Error("Got", vito) t.Error("Got", vito)
} }
if turing != "10 Turing" { if turing != "10 Babbage" {
t.Error("Got", turing) t.Error("Got", turing)
} }
if eins != "10 Eins" { if eins != "10 Ada" {
t.Error("Got", eins) t.Error("Got", eins)
} }

View File

@ -9,14 +9,6 @@ import (
"runtime" "runtime"
) )
// Log types available
type LogType byte
const (
LogTypeStdIn = 1
LogTypeFile = 2
)
// Config struct // Config struct
type config struct { type config struct {
Db Database Db Database
@ -34,7 +26,7 @@ var Config *config
// Read config // Read config
// //
// Initialize the global Config variable with default settings // Initialize the global Config variable with default settings
func ReadConfig(base string) *config { func ReadConfig(base string, logTypes LoggerType) *config {
if Config == nil { if Config == nil {
usr, _ := user.Current() usr, _ := user.Current()
path := path.Join(usr.HomeDir, base) path := path.Join(usr.HomeDir, base)
@ -50,8 +42,8 @@ func ReadConfig(base string) *config {
} }
} }
Config = &config{ExecPath: path, Debug: true, Ver: "0.5.0 RC6"} Config = &config{ExecPath: path, Debug: true, Ver: "0.5.0 RC7"}
Config.Log = NewLogger(LogFile|LogStd, LogLevelDebug) Config.Log = NewLogger(logTypes, LogLevelDebug)
Config.SetClientString("/Ethereum(G)") Config.SetClientString("/Ethereum(G)")
} }
@ -138,7 +130,6 @@ func (log *Logger) Infoln(v ...interface{}) {
return return
} }
//fmt.Println(len(log.logSys))
for _, logger := range log.logSys { for _, logger := range log.logSys {
logger.Println(v...) logger.Println(v...)
} }
@ -153,3 +144,15 @@ func (log *Logger) Infof(format string, v ...interface{}) {
logger.Printf(format, v...) logger.Printf(format, v...)
} }
} }
func (log *Logger) Fatal(v ...interface{}) {
if log.logLevel > LogLevelInfo {
return
}
for _, logger := range log.logSys {
logger.Println(v...)
}
os.Exit(1)
}

View File

@ -46,6 +46,7 @@ func (e *ReactorEvent) Remove(ch chan React) {
// Basic reactor resource // Basic reactor resource
type React struct { type React struct {
Resource interface{} Resource interface{}
Event string
} }
// The reactor basic engine. Acts as bridge // The reactor basic engine. Acts as bridge
@ -81,6 +82,6 @@ func (reactor *ReactorEngine) Unsubscribe(event string, ch chan React) {
func (reactor *ReactorEngine) Post(event string, resource interface{}) { func (reactor *ReactorEngine) Post(event string, resource interface{}) {
ev := reactor.patterns[event] ev := reactor.patterns[event]
if ev != nil { if ev != nil {
ev.Post(React{Resource: resource}) ev.Post(React{Resource: resource, Event: event})
} }
} }

138
peer.go
View File

@ -18,7 +18,7 @@ const (
// The size of the output buffer for writing messages // The size of the output buffer for writing messages
outputBufferSize = 50 outputBufferSize = 50
// Current protocol version // Current protocol version
ProtocolVersion = 8 ProtocolVersion = 10
) )
type DiscReason byte type DiscReason byte
@ -127,6 +127,7 @@ type Peer struct {
// Indicated whether the node is catching up or not // Indicated whether the node is catching up or not
catchingUp bool catchingUp bool
diverted bool
blocksRequested int blocksRequested int
Version string Version string
@ -190,7 +191,6 @@ func (p *Peer) QueueMessage(msg *ethwire.Msg) {
if atomic.LoadInt32(&p.connected) != 1 { if atomic.LoadInt32(&p.connected) != 1 {
return return
} }
p.outputQueue <- msg p.outputQueue <- msg
} }
@ -268,7 +268,6 @@ func (p *Peer) HandleInbound() {
for atomic.LoadInt32(&p.disconnect) == 0 { for atomic.LoadInt32(&p.disconnect) == 0 {
// HMM? // HMM?
time.Sleep(500 * time.Millisecond) time.Sleep(500 * time.Millisecond)
// Wait for a message from the peer // Wait for a message from the peer
msgs, err := ethwire.ReadMessages(p.conn) msgs, err := ethwire.ReadMessages(p.conn)
if err != nil { if err != nil {
@ -300,39 +299,44 @@ func (p *Peer) HandleInbound() {
var err error var err error
// Make sure we are actually receiving anything // Make sure we are actually receiving anything
if msg.Data.Len()-1 > 1 && p.catchingUp { if msg.Data.Len()-1 > 1 && p.diverted {
// We requested blocks and now we need to make sure we have a common ancestor somewhere in these blocks so we can find // We requested blocks and now we need to make sure we have a common ancestor somewhere in these blocks so we can find
// common ground to start syncing from // common ground to start syncing from
lastBlock = ethchain.NewBlockFromRlpValue(msg.Data.Get(msg.Data.Len() - 1)) lastBlock = ethchain.NewBlockFromRlpValue(msg.Data.Get(msg.Data.Len() - 1))
if !p.ethereum.StateManager().BlockChain().HasBlock(lastBlock.Hash()) { ethutil.Config.Log.Infof("[PEER] Last block: %x. Checking if we have it locally.\n", lastBlock.Hash())
// If we can't find a common ancenstor we need to request more blocks.
// FIXME: At one point this won't scale anymore since we are not asking for an offset
// we just keep increasing the amount of blocks.
//fmt.Println("[PEER] No common ancestor found, requesting more blocks.")
p.blocksRequested = p.blocksRequested * 2
p.catchingUp = false
p.SyncWithBlocks()
}
for i := msg.Data.Len() - 1; i >= 0; i-- { for i := msg.Data.Len() - 1; i >= 0; i-- {
block = ethchain.NewBlockFromRlpValue(msg.Data.Get(i)) block = ethchain.NewBlockFromRlpValue(msg.Data.Get(i))
// Do we have this block on our chain? If so we can continue // Do we have this block on our chain? If so we can continue
if !p.ethereum.StateManager().BlockChain().HasBlock(block.Hash()) { if !p.ethereum.StateManager().BlockChain().HasBlock(block.Hash()) {
// We don't have this block, but we do have a block with the same prevHash, diversion time! // We don't have this block, but we do have a block with the same prevHash, diversion time!
if p.ethereum.StateManager().BlockChain().HasBlockWithPrevHash(block.PrevHash) { if p.ethereum.StateManager().BlockChain().HasBlockWithPrevHash(block.PrevHash) {
if p.ethereum.StateManager().BlockChain().FindCanonicalChainFromMsg(msg, block.PrevHash) { p.diverted = false
return if !p.ethereum.StateManager().BlockChain().FindCanonicalChainFromMsg(msg, block.PrevHash) {
p.SyncWithPeerToLastKnown()
} }
break
} }
} }
} }
if !p.ethereum.StateManager().BlockChain().HasBlock(lastBlock.Hash()) {
// If we can't find a common ancenstor we need to request more blocks.
// FIXME: At one point this won't scale anymore since we are not asking for an offset
// we just keep increasing the amount of blocks.
p.blocksRequested = p.blocksRequested * 2
ethutil.Config.Log.Infof("[PEER] No common ancestor found, requesting %d more blocks.\n", p.blocksRequested)
p.catchingUp = false
p.FindCommonParentBlock()
break
}
} }
for i := msg.Data.Len() - 1; i >= 0; i-- { for i := msg.Data.Len() - 1; i >= 0; i-- {
block = ethchain.NewBlockFromRlpValue(msg.Data.Get(i)) block = ethchain.NewBlockFromRlpValue(msg.Data.Get(i))
p.ethereum.StateManager().PrepareDefault(block) //p.ethereum.StateManager().PrepareDefault(block)
err = p.ethereum.StateManager().ProcessBlock(block, false) state := p.ethereum.StateManager().CurrentState()
err = p.ethereum.StateManager().ProcessBlock(state, block, false)
if err != nil { if err != nil {
if ethutil.Config.Debug { if ethutil.Config.Debug {
@ -345,23 +349,28 @@ func (p *Peer) HandleInbound() {
} }
} }
if msg.Data.Len() == 0 {
// Set catching up to false if
// the peer has nothing left to give
p.catchingUp = false
}
if err != nil { if err != nil {
// If the parent is unknown try to catch up with this peer // If the parent is unknown try to catch up with this peer
if ethchain.IsParentErr(err) { if ethchain.IsParentErr(err) {
ethutil.Config.Log.Infoln("Attempting to catch up") ethutil.Config.Log.Infoln("Attempting to catch up since we don't know the parent")
p.catchingUp = false p.catchingUp = false
p.CatchupWithPeer(p.ethereum.BlockChain().CurrentBlock.Hash()) p.CatchupWithPeer(p.ethereum.BlockChain().CurrentBlock.Hash())
} else if ethchain.IsValidationErr(err) { } else if ethchain.IsValidationErr(err) {
fmt.Println(err) fmt.Println("Err:", err)
p.catchingUp = false p.catchingUp = false
} }
} else { } else {
// XXX Do we want to catch up if there were errors?
// If we're catching up, try to catch up further. // If we're catching up, try to catch up further.
if p.catchingUp && msg.Data.Len() > 1 { if p.catchingUp && msg.Data.Len() > 1 {
if ethutil.Config.Debug && lastBlock != nil { if lastBlock != nil {
blockInfo := lastBlock.BlockInfo() blockInfo := lastBlock.BlockInfo()
ethutil.Config.Log.Infof("Synced to block height #%d %x %x\n", blockInfo.Number, lastBlock.Hash(), blockInfo.Hash) ethutil.Config.Log.Debugf("Synced to block height #%d %x %x\n", blockInfo.Number, lastBlock.Hash(), blockInfo.Hash)
} }
p.catchingUp = false p.catchingUp = false
@ -371,11 +380,6 @@ func (p *Peer) HandleInbound() {
} }
} }
if msg.Data.Len() == 0 {
// Set catching up to false if
// the peer has nothing left to give
p.catchingUp = false
}
case ethwire.MsgTxTy: case ethwire.MsgTxTy:
// If the message was a transaction queue the transaction // If the message was a transaction queue the transaction
// in the TxPool where it will undergo validation and // in the TxPool where it will undergo validation and
@ -443,7 +447,7 @@ func (p *Peer) HandleInbound() {
} }
} else { } else {
ethutil.Config.Log.Debugf("[PEER] Could not find a similar block") //ethutil.Config.Log.Debugf("[PEER] Could not find a similar block")
// If no blocks are found we send back a reply with msg not in chain // If no blocks are found we send back a reply with msg not in chain
// and the last hash from get chain // and the last hash from get chain
lastHash := msg.Data.Get(l - 1) lastHash := msg.Data.Get(l - 1)
@ -451,8 +455,14 @@ func (p *Peer) HandleInbound() {
p.QueueMessage(ethwire.NewMessage(ethwire.MsgNotInChainTy, []interface{}{lastHash.Raw()})) p.QueueMessage(ethwire.NewMessage(ethwire.MsgNotInChainTy, []interface{}{lastHash.Raw()}))
} }
case ethwire.MsgNotInChainTy: case ethwire.MsgNotInChainTy:
ethutil.Config.Log.Debugf("Not in chain %x\n", msg.Data) ethutil.Config.Log.Debugf("Not in chain: %x\n", msg.Data.Get(0).Bytes())
// TODO if p.diverted == true {
// If were already looking for a common parent and we get here again we need to go deeper
p.blocksRequested = p.blocksRequested * 2
}
p.diverted = true
p.catchingUp = false
p.FindCommonParentBlock()
case ethwire.MsgGetTxsTy: case ethwire.MsgGetTxsTy:
// Get the current transactions of the pool // Get the current transactions of the pool
txs := p.ethereum.TxPool().CurrentTransactions() txs := p.ethereum.TxPool().CurrentTransactions()
@ -470,7 +480,6 @@ func (p *Peer) HandleInbound() {
} }
} }
} }
p.Stop() p.Stop()
} }
@ -580,14 +589,18 @@ func (p *Peer) handleHandshake(msg *ethwire.Msg) {
} }
// Catch up with the connected peer
p.SyncWithBlocks()
// Set the peer's caps // Set the peer's caps
p.caps = Caps(c.Get(3).Byte()) p.caps = Caps(c.Get(3).Byte())
// Get a reference to the peers version // Get a reference to the peers version
p.Version = c.Get(2).Str() p.Version = c.Get(2).Str()
// Catch up with the connected peer
if !p.ethereum.IsUpToDate() {
ethutil.Config.Log.Debugln("Already syncing up with a peer; sleeping")
time.Sleep(10 * time.Second)
}
p.SyncWithPeerToLastKnown()
ethutil.Config.Log.Debugln("[PEER]", p) ethutil.Config.Log.Debugln("[PEER]", p)
} }
@ -608,38 +621,47 @@ func (p *Peer) String() string {
return fmt.Sprintf("[%s] (%s) %v %s [%s]", strConnectType, strBoundType, p.conn.RemoteAddr(), p.Version, p.caps) return fmt.Sprintf("[%s] (%s) %v %s [%s]", strConnectType, strBoundType, p.conn.RemoteAddr(), p.Version, p.caps)
} }
func (p *Peer) SyncWithBlocks() { func (p *Peer) SyncWithPeerToLastKnown() {
if !p.catchingUp { p.catchingUp = false
p.catchingUp = true p.CatchupWithPeer(p.ethereum.BlockChain().CurrentBlock.Hash())
// FIXME: THIS SHOULD NOT BE NEEDED
if p.blocksRequested == 0 {
p.blocksRequested = 10
}
blocks := p.ethereum.BlockChain().GetChain(p.ethereum.BlockChain().CurrentBlock.Hash(), p.blocksRequested)
var hashes []interface{}
for _, block := range blocks {
hashes = append(hashes, block.Hash())
}
msgInfo := append(hashes, uint64(50))
msg := ethwire.NewMessage(ethwire.MsgGetChainTy, msgInfo)
p.QueueMessage(msg)
}
} }
func (p *Peer) FindCommonParentBlock() {
if p.catchingUp {
return
}
p.catchingUp = true
if p.blocksRequested == 0 {
p.blocksRequested = 20
}
blocks := p.ethereum.BlockChain().GetChain(p.ethereum.BlockChain().CurrentBlock.Hash(), p.blocksRequested)
var hashes []interface{}
for _, block := range blocks {
hashes = append(hashes, block.Hash())
}
msgInfo := append(hashes, uint64(len(hashes)))
ethutil.Config.Log.Infof("Asking for block from %x (%d total) from %s\n", p.ethereum.BlockChain().CurrentBlock.Hash(), len(hashes), p.conn.RemoteAddr().String())
msg := ethwire.NewMessage(ethwire.MsgGetChainTy, msgInfo)
p.QueueMessage(msg)
}
func (p *Peer) CatchupWithPeer(blockHash []byte) { func (p *Peer) CatchupWithPeer(blockHash []byte) {
if !p.catchingUp { if !p.catchingUp {
// Make sure nobody else is catching up when you want to do this
p.catchingUp = true p.catchingUp = true
msg := ethwire.NewMessage(ethwire.MsgGetChainTy, []interface{}{blockHash, uint64(50)}) msg := ethwire.NewMessage(ethwire.MsgGetChainTy, []interface{}{blockHash, uint64(50)})
p.QueueMessage(msg) p.QueueMessage(msg)
ethutil.Config.Log.Debugf("Requesting blockchain %x...\n", p.ethereum.BlockChain().CurrentBlock.Hash()[:4]) ethutil.Config.Log.Debugf("Requesting blockchain %x... from peer %s\n", p.ethereum.BlockChain().CurrentBlock.Hash()[:4], p.conn.RemoteAddr())
msg = ethwire.NewMessage(ethwire.MsgGetTxsTy, []interface{}{}) /*
p.QueueMessage(msg) msg = ethwire.NewMessage(ethwire.MsgGetTxsTy, []interface{}{})
ethutil.Config.Log.Debugln("Requested transactions") p.QueueMessage(msg)
*/
} }
} }