aboutsummaryrefslogtreecommitdiffstats
path: root/core
diff options
context:
space:
mode:
Diffstat (limited to 'core')
-rw-r--r--core/block_manager.go6
-rw-r--r--core/state_transition.go145
-rw-r--r--core/transaction_pool.go21
-rw-r--r--core/types/transaction.go94
-rw-r--r--core/vm_env.go10
5 files changed, 150 insertions, 126 deletions
diff --git a/core/block_manager.go b/core/block_manager.go
index 7cb9c4208..85b4891a5 100644
--- a/core/block_manager.go
+++ b/core/block_manager.go
@@ -109,11 +109,11 @@ done:
// If we are mining this block and validating we want to set the logs back to 0
state.EmptyLogs()
- txGas := new(big.Int).Set(tx.Gas)
+ txGas := new(big.Int).Set(tx.Gas())
cb := state.GetStateObject(coinbase.Address())
st := NewStateTransition(cb, tx, state, block)
- err = st.TransitionState()
+ _, err = st.TransitionState()
if err != nil {
switch {
case IsNonceErr(err):
@@ -132,7 +132,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)
diff --git a/core/state_transition.go b/core/state_transition.go
index 820ba66e6..9e81ddf28 100644
--- a/core/state_transition.go
+++ b/core/state_transition.go
@@ -5,6 +5,8 @@ import (
"math/big"
"github.com/ethereum/go-ethereum/core/types"
+ "github.com/ethereum/go-ethereum/crypto"
+ "github.com/ethereum/go-ethereum/ethutil"
"github.com/ethereum/go-ethereum/state"
"github.com/ethereum/go-ethereum/vm"
)
@@ -27,48 +29,69 @@ import (
*/
type StateTransition struct {
coinbase, receiver []byte
- tx *types.Transaction
+ msg Message
gas, gasPrice *big.Int
+ initialGas *big.Int
value *big.Int
data []byte
state *state.StateDB
block *types.Block
cb, rec, sen *state.StateObject
+
+ Env vm.Environment
}
-func NewStateTransition(coinbase *state.StateObject, tx *types.Transaction, state *state.StateDB, block *types.Block) *StateTransition {
- return &StateTransition{coinbase.Address(), tx.Recipient, tx, new(big.Int), new(big.Int).Set(tx.GasPrice), tx.Value, tx.Data, state, block, coinbase, nil, nil}
+type Message interface {
+ Hash() []byte
+
+ From() []byte
+ To() []byte
+
+ GasPrice() *big.Int
+ Gas() *big.Int
+ Value() *big.Int
+
+ Nonce() uint64
+ Data() []byte
}
-func (self *StateTransition) Coinbase() *state.StateObject {
- if self.cb != nil {
- return self.cb
- }
+func AddressFromMessage(msg Message) []byte {
+ // Generate a new address
+ return crypto.Sha3(ethutil.NewValue([]interface{}{msg.From(), msg.Nonce()}).Encode())[12:]
+}
- self.cb = self.state.GetOrNewStateObject(self.coinbase)
- return self.cb
+func MessageCreatesContract(msg Message) bool {
+ return len(msg.To()) == 0
}
-func (self *StateTransition) Sender() *state.StateObject {
- if self.sen != nil {
- return self.sen
- }
- self.sen = self.state.GetOrNewStateObject(self.tx.Sender())
+func MessageGasValue(msg Message) *big.Int {
+ return new(big.Int).Mul(msg.Gas(), msg.GasPrice())
+}
- return self.sen
+func NewStateTransition(coinbase *state.StateObject, msg Message, state *state.StateDB, block *types.Block) *StateTransition {
+ return &StateTransition{coinbase.Address(), msg.To(), msg, new(big.Int), new(big.Int).Set(msg.GasPrice()), new(big.Int), msg.Value(), msg.Data(), state, block, coinbase, nil, nil, nil}
}
-func (self *StateTransition) Receiver() *state.StateObject {
- if self.tx != nil && self.tx.CreatesContract() {
- return nil
- }
- if self.rec != nil {
- return self.rec
+func (self *StateTransition) VmEnv() vm.Environment {
+ if self.Env == nil {
+ self.Env = NewEnv(self.state, self.msg, self.block)
}
- self.rec = self.state.GetOrNewStateObject(self.tx.Recipient)
- return self.rec
+ return self.Env
+}
+
+func (self *StateTransition) Coinbase() *state.StateObject {
+ return self.state.GetOrNewStateObject(self.coinbase)
+}
+func (self *StateTransition) From() *state.StateObject {
+ return self.state.GetOrNewStateObject(self.msg.From())
+}
+func (self *StateTransition) To() *state.StateObject {
+ if self.msg != nil && MessageCreatesContract(self.msg) {
+ return nil
+ }
+ return self.state.GetOrNewStateObject(self.msg.To())
}
func (self *StateTransition) UseGas(amount *big.Int) error {
@@ -87,41 +110,33 @@ func (self *StateTransition) AddGas(amount *big.Int) {
func (self *StateTransition) BuyGas() error {
var err error
- sender := self.Sender()
- if sender.Balance().Cmp(self.tx.GasValue()) < 0 {
- return fmt.Errorf("Insufficient funds to pre-pay gas. Req %v, has %v", self.tx.GasValue(), sender.Balance())
+ sender := self.From()
+ if sender.Balance().Cmp(MessageGasValue(self.msg)) < 0 {
+ return fmt.Errorf("Insufficient funds to pre-pay gas. Req %v, has %v", MessageGasValue(self.msg), sender.Balance())
}
coinbase := self.Coinbase()
- err = coinbase.BuyGas(self.tx.Gas, self.tx.GasPrice)
+ err = coinbase.BuyGas(self.msg.Gas(), self.msg.GasPrice())
if err != nil {
return err
}
- self.AddGas(self.tx.Gas)
- sender.SubAmount(self.tx.GasValue())
+ self.AddGas(self.msg.Gas())
+ self.initialGas.Set(self.msg.Gas())
+ sender.SubAmount(MessageGasValue(self.msg))
return nil
}
-func (self *StateTransition) RefundGas() {
- coinbase, sender := self.Coinbase(), self.Sender()
- coinbase.RefundGas(self.gas, self.tx.GasPrice)
-
- // Return remaining gas
- remaining := new(big.Int).Mul(self.gas, self.tx.GasPrice)
- sender.AddAmount(remaining)
-}
-
func (self *StateTransition) preCheck() (err error) {
var (
- tx = self.tx
- sender = self.Sender()
+ msg = self.msg
+ sender = self.From()
)
// Make sure this transaction's nonce is correct
- if sender.Nonce != tx.Nonce {
- return NonceError(tx.Nonce, sender.Nonce)
+ if sender.Nonce != msg.Nonce() {
+ return NonceError(msg.Nonce(), sender.Nonce)
}
// Pre-pay gas / Buy gas of the coinbase account
@@ -132,8 +147,8 @@ func (self *StateTransition) preCheck() (err error) {
return nil
}
-func (self *StateTransition) TransitionState() (err error) {
- statelogger.Debugf("(~) %x\n", self.tx.Hash())
+func (self *StateTransition) TransitionState() (ret []byte, err error) {
+ statelogger.Debugf("(~) %x\n", self.msg.Hash())
// XXX Transactions after this point are considered valid.
if err = self.preCheck(); err != nil {
@@ -141,8 +156,8 @@ func (self *StateTransition) TransitionState() (err error) {
}
var (
- tx = self.tx
- sender = self.Sender()
+ msg = self.msg
+ sender = self.From()
)
defer self.RefundGas()
@@ -168,16 +183,15 @@ func (self *StateTransition) TransitionState() (err error) {
return
}
- var ret []byte
- vmenv := NewEnv(self.state, self.tx, self.block)
+ vmenv := self.VmEnv()
var ref vm.ClosureRef
- if tx.CreatesContract() {
- self.rec = MakeContract(tx, self.state)
+ if MessageCreatesContract(msg) {
+ 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)
@@ -187,11 +201,32 @@ 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
}
+
+func (self *StateTransition) RefundGas() {
+ coinbaseSub := new(big.Int).Set(self.gas)
+ uhalf := new(big.Int).Div(self.GasUsed(), ethutil.Big2)
+ for addr, ref := range self.state.Refunds() {
+ refund := ethutil.BigMin(uhalf, ref)
+ coinbaseSub.Add(self.gas, refund)
+ self.state.AddBalance([]byte(addr), refund.Mul(refund, self.msg.GasPrice()))
+ }
+
+ coinbase, sender := self.Coinbase(), self.From()
+ coinbase.RefundGas(coinbaseSub, self.msg.GasPrice())
+
+ // Return remaining gas
+ remaining := new(big.Int).Mul(self.gas, self.msg.GasPrice())
+ sender.AddAmount(remaining)
+}
+
+func (self *StateTransition) GasUsed() *big.Int {
+ return new(big.Int).Sub(self.initialGas, self.gas)
+}
diff --git a/core/transaction_pool.go b/core/transaction_pool.go
index 2bbda7d90..17fcdb86a 100644
--- a/core/transaction_pool.go
+++ b/core/transaction_pool.go
@@ -106,8 +106,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()
@@ -118,17 +118,11 @@ 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())
- }
-
- if tx.IsContract() {
- if tx.GasPrice.Cmp(big.NewInt(minGasPrice)) < 0 {
- return fmt.Errorf("Gasprice too low, %s given should be at least %d.", tx.GasPrice, minGasPrice)
- }
+ return fmt.Errorf("Insufficient amount in sender's (%x) account", tx.From())
}
// Increment the nonce making each tx valid only once to prevent replay
@@ -154,10 +148,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})
@@ -204,7 +195,7 @@ func (pool *TxPool) RemoveInvalid(state *state.StateDB) {
tx := e.Value.(*types.Transaction)
sender := state.GetAccount(tx.Sender())
err := pool.ValidateTransaction(tx)
- if err != nil || sender.Nonce >= tx.Nonce {
+ if err != nil || sender.Nonce >= tx.Nonce() {
pool.pool.Remove(e)
}
}
diff --git a/core/types/transaction.go b/core/types/transaction.go
index 63edef756..c64fb69f0 100644
--- a/core/types/transaction.go
+++ b/core/types/transaction.go
@@ -6,37 +6,30 @@ import (
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethutil"
- "github.com/ethereum/go-ethereum/state"
"github.com/obscuren/secp256k1-go"
)
-var ContractAddr = []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
-
func IsContractAddr(addr []byte) bool {
return len(addr) == 0
- //return bytes.Compare(addr, ContractAddr) == 0
}
type Transaction struct {
- Nonce uint64
- Recipient []byte
- Value *big.Int
- Gas *big.Int
- GasPrice *big.Int
- Data []byte
+ nonce uint64
+ recipient []byte
+ value *big.Int
+ gas *big.Int
+ gasPrice *big.Int
+ data []byte
v byte
r, s []byte
-
- // Indicates whether this tx is a contract creation transaction
- contractCreation bool
}
func NewContractCreationTx(value, gas, gasPrice *big.Int, script []byte) *Transaction {
- return &Transaction{Recipient: nil, Value: value, Gas: gas, GasPrice: gasPrice, Data: script, contractCreation: true}
+ return &Transaction{recipient: nil, value: value, gas: gas, gasPrice: gasPrice, data: script}
}
func NewTransactionMessage(to []byte, value, gas, gasPrice *big.Int, data []byte) *Transaction {
- return &Transaction{Recipient: to, Value: value, GasPrice: gasPrice, Gas: gas, Data: data, contractCreation: IsContractAddr(to)}
+ return &Transaction{recipient: to, value: value, gasPrice: gasPrice, gas: gas, data: data}
}
func NewTransactionFromBytes(data []byte) *Transaction {
@@ -53,33 +46,42 @@ func NewTransactionFromValue(val *ethutil.Value) *Transaction {
return tx
}
-func (self *Transaction) GasValue() *big.Int {
- return new(big.Int).Mul(self.Gas, self.GasPrice)
+func (tx *Transaction) Hash() []byte {
+ data := []interface{}{tx.Nonce, tx.gasPrice, tx.gas, tx.recipient, tx.Value, tx.Data}
+
+ return crypto.Sha3(ethutil.NewValue(data).Encode())
}
-func (self *Transaction) TotalValue() *big.Int {
- v := self.GasValue()
- return v.Add(v, self.Value)
+func (self *Transaction) Data() []byte {
+ return self.data
}
-func (tx *Transaction) Hash() []byte {
- data := []interface{}{tx.Nonce, tx.GasPrice, tx.Gas, tx.Recipient, tx.Value, tx.Data}
+func (self *Transaction) Gas() *big.Int {
+ return self.gas
+}
- return crypto.Sha3(ethutil.NewValue(data).Encode())
+func (self *Transaction) GasPrice() *big.Int {
+ return self.gasPrice
+}
+
+func (self *Transaction) Value() *big.Int {
+ return self.value
}
-func (tx *Transaction) CreatesContract() bool {
- return tx.contractCreation
+func (self *Transaction) Nonce() uint64 {
+ return self.nonce
}
-/* Deprecated */
-func (tx *Transaction) IsContract() bool {
- return tx.CreatesContract()
+func (self *Transaction) SetNonce(nonce uint64) {
+ self.nonce = nonce
}
-func (tx *Transaction) CreationAddress(state *state.StateDB) []byte {
- // Generate a new address
- return crypto.Sha3(ethutil.NewValue([]interface{}{tx.Sender(), tx.Nonce}).Encode())[12:]
+func (self *Transaction) From() []byte {
+ return self.Sender()
+}
+
+func (self *Transaction) To() []byte {
+ return self.recipient
}
func (tx *Transaction) Curve() (v byte, r []byte, s []byte) {
@@ -136,7 +138,7 @@ func (tx *Transaction) Sign(privk []byte) error {
}
func (tx *Transaction) RlpData() interface{} {
- data := []interface{}{tx.Nonce, tx.GasPrice, tx.Gas, tx.Recipient, tx.Value, tx.Data}
+ data := []interface{}{tx.Nonce, tx.GasPrice, tx.Gas, tx.recipient, tx.Value, tx.Data}
// TODO Remove prefixing zero's
@@ -156,20 +158,16 @@ func (tx *Transaction) RlpDecode(data []byte) {
}
func (tx *Transaction) RlpValueDecode(decoder *ethutil.Value) {
- tx.Nonce = decoder.Get(0).Uint()
- tx.GasPrice = decoder.Get(1).BigInt()
- tx.Gas = decoder.Get(2).BigInt()
- tx.Recipient = decoder.Get(3).Bytes()
- tx.Value = decoder.Get(4).BigInt()
- tx.Data = decoder.Get(5).Bytes()
+ tx.nonce = decoder.Get(0).Uint()
+ tx.gasPrice = decoder.Get(1).BigInt()
+ tx.gas = decoder.Get(2).BigInt()
+ tx.recipient = decoder.Get(3).Bytes()
+ tx.value = decoder.Get(4).BigInt()
+ tx.data = decoder.Get(5).Bytes()
tx.v = byte(decoder.Get(6).Uint())
tx.r = decoder.Get(7).Bytes()
tx.s = decoder.Get(8).Bytes()
-
- if IsContractAddr(tx.Recipient) {
- tx.contractCreation = true
- }
}
func (tx *Transaction) String() string {
@@ -188,12 +186,12 @@ func (tx *Transaction) String() string {
S: 0x%x
`,
tx.Hash(),
- len(tx.Recipient) == 0,
+ len(tx.recipient) == 0,
tx.Sender(),
- tx.Recipient,
- tx.Nonce,
- tx.GasPrice,
- tx.Gas,
+ tx.recipient,
+ tx.nonce,
+ tx.gasPrice,
+ tx.gas,
tx.Value,
tx.Data,
tx.v,
@@ -221,5 +219,5 @@ func (s Transactions) GetRlp(i int) []byte { return ethutil.Rlp(s[i]) }
type TxByNonce struct{ Transactions }
func (s TxByNonce) Less(i, j int) bool {
- return s.Transactions[i].Nonce < s.Transactions[j].Nonce
+ return s.Transactions[i].nonce < s.Transactions[j].nonce
}
diff --git a/core/vm_env.go b/core/vm_env.go
index 9e1815188..0b6744972 100644
--- a/core/vm_env.go
+++ b/core/vm_env.go
@@ -11,26 +11,26 @@ import (
type VMEnv struct {
state *state.StateDB
block *types.Block
- tx *types.Transaction
+ msg Message
depth int
}
-func NewEnv(state *state.StateDB, tx *types.Transaction, block *types.Block) *VMEnv {
+func NewEnv(state *state.StateDB, msg Message, block *types.Block) *VMEnv {
return &VMEnv{
state: state,
block: block,
- tx: tx,
+ msg: msg,
}
}
-func (self *VMEnv) Origin() []byte { return self.tx.Sender() }
+func (self *VMEnv) Origin() []byte { return self.msg.From() }
func (self *VMEnv) BlockNumber() *big.Int { return self.block.Number }
func (self *VMEnv) PrevHash() []byte { return self.block.PrevHash }
func (self *VMEnv) Coinbase() []byte { return self.block.Coinbase }
func (self *VMEnv) Time() int64 { return self.block.Time }
func (self *VMEnv) Difficulty() *big.Int { return self.block.Difficulty }
func (self *VMEnv) BlockHash() []byte { return self.block.Hash() }
-func (self *VMEnv) Value() *big.Int { return self.tx.Value }
+func (self *VMEnv) Value() *big.Int { return self.msg.Value() }
func (self *VMEnv) State() *state.StateDB { return self.state }
func (self *VMEnv) GasLimit() *big.Int { return self.block.GasLimit }
func (self *VMEnv) Depth() int { return self.depth }