@ -39,20 +39,13 @@ type StateManager struct {
// The ethereum manager interface
Ethereum EthManager
// 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
// it could be used for setting account nonces without effecting
// the main states.
transState * State
// Manifest for keeping changes regarding state objects. See `notify`
// XXX Should we move the manifest to the State object. Benefit:
// * All states can keep their own local changes
//manifest *Manifest
// Mining state. The mining state is used purely and solely by the mining
// operation.
miningState * State
}
func NewStateManager ( ethereum EthManager ) * StateManager {
@ -62,30 +55,39 @@ func NewStateManager(ethereum EthManager) *StateManager {
Pow : & EasyPow { } ,
Ethereum : ethereum ,
bc : ethereum . BlockChain ( ) ,
//manifest: NewManifest(),
}
sm . proc State = ethereum . BlockChain ( ) . CurrentBlock . State ( )
sm . transState = sm . procState . Copy ( )
sm . trans State = ethereum . BlockChain ( ) . CurrentBlock . State ( ) . Copy ( )
sm . miningState = ethereum . BlockChain ( ) . CurrentBlock . State ( ) . Copy ( )
return sm
}
func ( sm * StateManager ) Proc State( ) * State {
return sm . p rocState
func ( sm * StateManager ) Current State( ) * State {
return sm . Ethereum . BlockChain ( ) . Cu rrentBl ock . State ( )
}
func ( sm * StateManager ) TransState ( ) * State {
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 {
return sm . bc
}
func ( sm * StateManager ) MakeContract ( tx * Transaction ) * StateObject {
contract := MakeContract ( tx , sm . procState )
func ( sm * StateManager ) MakeContract ( state * State , tx * Transaction ) * StateObject {
contract := MakeContract ( tx , state )
if contract != nil {
sm . procState . states [ string ( tx . Hash ( ) [ 12 : ] ) ] = contract . state
state . states [ string ( tx . CreationAddress ( ) ) ] = contract . state
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
// 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
for _ , tx := range txs {
// If there's no recipient, it's a contract
@ -104,9 +106,9 @@ func (sm *StateManager) ApplyTransactions(block *Block, txs []*Transaction) {
if tx . IsContract ( ) {
err := sm . Ethereum . TxPool ( ) . ProcessTransaction ( tx , block , false )
if err == nil {
contract := sm . MakeContract ( tx )
contract := sm . MakeContract ( state , tx )
if contract != nil {
sm . EvalScript ( contract . Init ( ) , contract , tx , block )
sm . EvalScript ( state , contract . Init ( ) , contract , tx , block )
} else {
ethutil . Config . Log . Infoln ( "[STATE] Unable to create contract" )
}
@ -115,9 +117,10 @@ func (sm *StateManager) ApplyTransactions(block *Block, txs []*Transaction) {
}
} else {
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 {
sm . EvalScript ( contract . Script ( ) , contract , tx , block )
sm . EvalScript ( state , contract . Script ( ) , contract , tx , block )
} else if err != nil {
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
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
sm . mutex . Lock ( )
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
// nodes this won't happen because Commit would have been called
// 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
// 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
sm . ApplyTransactions ( sm . bc . CurrentBlock , block . Transactions ( ) )
sm . ApplyTransactions ( state , s m . bc . CurrentBlock , block . Transactions ( ) )
// Block validation
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
// 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 )
return err
}
if ! sm . compState . Cmp ( sm . procState ) {
return fmt . Errorf ( "Invalid merkle root. Expected %x, got %x" , sm . compState . trie . Root , sm . procState . trie . Root )
//if !sm.compState.Cmp(state) {
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
if sm . CalculateTD ( block ) {
// Sync the current block's state to the database and cancelling out the deferred Undo
sm . procS tate . Sync ( )
state . Sync ( )
// Add the block to the chain
sm . bc . Add ( block )
sm . notifyChanges ( state )
ethutil . Config . Log . Infof ( "[STATE] Added block #%d (%x)\n" , block . BlockInfo ( ) . Number , block . Hash ( ) )
if dontReact == false {
sm . Ethereum . Reactor ( ) . Post ( "newBlock" , block )
sm . notifyChanges ( )
sm . procState . manifest . Reset ( )
state . manifest . Reset ( )
}
sm . Ethereum . Broadcast ( ethwire . MsgBlockTy , [ ] interface { } { block . Value ( ) . Val } )
sm . Ethereum . TxPool ( ) . RemoveInvalid ( sm . procS tate )
sm . Ethereum . TxPool ( ) . RemoveInvalid ( state )
} else {
fmt . Println ( "total diff failed" )
}
@ -276,21 +267,21 @@ func CalculateUncleReward(block *Block) *big.Int {
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
account := sm . procS tate . GetAccount ( block . Coinbase )
account := state . GetAccount ( block . Coinbase )
// Reward amount of ether to the coinbase address
account . AddAmount ( CalculateBlockReward ( block , len ( block . Uncles ) ) )
addr := make ( [ ] byte , len ( block . Coinbase ) )
copy ( addr , block . Coinbase )
sm . procS tate . UpdateStateObject ( account )
state . UpdateStateObject ( account )
for _ , uncle := range block . Uncles {
uncleAccount := sm . procS tate . GetAccount ( uncle . Coinbase )
uncleAccount := state . GetAccount ( uncle . Coinbase )
uncleAccount . AddAmount ( CalculateUncleReward ( uncle ) )
sm . procS tate . UpdateStateObject ( uncleAccount )
state . UpdateStateObject ( uncleAccount )
}
return nil
@ -300,8 +291,8 @@ func (sm *StateManager) Stop() {
sm . bc . Stop ( )
}
func ( sm * StateManager ) EvalScript ( script [ ] byte , object * StateObject , tx * Transaction , block * Block ) {
account := sm . procS tate . GetAccount ( tx . Sender ( ) )
func ( sm * StateManager ) EvalScript ( state * State , s cript [ ] byte , object * StateObject , tx * Transaction , block * Block ) {
account := state . GetAccount ( tx . Sender ( ) )
err := account . ConvertGas ( tx . Gas , tx . GasPrice )
if err != nil {
@ -309,8 +300,8 @@ func (sm *StateManager) EvalScript(script []byte, object *StateObject, tx *Trans
return
}
closure := NewClosure ( account , object , script , sm . procS tate , tx . Gas , tx . GasPrice )
vm := NewVm ( sm . procS tate , sm , RuntimeVars {
closure := NewClosure ( account , object , script , state , tx . Gas , tx . GasPrice )
vm := NewVm ( state , sm , RuntimeVars {
Origin : account . Address ( ) ,
BlockNumber : block . BlockInfo ( ) . Number ,
PrevHash : block . PrevHash ,
@ -323,16 +314,16 @@ func (sm *StateManager) EvalScript(script []byte, object *StateObject, tx *Trans
closure . Call ( vm , tx . Data , nil )
// Update the account (refunds)
sm . procS tate . UpdateStateObject ( account )
sm . procS tate . UpdateStateObject ( object )
state . UpdateStateObject ( account )
state . UpdateStateObject ( object )
}
func ( sm * StateManager ) notifyChanges ( ) {
for addr , stateObject := range sm . procS tate . manifest . objectChanges {
func ( sm * StateManager ) notifyChanges ( state * State ) {
for addr , stateObject := range state . manifest . objectChanges {
sm . Ethereum . Reactor ( ) . Post ( "object:" + addr , stateObject )
}
for stateObjectAddr , mappedObjects := range sm . procS tate . manifest . storageChanges {
for stateObjectAddr , mappedObjects := range state . manifest . storageChanges {
for addr , value := range mappedObjects {
sm . Ethereum . Reactor ( ) . Post ( "storage:" + stateObjectAddr + ":" + addr , & StorageState { [ ] byte ( stateObjectAddr ) , [ ] byte ( addr ) , value } )
}