Skip to content

Commit

Permalink
Created generic message (easy for testing)
Browse files Browse the repository at this point in the history
  • Loading branch information
obscuren committed Dec 18, 2014
1 parent 9e286e1 commit db49417
Show file tree
Hide file tree
Showing 10 changed files with 159 additions and 102 deletions.
16 changes: 8 additions & 8 deletions cmd/mist/gui.go
Expand Up @@ -305,13 +305,13 @@ func (gui *Gui) insertTransaction(window string, tx *types.Transaction) {

var (
ptx = xeth.NewJSTx(tx, pipe.World().State())
send = nameReg.Storage(tx.Sender())
rec = nameReg.Storage(tx.Recipient)
send = nameReg.Storage(tx.From())
rec = nameReg.Storage(tx.To())
s, r string
)

if tx.CreatesContract() {
rec = nameReg.Storage(tx.CreationAddress(pipe.World().State()))
rec = nameReg.Storage(core.AddressFromMessage(tx))
}

if send.Len() != 0 {
Expand All @@ -323,9 +323,9 @@ func (gui *Gui) insertTransaction(window string, tx *types.Transaction) {
r = strings.Trim(rec.Str(), "\x00")
} else {
if tx.CreatesContract() {
r = ethutil.Bytes2Hex(tx.CreationAddress(pipe.World().State()))
r = ethutil.Bytes2Hex(core.AddressFromMessage(tx))
} else {
r = ethutil.Bytes2Hex(tx.Recipient)
r = ethutil.Bytes2Hex(tx.To())
}
}
ptx.Sender = s
Expand Down Expand Up @@ -449,11 +449,11 @@ func (gui *Gui) update() {
object := state.GetAccount(gui.address())

if bytes.Compare(tx.Sender(), gui.address()) == 0 {
object.SubAmount(tx.Value)
object.SubAmount(tx.Value())

gui.txDb.Put(tx.Hash(), tx.RlpEncode())
} else if bytes.Compare(tx.Recipient, gui.address()) == 0 {
object.AddAmount(tx.Value)
} else if bytes.Compare(tx.To(), gui.address()) == 0 {
object.AddAmount(tx.Value())

gui.txDb.Put(tx.Hash(), tx.RlpEncode())
}
Expand Down
4 changes: 2 additions & 2 deletions core/block_manager.go
Expand Up @@ -111,7 +111,7 @@ 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)
Expand All @@ -134,7 +134,7 @@ done:
}

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)
Expand Down
98 changes: 66 additions & 32 deletions core/state_transition.go
Expand Up @@ -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"
)
Expand All @@ -27,18 +29,50 @@ import (
*/
type StateTransition struct {
coinbase, receiver []byte
tx *types.Transaction
msg Message
gas, gasPrice *big.Int
value *big.Int
data []byte
state *state.StateDB
block *types.Block

cb, rec, sen *state.StateObject

Env vm.Environment
}

type Message interface {
Hash() []byte

CreatesContract() bool

From() []byte
To() []byte

GasValue() *big.Int
GasPrice() *big.Int
Gas() *big.Int
Value() *big.Int

Nonce() uint64
Data() []byte
}

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}
func AddressFromMessage(msg Message) []byte {
// Generate a new address
return crypto.Sha3(ethutil.NewValue([]interface{}{msg.From(), msg.Nonce()}).Encode())[12:]
}

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()), msg.Value(), msg.Data(), state, block, coinbase, nil, nil, nil}
}

func (self *StateTransition) VmEnv() vm.Environment {
if self.Env == nil {
self.Env = NewEnv(self.state, self.msg, self.block)
}

return self.Env
}

