Merge branch 'develop' of github.com:ethereum/eth-go into develop

This commit is contained in:
Maran 2014-06-17 11:40:37 +02:00
commit a90ffe1af1
7 changed files with 67 additions and 279 deletions

View File

@ -1,236 +0,0 @@
package ethchain
import (
"bytes"
"fmt"
"github.com/ethereum/eth-go/ethutil"
"math/big"
)
func (sm *StateManager) MakeStateObject(state *State, tx *Transaction) *StateObject {
contract := MakeContract(tx, state)
if contract != nil {
state.states[string(tx.CreationAddress())] = contract.state
return contract
}
return nil
}
func (sm *StateManager) EvalScript(state *State, script []byte, object *StateObject, tx *Transaction, block *Block) (ret []byte, gas *big.Int, err error) {
account := state.GetAccount(tx.Sender())
err = account.ConvertGas(tx.Gas, tx.GasPrice)
if err != nil {
ethutil.Config.Log.Debugln(err)
return
}
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,
Coinbase: block.Coinbase,
Time: block.Time,
Diff: block.Difficulty,
Value: tx.Value,
//Price: tx.GasPrice,
})
ret, gas, err = closure.Call(vm, tx.Data, nil)
// Update the account (refunds)
state.UpdateStateObject(account)
state.UpdateStateObject(object)
return
}
func (self *StateManager) ProcessTransaction(tx *Transaction, coinbase *StateObject, state *State, toContract bool) (gas *big.Int, err error) {
fmt.Printf("state root before update %x\n", state.Root())
defer func() {
if r := recover(); r != nil {
ethutil.Config.Log.Infoln(r)
err = fmt.Errorf("%v", r)
}
}()
gas = new(big.Int)
addGas := func(g *big.Int) { gas.Add(gas, g) }
addGas(GasTx)
// Get the sender
sender := state.GetAccount(tx.Sender())
if sender.Nonce != tx.Nonce {
err = NonceError(tx.Nonce, sender.Nonce)
return
}
sender.Nonce += 1
defer func() {
//state.UpdateStateObject(sender)
// Notify all subscribers
self.Ethereum.Reactor().Post("newTx:post", tx)
}()
txTotalBytes := big.NewInt(int64(len(tx.Data)))
//fmt.Println("txTotalBytes", txTotalBytes)
//txTotalBytes.Div(txTotalBytes, ethutil.Big32)
addGas(new(big.Int).Mul(txTotalBytes, GasData))
rGas := new(big.Int).Set(gas)
rGas.Mul(gas, tx.GasPrice)
// Make sure there's enough in the sender's account. Having insufficient
// funds won't invalidate this transaction but simple ignores it.
totAmount := new(big.Int).Add(tx.Value, rGas)
if sender.Amount.Cmp(totAmount) < 0 {
state.UpdateStateObject(sender)
err = fmt.Errorf("[TXPL] Insufficient amount in sender's (%x) account", tx.Sender())
return
}
coinbase.BuyGas(gas, tx.GasPrice)
state.UpdateStateObject(coinbase)
fmt.Printf("1. root %x\n", state.Root())
// Get the receiver
receiver := state.GetAccount(tx.Recipient)
// Send Tx to self
if bytes.Compare(tx.Recipient, tx.Sender()) == 0 {
// Subtract the fee
sender.SubAmount(rGas)
} else {
// Subtract the amount from the senders account
sender.SubAmount(totAmount)
state.UpdateStateObject(sender)
fmt.Printf("3. root %x\n", state.Root())
// Add the amount to receivers account which should conclude this transaction
receiver.AddAmount(tx.Value)
state.UpdateStateObject(receiver)
fmt.Printf("2. root %x\n", state.Root())
}
ethutil.Config.Log.Infof("[TXPL] Processed Tx %x\n", tx.Hash())
return
}
func (sm *StateManager) ApplyTransaction(coinbase []byte, state *State, block *Block, tx *Transaction) (totalGasUsed *big.Int, err error) {
/*
Applies transactions to the given state and creates new
state objects where needed.
If said objects needs to be created
run the initialization script provided by the transaction and
assume there's a return value. The return value will be set to
the script section of the state object.
*/
var (
addTotalGas = func(gas *big.Int) { totalGasUsed.Add(totalGasUsed, gas) }
gas = new(big.Int)
script []byte
)
totalGasUsed = big.NewInt(0)
snapshot := state.Snapshot()
ca := state.GetAccount(coinbase)
// Apply the transaction to the current state
gas, err = sm.ProcessTransaction(tx, ca, state, false)
addTotalGas(gas)
fmt.Println("gas used by tx", gas)
if tx.CreatesContract() {
if err == nil {
// Create a new state object and the transaction
// as it's data provider.
contract := sm.MakeStateObject(state, tx)
if contract != nil {
fmt.Println(Disassemble(contract.Init()))
// Evaluate the initialization script
// and use the return value as the
// script section for the state object.
script, gas, err = sm.EvalScript(state, contract.Init(), contract, tx, block)
fmt.Println("gas used by eval", gas)
addTotalGas(gas)
fmt.Println("total =", totalGasUsed)
fmt.Println("script len =", len(script))
if err != nil {
err = fmt.Errorf("[STATE] Error during init script run %v", err)
return
}
contract.script = script
state.UpdateStateObject(contract)
} else {
err = fmt.Errorf("[STATE] Unable to create contract")
}
} else {
err = fmt.Errorf("[STATE] contract creation tx: %v for sender %x", err, tx.Sender())
}
} else {
// Find the state object at the "recipient" address. If
// there's an object attempt to run the script.
stateObject := state.GetStateObject(tx.Recipient)
if err == nil && stateObject != nil && len(stateObject.Script()) > 0 {
_, gas, err = sm.EvalScript(state, stateObject.Script(), stateObject, tx, block)
addTotalGas(gas)
}
}
parent := sm.bc.GetBlock(block.PrevHash)
total := new(big.Int).Add(block.GasUsed, totalGasUsed)
limit := block.CalcGasLimit(parent)
if total.Cmp(limit) > 0 {
state.Revert(snapshot)
err = GasLimitError(total, limit)
}
return
}
// Apply transactions uses the transaction passed to it and applies them onto
// the current processing state.
func (sm *StateManager) ApplyTransactions(coinbase []byte, state *State, block *Block, txs []*Transaction) ([]*Receipt, []*Transaction) {
// Process each transaction/contract
var receipts []*Receipt
var validTxs []*Transaction
var ignoredTxs []*Transaction // Transactions which go over the gasLimit
totalUsedGas := big.NewInt(0)
for _, tx := range txs {
usedGas, err := sm.ApplyTransaction(coinbase, state, block, tx)
if err != nil {
if IsNonceErr(err) {
continue
}
if IsGasLimitErr(err) {
ignoredTxs = append(ignoredTxs, tx)
// We need to figure out if we want to do something with thse txes
ethutil.Config.Log.Debugln("Gastlimit:", err)
continue
}
ethutil.Config.Log.Infoln(err)
}
accumelative := new(big.Int).Set(totalUsedGas.Add(totalUsedGas, usedGas))
receipt := &Receipt{tx, ethutil.CopyBytes(state.Root().([]byte)), accumelative}
receipts = append(receipts, receipt)
validTxs = append(validTxs, tx)
}
fmt.Println("################# MADE\n", receipts, "\n############################")
// Update the total gas used for the block (to be mined)
block.GasUsed = totalUsedGas
return receipts, validTxs
}