func (self *StateTransition) Coinbase() *state.StateObject {
Expand All @@ -49,25 +83,25 @@ func (self *StateTransition) Coinbase() *state.StateObject {
self.cb = self.state.GetOrNewStateObject(self.coinbase)
return self.cb
}
func (self *StateTransition) Sender() *state.StateObject {
func (self *StateTransition) From() *state.StateObject {
if self.sen != nil {
return self.sen
}

self.sen = self.state.GetOrNewStateObject(self.tx.Sender())
self.sen = self.state.GetOrNewStateObject(self.msg.From())

return self.sen
}
func (self *StateTransition) Receiver() *state.StateObject {
if self.tx != nil && self.tx.CreatesContract() {
func (self *StateTransition) To() *state.StateObject {
if self.msg != nil && self.msg.CreatesContract() {
return nil
}

if self.rec != nil {
return self.rec
}

self.rec = self.state.GetOrNewStateObject(self.tx.Recipient)
self.rec = self.state.GetOrNewStateObject(self.msg.To())
return self.rec
}

Expand All @@ -87,41 +121,41 @@ 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(self.msg.GasValue()) < 0 {
return fmt.Errorf("Insufficient funds to pre-pay gas. Req %v, has %v", self.msg.GasValue(), 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())
sender.SubAmount(self.msg.GasValue())

return nil
}

func (self *StateTransition) RefundGas() {
coinbase, sender := self.Coinbase(), self.Sender()
coinbase.RefundGas(self.gas, self.tx.GasPrice)
coinbase, sender := self.Coinbase(), self.From()
coinbase.RefundGas(self.gas, self.msg.GasPrice())

// Return remaining gas
remaining := new(big.Int).Mul(self.gas, self.tx.GasPrice)
remaining := new(big.Int).Mul(self.gas, self.msg.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
Expand All @@ -133,16 +167,16 @@ func (self *StateTransition) preCheck() (err error) {
}

func (self *StateTransition) TransitionState() (err error) {
statelogger.Debugf("(~) %x\n", self.tx.Hash())
statelogger.Debugf("(~) %x\n", self.msg.Hash())

// XXX Transactions after this point are considered valid.
if err = self.preCheck(); err != nil {
return
}

var (
tx = self.tx
sender = self.Sender()
msg = self.msg
sender = self.From()
)

defer self.RefundGas()
Expand All @@ -169,15 +203,15 @@ func (self *StateTransition) TransitionState() (err error) {
}

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)
if msg.CreatesContract() {
self.rec = MakeContract(msg, self.state)

ret, err, ref = vmenv.Create(sender, self.rec.Address(), self.tx.Data, self.gas, self.gasPrice, self.value)
ret, err, ref = vmenv.Create(sender, self.rec.Address(), self.msg.Data(), self.gas, self.gasPrice, self.value)
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)
Expand All @@ -187,11 +221,11 @@ func (self *StateTransition) TransitionState() (err error) {
}

// 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
}
17 changes: 7 additions & 10 deletions core/transaction_pool.go
Expand Up @@ -112,8 +112,8 @@ func (pool *TxPool) ValidateTransaction(tx *types.Transaction) error {
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()
Expand All @@ -124,15 +124,15 @@ func (pool *TxPool) ValidateTransaction(tx *types.Transaction) error {
// Get the 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())
return fmt.Errorf("Insufficient amount in sender's (%x) account", tx.From())
}

if tx.IsContract() {
if tx.GasPrice.Cmp(big.NewInt(minGasPrice)) < 0 {
if tx.GasPrice().Cmp(big.NewInt(minGasPrice)) < 0 {
return fmt.Errorf("Gasprice too low, %s given should be at least %d.", tx.GasPrice, minGasPrice)
}
}
Expand Down Expand Up @@ -160,10 +160,7 @@ func (self *TxPool) Add(tx *types.Transaction) error {

self.addTransaction(tx)

tmp := make([]byte, 4)
copy(tmp, tx.Recipient)

txplogger.Debugf("(t) %x => %x (%v) %x\n", tx.Sender()[:4], tmp, tx.Value, tx.Hash())
txplogger.Debugf("(t) %x => %x (%v) %x\n", tx.From()[:4], tx.To()[:4], tx.Value, tx.Hash())

// Notify the subscribers
go self.eventMux.Post(TxPreEvent{tx})
Expand Down Expand Up @@ -200,7 +197,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)
}
}
Expand Down

0 comments on commit db49417

Please sign in to comment.