View File

@ -13,8 +13,6 @@ import (
type State struct {
// The trie for this structure
trie *ethutil.Trie
// Nested states
states map[string]*State
stateObjects map[string]*StateObject
@ -23,7 +21,7 @@ type State struct {
// Create a new state from a given trie
func NewState(trie *ethutil.Trie) *State {
return &State{trie: trie, states: make(map[string]*State), stateObjects: make(map[string]*StateObject), manifest: NewManifest()}
return &State{trie: trie, stateObjects: make(map[string]*StateObject), manifest: NewManifest()}
}
// Resets the trie and all siblings
@ -38,12 +36,16 @@ func (s *State) Reset() {
stateObject.state.Reset()
}
s.Empty()
}
// Syncs the trie and all siblings
func (s *State) Sync() {
// Sync all nested states
for _, stateObject := range s.stateObjects {
s.UpdateStateObject(stateObject)
if stateObject.state == nil {
continue
}
@ -52,6 +54,18 @@ func (s *State) Sync() {
}
s.trie.Sync()
s.Empty()
}
func (self *State) Empty() {
self.stateObjects = make(map[string]*StateObject)
}
func (self *State) Update() {
for _, stateObject := range self.stateObjects {
self.UpdateStateObject(stateObject)
}
}
// Purges the current trie.
@ -68,6 +82,7 @@ func (self *State) UpdateStateObject(stateObject *StateObject) {
addr := stateObject.Address()
if self.stateObjects[string(addr)] == nil {
panic("?")
self.stateObjects[string(addr)] = stateObject
}
@ -98,13 +113,19 @@ func (self *State) GetStateObject(addr []byte) *StateObject {
func (self *State) GetOrNewStateObject(addr []byte) *StateObject {
stateObject := self.GetStateObject(addr)
if stateObject == nil {
stateObject = NewStateObject(addr)
self.stateObjects[string(addr)] = stateObject
stateObject = self.NewStateObject(addr)
}
return stateObject
}
func (self *State) NewStateObject(addr []byte) *StateObject {
stateObject := NewStateObject(addr)
self.stateObjects[string(addr)] = stateObject
return stateObject
}
func (self *State) GetAccount(addr []byte) *StateObject {
return self.GetOrNewStateObject(addr)
}
@ -132,7 +153,7 @@ func (s *State) Snapshot() *State {
func (s *State) Revert(snapshot *State) {
s.trie = snapshot.trie
s.states = snapshot.states
s.stateObjects = snapshot.stateObjects
}
func (s *State) Put(key, object []byte) {

View File

@ -181,7 +181,6 @@ func (sm *StateManager) ProcessBlock(state *State, parent, block *Block, dontRea
coinbase.SetGasPool(block.CalcGasLimit(parent))
// Process the transactions on to current block
//sm.ApplyTransactions(block.Coinbase, state, parent, block.Transactions())
sm.ProcessTransactions(coinbase, state, block, parent, block.Transactions())
// Block validation
@ -197,6 +196,9 @@ func (sm *StateManager) ProcessBlock(state *State, parent, block *Block, dontRea
return err
}
// Update the state with pending changes
state.Update()
if !block.State().Cmp(state) {
return fmt.Errorf("Invalid merkle root.\nrec: %x\nis: %x", block.State().trie.Root, state.trie.Root)
}

View File

@ -4,8 +4,15 @@ import (
"fmt"
"github.com/ethereum/eth-go/ethutil"
"math/big"
"strings"
)
type Code []byte
func (self Code) String() string {
return strings.Join(Disassemble(self), " ")
}
type StateObject struct {
// Address of the object
address []byte
@ -15,8 +22,8 @@ type StateObject struct {
Nonce uint64
// Contract related attributes
state *State
script []byte
initScript []byte
script Code
initScript Code
// Total gas pool is the total amount of gas currently
// left if this object is the coinbase. Gas is directly
@ -30,12 +37,9 @@ func MakeContract(tx *Transaction, state *State) *StateObject {
if tx.IsContract() {
addr := tx.CreationAddress()
value := tx.Value
contract := NewContract(addr, value, ZeroHash256)
contract := state.NewStateObject(addr)
contract.initScript = tx.Data
state.UpdateStateObject(contract)
contract.state = NewState(ethutil.NewTrie(ethutil.Config.Db, ""))
return contract
}
@ -120,13 +124,13 @@ func (c *StateObject) ReturnGas(gas, price *big.Int, state *State) {
func (c *StateObject) AddAmount(amount *big.Int) {
c.SetAmount(new(big.Int).Add(c.Amount, amount))
ethutil.Config.Log.Printf(ethutil.LogLevelSystem, "%x: #%d %v (+ %v)\n", c.Address(), c.Nonce, c.Amount, amount)
ethutil.Config.Log.Printf(ethutil.LogLevelInfo, "%x: #%d %v (+ %v)\n", c.Address(), c.Nonce, c.Amount, amount)
}
func (c *StateObject) SubAmount(amount *big.Int) {
c.SetAmount(new(big.Int).Sub(c.Amount, amount))
ethutil.Config.Log.Printf(ethutil.LogLevelSystem, "%x: #%d %v (- %v)\n", c.Address(), c.Nonce, c.Amount, amount)
ethutil.Config.Log.Printf(ethutil.LogLevelInfo, "%x: #%d %v (- %v)\n", c.Address(), c.Nonce, c.Amount, amount)
}
func (c *StateObject) SetAmount(amount *big.Int) {
@ -197,12 +201,12 @@ func (c *StateObject) Address() []byte {
}
// Returns the main script body
func (c *StateObject) Script() []byte {
func (c *StateObject) Script() Code {
return c.script
}
// Returns the initialization script
func (c *StateObject) Init() []byte {
func (c *StateObject) Init() Code {
return c.initScript
}

View File

@ -67,15 +67,10 @@ func (self *StateTransition) Receiver() *StateObject {
func (self *StateTransition) MakeStateObject(state *State, tx *Transaction) *StateObject {
contract := MakeContract(tx, state)
if contract != nil {
state.states[string(tx.CreationAddress())] = contract.state
return contract
}
return nil
}
func (self *StateTransition) UseGas(amount *big.Int) error {
if self.gas.Cmp(amount) < 0 {
return OutOfGasError()
@ -137,6 +132,8 @@ func (self *StateTransition) TransitionState() (err error) {
receiver *StateObject
)
ethutil.Config.Log.Printf(ethutil.LogLevelInfo, "(~) %x\n", tx.Hash())
// Make sure this transaction's nonce is correct
if sender.Nonce != tx.Nonce {
return NonceError(tx.Nonce, sender.Nonce)
@ -152,6 +149,7 @@ func (self *StateTransition) TransitionState() (err error) {
defer func() {
self.RefundGas()
/*
if sender != nil {
self.state.UpdateStateObject(sender)
}
@ -161,6 +159,7 @@ func (self *StateTransition) TransitionState() (err error) {
}
self.state.UpdateStateObject(self.Coinbase())
*/
}()
// Increment the nonce for the next transaction
@ -209,6 +208,7 @@ func (self *StateTransition) TransitionState() (err error) {
receiver.script = code
} else {
if len(receiver.Script()) > 0 {
fmt.Println(receiver.Script())
_, err := self.Eval(receiver.Script(), receiver)
if err != nil {
return fmt.Errorf("Error during code execution %v", err)

View File

@ -95,9 +95,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro
step := 0
prevStep := 0
if ethutil.Config.Debug {
ethutil.Config.Log.Debugf("# op\n")
}
for {
prevStep = step
@ -109,9 +107,8 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro
val := closure.Get(pc)
// Get the opcode (it must be an opcode!)
op := OpCode(val.Uint())
if ethutil.Config.Debug {
ethutil.Config.Log.Debugf("%-3d %-4s", pc, op.String())
}
gas := new(big.Int)
addStepGasUsage := func(amount *big.Int) {
@ -525,8 +522,6 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro
vm.state.Revert(snapshot)
} else {
stack.Push(ethutil.BigD(addr))
vm.state.UpdateStateObject(contract)
}
case CALL:
// TODO RE-WRITE
@ -569,8 +564,6 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro
} else {
stack.Push(ethutil.BigTrue)
vm.state.UpdateStateObject(contract)
mem.Set(retOffset.Int64(), retSize.Int64(), ret)
}
} else {
@ -589,9 +582,11 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro
receiver := vm.state.GetAccount(stack.Pop().Bytes())
receiver.AddAmount(closure.object.Amount)
vm.state.UpdateStateObject(receiver)
closure.object.state.Purge()
trie := closure.object.state.trie
trie.NewIterator().Each(func(key string, v *ethutil.Value) {
trie.Delete(key)
})
fallthrough
case STOP: // Stop the closure

View File

@ -154,6 +154,8 @@ func (self *Miner) mineNewBlock() {
// Accumulate the rewards included for this block
stateManager.AccumelateRewards(self.block.State(), self.block)
self.block.State().Update()
ethutil.Config.Log.Infoln("[MINER] Mining on block. Includes", len(self.txs), "transactions")
// Find a valid nonce