Merged accounts and contracts in to StateObject
* Account removed * Contract removed * Address state changed to CachedStateObject * Added StateObject
This commit is contained in:
parent
ca13e3b105
commit
9c6aca7893
@ -1,76 +0,0 @@
|
||||
package ethchain
|
||||
|
||||
import (
|
||||
"github.com/ethereum/eth-go/ethutil"
|
||||
"math/big"
|
||||
)
|
||||
|
||||
type Account struct {
|
||||
address []byte
|
||||
Amount *big.Int
|
||||
Nonce uint64
|
||||
}
|
||||
|
||||
func NewAccount(address []byte, amount *big.Int) *Account {
|
||||
return &Account{address, amount, 0}
|
||||
}
|
||||
|
||||
func NewAccountFromData(address, data []byte) *Account {
|
||||
account := &Account{address: address}
|
||||
account.RlpDecode(data)
|
||||
|
||||
return account
|
||||
}
|
||||
|
||||
func (a *Account) AddFee(fee *big.Int) {
|
||||
a.AddFunds(fee)
|
||||
}
|
||||
|
||||
func (a *Account) AddFunds(funds *big.Int) {
|
||||
a.Amount.Add(a.Amount, funds)
|
||||
}
|
||||
|
||||
func (a *Account) Address() []byte {
|
||||
return a.address
|
||||
}
|
||||
|
||||
// Implements Callee
|
||||
func (a *Account) ReturnGas(value *big.Int, state *State) {
|
||||
// Return the value back to the sender
|
||||
a.AddFunds(value)
|
||||
state.UpdateAccount(a.address, a)
|
||||
}
|
||||
|
||||
func (a *Account) RlpEncode() []byte {
|
||||
return ethutil.Encode([]interface{}{a.Amount, a.Nonce})
|
||||
}
|
||||
|
||||
func (a *Account) RlpDecode(data []byte) {
|
||||
decoder := ethutil.NewValueFromBytes(data)
|
||||
|
||||
a.Amount = decoder.Get(0).BigInt()
|
||||
a.Nonce = decoder.Get(1).Uint()
|
||||
}
|
||||
|
||||
type AddrStateStore struct {
|
||||
states map[string]*AccountState
|
||||
}
|
||||
|
||||
func NewAddrStateStore() *AddrStateStore {
|
||||
return &AddrStateStore{states: make(map[string]*AccountState)}
|
||||
}
|
||||
|
||||
func (s *AddrStateStore) Add(addr []byte, account *Account) *AccountState {
|
||||
state := &AccountState{Nonce: account.Nonce, Account: account}
|
||||
s.states[string(addr)] = state
|
||||
return state
|
||||
}
|
||||
|
||||
func (s *AddrStateStore) Get(addr []byte) *AccountState {
|
||||
return s.states[string(addr)]
|
||||
}
|
||||
|
||||
type AccountState struct {
|
||||
Nonce uint64
|
||||
Account *Account
|
||||
}
|
@ -1,8 +0,0 @@
|
||||
package ethchain
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestAddressState(t *testing.T) {
|
||||
}
|
@ -142,12 +142,13 @@ func (block *Block) PayFee(addr []byte, fee *big.Int) bool {
|
||||
data := block.state.trie.Get(string(block.Coinbase))
|
||||
|
||||
// Get the ether (Coinbase) and add the fee (gief fee to miner)
|
||||
ether := NewAccountFromData(block.Coinbase, []byte(data))
|
||||
account := NewStateObjectFromBytes(block.Coinbase, []byte(data))
|
||||
|
||||
base = new(big.Int)
|
||||
ether.Amount = base.Add(ether.Amount, fee)
|
||||
account.Amount = base.Add(account.Amount, fee)
|
||||
|
||||
block.state.trie.Update(string(block.Coinbase), string(ether.RlpEncode()))
|
||||
//block.state.trie.Update(string(block.Coinbase), string(ether.RlpEncode()))
|
||||
block.state.UpdateStateObject(account)
|
||||
|
||||
return true
|
||||
}
|
||||
|
@ -262,9 +262,9 @@ func AddTestNetFunds(block *Block) {
|
||||
} {
|
||||
//log.Println("2^200 Wei to", addr)
|
||||
codedAddr := ethutil.FromHex(addr)
|
||||
addr := block.state.GetAccount(codedAddr)
|
||||
addr.Amount = ethutil.BigPow(2, 200)
|
||||
block.state.UpdateAccount(codedAddr, addr)
|
||||
account := block.state.GetAccount(codedAddr)
|
||||
account.Amount = ethutil.BigPow(2, 200)
|
||||
block.state.UpdateStateObject(account)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,119 +0,0 @@
|
||||
package ethchain
|
||||
|
||||
import (
|
||||
"github.com/ethereum/eth-go/ethutil"
|
||||
"math/big"
|
||||
)
|
||||
|
||||
type Contract struct {
|
||||
Amount *big.Int
|
||||
Nonce uint64
|
||||
//state *ethutil.Trie
|
||||
state *State
|
||||
address []byte
|
||||
script []byte
|
||||
initScript []byte
|
||||
}
|
||||
|
||||
func NewContract(address []byte, Amount *big.Int, root []byte) *Contract {
|
||||
contract := &Contract{address: address, Amount: Amount, Nonce: 0}
|
||||
contract.state = NewState(ethutil.NewTrie(ethutil.Config.Db, string(root)))
|
||||
|
||||
return contract
|
||||
}
|
||||
|
||||
func NewContractFromBytes(address, data []byte) *Contract {
|
||||
contract := &Contract{address: address}
|
||||
contract.RlpDecode(data)
|
||||
|
||||
return contract
|
||||
}
|
||||
|
||||
func (c *Contract) Addr(addr []byte) *ethutil.Value {
|
||||
return ethutil.NewValueFromBytes([]byte(c.state.trie.Get(string(addr))))
|
||||
}
|
||||
|
||||
func (c *Contract) SetAddr(addr []byte, value interface{}) {
|
||||
c.state.trie.Update(string(addr), string(ethutil.NewValue(value).Encode()))
|
||||
}
|
||||
|
||||
func (c *Contract) State() *State {
|
||||
return c.state
|
||||
}
|
||||
|
||||
func (c *Contract) GetMem(num *big.Int) *ethutil.Value {
|
||||
nb := ethutil.BigToBytes(num, 256)
|
||||
|
||||
return c.Addr(nb)
|
||||
}
|
||||
|
||||
func (c *Contract) GetInstr(pc *big.Int) *ethutil.Value {
|
||||
if int64(len(c.script)-1) < pc.Int64() {
|
||||
return ethutil.NewValue(0)
|
||||
}
|
||||
|
||||
return ethutil.NewValueFromBytes([]byte{c.script[pc.Int64()]})
|
||||
}
|
||||
|
||||
func (c *Contract) SetMem(num *big.Int, val *ethutil.Value) {
|
||||
addr := ethutil.BigToBytes(num, 256)
|
||||
c.state.trie.Update(string(addr), string(val.Encode()))
|
||||
}
|
||||
|
||||
// Return the gas back to the origin. Used by the Virtual machine or Closures
|
||||
func (c *Contract) ReturnGas(val *big.Int, state *State) {
|
||||
c.Amount.Add(c.Amount, val)
|
||||
}
|
||||
|
||||
func (c *Contract) Address() []byte {
|
||||
return c.address
|
||||
}
|
||||
|
||||
func (c *Contract) Script() []byte {
|
||||
return c.script
|
||||
}
|
||||
|
||||
func (c *Contract) Init() []byte {
|
||||
return c.initScript
|
||||
}
|
||||
|
||||
func (c *Contract) RlpEncode() []byte {
|
||||
return ethutil.Encode([]interface{}{c.Amount, c.Nonce, c.state.trie.Root, c.script, c.initScript})
|
||||
}
|
||||
|
||||
func (c *Contract) RlpDecode(data []byte) {
|
||||
decoder := ethutil.NewValueFromBytes(data)
|
||||
|
||||
c.Amount = decoder.Get(0).BigInt()
|
||||
c.Nonce = decoder.Get(1).Uint()
|
||||
c.state = NewState(ethutil.NewTrie(ethutil.Config.Db, decoder.Get(2).Interface()))
|
||||
c.script = decoder.Get(3).Bytes()
|
||||
c.initScript = decoder.Get(4).Bytes()
|
||||
}
|
||||
|
||||
func MakeContract(tx *Transaction, state *State) *Contract {
|
||||
// Create contract if there's no recipient
|
||||
if tx.IsContract() {
|
||||
addr := tx.Hash()[12:]
|
||||
|
||||
value := tx.Value
|
||||
contract := NewContract(addr, value, []byte(""))
|
||||
state.trie.Update(string(addr), string(contract.RlpEncode()))
|
||||
contract.script = tx.Data
|
||||
contract.initScript = tx.Init
|
||||
|
||||
/*
|
||||
for i, val := range tx.Data {
|
||||
if len(val) > 0 {
|
||||
bytNum := ethutil.BigToBytes(big.NewInt(int64(i)), 256)
|
||||
contract.state.trie.Update(string(bytNum), string(ethutil.Encode(val)))
|
||||
}
|
||||
}
|
||||
*/
|
||||
state.trie.Update(string(addr), string(contract.RlpEncode()))
|
||||
|
||||
return contract
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
@ -10,7 +10,7 @@ type KeyPair struct {
|
||||
PublicKey []byte
|
||||
|
||||
// The associated account
|
||||
account *Account
|
||||
account *StateObject
|
||||
state *State
|
||||
}
|
||||
|
||||
@ -24,7 +24,7 @@ func (k *KeyPair) Address() []byte {
|
||||
return ethutil.Sha3Bin(k.PublicKey[1:])[12:]
|
||||
}
|
||||
|
||||
func (k *KeyPair) Account() *Account {
|
||||
func (k *KeyPair) Account() *StateObject {
|
||||
if k.account == nil {
|
||||
k.account = k.state.GetAccount(k.Address())
|
||||
}
|
||||
|
@ -47,23 +47,14 @@ func (s *State) Purge() int {
|
||||
return s.trie.NewIterator().Purge()
|
||||
}
|
||||
|
||||
func (s *State) GetContract(addr []byte) *Contract {
|
||||
func (s *State) GetContract(addr []byte) *StateObject {
|
||||
data := s.trie.Get(string(addr))
|
||||
if data == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Whet get contract is called the retrieved value might
|
||||
// be an account. The StateManager uses this to check
|
||||
// to see if the address a tx was sent to is a contract
|
||||
// or an account
|
||||
value := ethutil.NewValueFromBytes([]byte(data))
|
||||
if value.Len() == 2 {
|
||||
return nil
|
||||
}
|
||||
|
||||
// build contract
|
||||
contract := NewContractFromBytes(addr, []byte(data))
|
||||
contract := NewStateObjectFromBytes(addr, []byte(data))
|
||||
|
||||
// Check if there's a cached state for this contract
|
||||
cachedState := s.states[string(addr)]
|
||||
@ -77,28 +68,17 @@ func (s *State) GetContract(addr []byte) *Contract {
|
||||
return contract
|
||||
}
|
||||
|
||||
func (s *State) UpdateContract(contract *Contract) {
|
||||
addr := contract.Address()
|
||||
|
||||
s.states[string(addr)] = contract.state
|
||||
s.trie.Update(string(addr), string(contract.RlpEncode()))
|
||||
}
|
||||
|
||||
func (s *State) GetAccount(addr []byte) (account *Account) {
|
||||
func (s *State) GetAccount(addr []byte) (account *StateObject) {
|
||||
data := s.trie.Get(string(addr))
|
||||
if data == "" {
|
||||
account = NewAccount(addr, big.NewInt(0))
|
||||
} else {
|
||||
account = NewAccountFromData(addr, []byte(data))
|
||||
account = NewStateObjectFromBytes(addr, []byte(data))
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (s *State) UpdateAccount(addr []byte, account *Account) {
|
||||
s.trie.Update(string(addr), string(account.RlpEncode()))
|
||||
}
|
||||
|
||||
func (s *State) Cmp(other *State) bool {
|
||||
return s.trie.Cmp(other.trie)
|
||||
}
|
||||
@ -119,7 +99,7 @@ const (
|
||||
|
||||
// Returns the object stored at key and the type stored at key
|
||||
// Returns nil if nothing is stored
|
||||
func (s *State) Get(key []byte) (*ethutil.Value, ObjType) {
|
||||
func (s *State) GetStateObject(key []byte) (*ethutil.Value, ObjType) {
|
||||
// Fetch data from the trie
|
||||
data := s.trie.Get(string(key))
|
||||
// Returns the nil type, indicating nothing could be retrieved.
|
||||
@ -145,6 +125,17 @@ func (s *State) Get(key []byte) (*ethutil.Value, ObjType) {
|
||||
return val, typ
|
||||
}
|
||||
|
||||
// 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()))
|
||||
}
|
||||
|
||||
func (s *State) Put(key, object []byte) {
|
||||
s.trie.Update(string(key), string(object))
|
||||
}
|
||||
@ -152,27 +143,3 @@ func (s *State) Put(key, object []byte) {
|
||||
func (s *State) Root() interface{} {
|
||||
return s.trie.Root
|
||||
}
|
||||
|
||||
// Script compilation functions
|
||||
// Compiles strings to machine code
|
||||
func Compile(code []string) (script []string) {
|
||||
script = make([]string, len(code))
|
||||
for i, val := range code {
|
||||
instr, _ := ethutil.CompileInstr(val)
|
||||
|
||||
script[i] = string(instr)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func CompileToValues(code []string) (script []*ethutil.Value) {
|
||||
script = make([]*ethutil.Value, len(code))
|
||||
for i, val := range code {
|
||||
instr, _ := ethutil.CompileInstr(val)
|
||||
|
||||
script[i] = ethutil.NewValue(instr)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
@ -30,7 +30,7 @@ type StateManager struct {
|
||||
bc *BlockChain
|
||||
// States for addresses. You can watch any address
|
||||
// at any given time
|
||||
addrStateStore *AddrStateStore
|
||||
stateObjectCache *StateObjectCache
|
||||
|
||||
// Stack for processing contracts
|
||||
stack *Stack
|
||||
@ -58,7 +58,7 @@ func NewStateManager(ethereum EthManager) *StateManager {
|
||||
mem: make(map[string]*big.Int),
|
||||
Pow: &EasyPow{},
|
||||
Ethereum: ethereum,
|
||||
addrStateStore: NewAddrStateStore(),
|
||||
stateObjectCache: NewStateObjectCache(),
|
||||
bc: ethereum.BlockChain(),
|
||||
}
|
||||
sm.procState = ethereum.BlockChain().CurrentBlock.State()
|
||||
@ -70,18 +70,18 @@ func (sm *StateManager) ProcState() *State {
|
||||
}
|
||||
|
||||
// Watches any given address and puts it in the address state store
|
||||
func (sm *StateManager) WatchAddr(addr []byte) *AccountState {
|
||||
func (sm *StateManager) WatchAddr(addr []byte) *CachedStateObject {
|
||||
//XXX account := sm.bc.CurrentBlock.state.GetAccount(addr)
|
||||
account := sm.procState.GetAccount(addr)
|
||||
|
||||
return sm.addrStateStore.Add(addr, account)
|
||||
return sm.stateObjectCache.Add(addr, account)
|
||||
}
|
||||
|
||||
func (sm *StateManager) GetAddrState(addr []byte) *AccountState {
|
||||
account := sm.addrStateStore.Get(addr)
|
||||
func (sm *StateManager) GetAddrState(addr []byte) *CachedStateObject {
|
||||
account := sm.stateObjectCache.Get(addr)
|
||||
if account == nil {
|
||||
a := sm.procState.GetAccount(addr)
|
||||
account = &AccountState{Nonce: a.Nonce, Account: a}
|
||||
account = &CachedStateObject{Nonce: a.Nonce, Object: a}
|
||||
}
|
||||
|
||||
return account
|
||||
@ -116,7 +116,7 @@ func (sm *StateManager) ApplyTransactions(block *Block, txs []*Transaction) {
|
||||
if contract := sm.procState.GetContract(tx.Recipient); contract != nil {
|
||||
err = sm.Ethereum.TxPool().ProcessTransaction(tx, block, true)
|
||||
if err == nil {
|
||||
sm.ProcessContract(contract, tx, block)
|
||||
sm.EvalScript(contract.Script(), contract, tx, block)
|
||||
}
|
||||
} else {
|
||||
err = sm.Ethereum.TxPool().ProcessTransaction(tx, block, false)
|
||||
@ -180,7 +180,6 @@ func (sm *StateManager) ProcessBlock(block *Block, dontReact bool) error {
|
||||
return err
|
||||
}
|
||||
|
||||
// if !sm.compState.Cmp(sm.procState)
|
||||
if !sm.compState.Cmp(sm.procState) {
|
||||
return fmt.Errorf("Invalid merkle root. Expected %x, got %x", sm.compState.trie.Root, sm.procState.trie.Root)
|
||||
}
|
||||
@ -190,9 +189,6 @@ func (sm *StateManager) ProcessBlock(block *Block, dontReact bool) error {
|
||||
// Sync the current block's state to the database and cancelling out the deferred Undo
|
||||
sm.procState.Sync()
|
||||
|
||||
// Broadcast the valid block back to the wire
|
||||
//sm.Ethereum.Broadcast(ethwire.MsgBlockTy, []interface{}{block.Value().Val})
|
||||
|
||||
// Add the block to the chain
|
||||
sm.bc.Add(block)
|
||||
|
||||
@ -282,22 +278,20 @@ func CalculateUncleReward(block *Block) *big.Int {
|
||||
}
|
||||
|
||||
func (sm *StateManager) AccumelateRewards(block *Block) error {
|
||||
|
||||
// Get the coinbase rlp data
|
||||
acc := sm.procState.GetAccount(block.Coinbase)
|
||||
// Get the account associated with the coinbase
|
||||
account := sm.procState.GetAccount(block.Coinbase)
|
||||
// Reward amount of ether to the coinbase address
|
||||
acc.AddFee(CalculateBlockReward(block, len(block.Uncles)))
|
||||
account.AddAmount(CalculateBlockReward(block, len(block.Uncles)))
|
||||
|
||||
addr := make([]byte, len(block.Coinbase))
|
||||
copy(addr, block.Coinbase)
|
||||
sm.procState.UpdateAccount(addr, acc)
|
||||
sm.procState.UpdateStateObject(account)
|
||||
|
||||
for _, uncle := range block.Uncles {
|
||||
uncleAddr := sm.procState.GetAccount(uncle.Coinbase)
|
||||
uncleAddr.AddFee(CalculateUncleReward(uncle))
|
||||
uncleAccount := sm.procState.GetAccount(uncle.Coinbase)
|
||||
uncleAccount.AddAmount(CalculateUncleReward(uncle))
|
||||
|
||||
//processor.state.UpdateAccount(uncle.Coinbase, uncleAddr)
|
||||
sm.procState.UpdateAccount(uncle.Coinbase, uncleAddr)
|
||||
sm.procState.UpdateStateObject(uncleAccount)
|
||||
}
|
||||
|
||||
return nil
|
||||
@ -307,7 +301,7 @@ func (sm *StateManager) Stop() {
|
||||
sm.bc.Stop()
|
||||
}
|
||||
|
||||
func (sm *StateManager) ProcessContract(contract *Contract, tx *Transaction, block *Block) {
|
||||
func (sm *StateManager) EvalScript(script []byte, object *StateObject, tx *Transaction, block *Block) {
|
||||
// Recovering function in case the VM had any errors
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
@ -316,7 +310,7 @@ func (sm *StateManager) ProcessContract(contract *Contract, tx *Transaction, blo
|
||||
}()
|
||||
|
||||
caller := sm.procState.GetAccount(tx.Sender())
|
||||
closure := NewClosure(caller, contract, contract.script, sm.procState, tx.Gas, tx.Value)
|
||||
closure := NewClosure(caller, object, script, sm.procState, tx.Gas, tx.Value)
|
||||
vm := NewVm(sm.procState, RuntimeVars{
|
||||
Origin: caller.Address(),
|
||||
BlockNumber: block.BlockInfo().Number,
|
||||
@ -324,11 +318,9 @@ func (sm *StateManager) ProcessContract(contract *Contract, tx *Transaction, blo
|
||||
Coinbase: block.Coinbase,
|
||||
Time: block.Time,
|
||||
Diff: block.Difficulty,
|
||||
// XXX Tx data? Could be just an argument to the closure instead
|
||||
TxData: nil,
|
||||
})
|
||||
closure.Call(vm, nil, nil)
|
||||
|
||||
// Update the account (refunds)
|
||||
sm.procState.UpdateAccount(tx.Sender(), caller)
|
||||
sm.procState.UpdateStateObject(caller)
|
||||
}
|
||||
|
162
ethchain/state_object.go
Normal file
162
ethchain/state_object.go
Normal file
@ -0,0 +1,162 @@
|
||||
package ethchain
|
||||
|
||||
import (
|
||||
"github.com/ethereum/eth-go/ethutil"
|
||||
"math/big"
|
||||
)
|
||||
|
||||
type StateObject struct {
|
||||
// Address of the object
|
||||
address []byte
|
||||
// Shared attributes
|
||||
Amount *big.Int
|
||||
Nonce uint64
|
||||
// Contract related attributes
|
||||
state *State
|
||||
script []byte
|
||||
initScript []byte
|
||||
}
|
||||
|
||||
func NewContract(address []byte, Amount *big.Int, root []byte) *StateObject {
|
||||
contract := &StateObject{address: address, Amount: Amount, Nonce: 0}
|
||||
contract.state = NewState(ethutil.NewTrie(ethutil.Config.Db, string(root)))
|
||||
|
||||
return contract
|
||||
}
|
||||
|
||||
// Returns a newly created account
|
||||
func NewAccount(address []byte, amount *big.Int) *StateObject {
|
||||
account := &StateObject{address: address, Amount: amount, Nonce: 0}
|
||||
|
||||
return account
|
||||
}
|
||||
|
||||
func NewStateObjectFromBytes(address, data []byte) *StateObject {
|
||||
object := &StateObject{address: address}
|
||||
object.RlpDecode(data)
|
||||
|
||||
return object
|
||||
}
|
||||
|
||||
func (c *StateObject) Addr(addr []byte) *ethutil.Value {
|
||||
return ethutil.NewValueFromBytes([]byte(c.state.trie.Get(string(addr))))
|
||||
}
|
||||
|
||||
func (c *StateObject) SetAddr(addr []byte, value interface{}) {
|
||||
c.state.trie.Update(string(addr), string(ethutil.NewValue(value).Encode()))
|
||||
}
|
||||
|
||||
func (c *StateObject) State() *State {
|
||||
return c.state
|
||||
}
|
||||
|
||||
func (c *StateObject) GetMem(num *big.Int) *ethutil.Value {
|
||||
nb := ethutil.BigToBytes(num, 256)
|
||||
|
||||
return c.Addr(nb)
|
||||
}
|
||||
|
||||
func (c *StateObject) GetInstr(pc *big.Int) *ethutil.Value {
|
||||
if int64(len(c.script)-1) < pc.Int64() {
|
||||
return ethutil.NewValue(0)
|
||||
}
|
||||
|
||||
return ethutil.NewValueFromBytes([]byte{c.script[pc.Int64()]})
|
||||
}
|
||||
|
||||
func (c *StateObject) SetMem(num *big.Int, val *ethutil.Value) {
|
||||
addr := ethutil.BigToBytes(num, 256)
|
||||
c.state.trie.Update(string(addr), string(val.Encode()))
|
||||
}
|
||||
|
||||
// Return the gas back to the origin. Used by the Virtual machine or Closures
|
||||
func (c *StateObject) ReturnGas(val *big.Int, state *State) {
|
||||
c.AddAmount(val)
|
||||
}
|
||||
|
||||
func (c *StateObject) AddAmount(amount *big.Int) {
|
||||
c.Amount.Add(c.Amount, amount)
|
||||
}
|
||||
|
||||
func (c *StateObject) SubAmount(amount *big.Int) {
|
||||
c.Amount.Sub(c.Amount, amount)
|
||||
}
|
||||
|
||||
func (c *StateObject) Address() []byte {
|
||||
return c.address
|
||||
}
|
||||
|
||||
func (c *StateObject) Script() []byte {
|
||||
return c.script
|
||||
}
|
||||
|
||||
func (c *StateObject) Init() []byte {
|
||||
return c.initScript
|
||||
}
|
||||
|
||||
func (c *StateObject) RlpEncode() []byte {
|
||||
var root interface{}
|
||||
if c.state != nil {
|
||||
root = c.state.trie.Root
|
||||
} else {
|
||||
root = nil
|
||||
}
|
||||
return ethutil.Encode([]interface{}{c.Amount, c.Nonce, root, c.script})
|
||||
}
|
||||
|
||||
func (c *StateObject) RlpDecode(data []byte) {
|
||||
decoder := ethutil.NewValueFromBytes(data)
|
||||
|
||||
c.Amount = decoder.Get(0).BigInt()
|
||||
c.Nonce = decoder.Get(1).Uint()
|
||||
c.state = NewState(ethutil.NewTrie(ethutil.Config.Db, decoder.Get(2).Interface()))
|
||||
c.script = decoder.Get(3).Bytes()
|
||||
}
|
||||
|
||||
func MakeContract(tx *Transaction, state *State) *StateObject {
|
||||
// Create contract if there's no recipient
|
||||
if tx.IsContract() {
|
||||
// FIXME
|
||||
addr := tx.Hash()[12:]
|
||||
|
||||
value := tx.Value
|
||||
contract := NewContract(addr, value, []byte(""))
|
||||
state.UpdateStateObject(contract)
|
||||
|
||||
contract.script = tx.Data
|
||||
contract.initScript = tx.Init
|
||||
|
||||
state.UpdateStateObject(contract)
|
||||
|
||||
return contract
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// The cached state and state object cache are helpers which will give you somewhat
|
||||
// control over the nonce. When creating new transactions you're interested in the 'next'
|
||||
// nonce rather than the current nonce. This to avoid creating invalid-nonce transactions.
|
||||
type StateObjectCache struct {
|
||||
cachedObjects map[string]*CachedStateObject
|
||||
}
|
||||
|
||||
func NewStateObjectCache() *StateObjectCache {
|
||||
return &StateObjectCache{cachedObjects: make(map[string]*CachedStateObject)}
|
||||
}
|
||||
|
||||
func (s *StateObjectCache) Add(addr []byte, object *StateObject) *CachedStateObject {
|
||||
state := &CachedStateObject{Nonce: object.Nonce, Object: object}
|
||||
s.cachedObjects[string(addr)] = state
|
||||
|
||||
return state
|
||||
}
|
||||
|
||||
func (s *StateObjectCache) Get(addr []byte) *CachedStateObject {
|
||||
return s.cachedObjects[string(addr)]
|
||||
}
|
||||
|
||||
type CachedStateObject struct {
|
||||
Nonce uint64
|
||||
Object *StateObject
|
||||
}
|
@ -23,8 +23,8 @@ type Transaction struct {
|
||||
contractCreation bool
|
||||
}
|
||||
|
||||
func NewContractCreationTx(value, gasprice *big.Int, data []byte) *Transaction {
|
||||
return &Transaction{Value: value, Gasprice: gasprice, Data: data, contractCreation: true}
|
||||
func NewContractCreationTx(value, gasprice *big.Int, script []byte, init []byte) *Transaction {
|
||||
return &Transaction{Value: value, Gasprice: gasprice, Data: script, Init: init, contractCreation: true}
|
||||
}
|
||||
|
||||
func NewTransactionMessage(to []byte, value, gasprice, gas *big.Int, data []byte) *Transaction {
|
||||
|
@ -118,20 +118,20 @@ func (pool *TxPool) ProcessTransaction(tx *Transaction, block *Block, toContract
|
||||
// Send Tx to self
|
||||
if bytes.Compare(tx.Recipient, tx.Sender()) == 0 {
|
||||
// Subtract the fee
|
||||
sender.Amount.Sub(sender.Amount, new(big.Int).Mul(TxFee, TxFeeRat))
|
||||
sender.SubAmount(new(big.Int).Mul(TxFee, TxFeeRat))
|
||||
} else if toContract {
|
||||
sender.Amount.Sub(sender.Amount, new(big.Int).Mul(TxFee, TxFeeRat))
|
||||
sender.SubAmount(new(big.Int).Mul(TxFee, TxFeeRat))
|
||||
} else {
|
||||
// Subtract the amount from the senders account
|
||||
sender.Amount.Sub(sender.Amount, totAmount)
|
||||
sender.SubAmount(totAmount)
|
||||
|
||||
// Add the amount to receivers account which should conclude this transaction
|
||||
receiver.Amount.Add(receiver.Amount, tx.Value)
|
||||
receiver.AddAmount(tx.Value)
|
||||
|
||||
block.state.UpdateAccount(tx.Recipient, receiver)
|
||||
block.state.UpdateStateObject(receiver)
|
||||
}
|
||||
|
||||
block.state.UpdateAccount(tx.Sender(), sender)
|
||||
block.state.UpdateStateObject(sender)
|
||||
|
||||
log.Printf("[TXPL] Processed Tx %x\n", tx.Hash())
|
||||
|
||||
@ -151,7 +151,7 @@ func (pool *TxPool) ValidateTransaction(tx *Transaction) error {
|
||||
|
||||
// Get the sender
|
||||
accountState := pool.Ethereum.StateManager().GetAddrState(tx.Sender())
|
||||
sender := accountState.Account
|
||||
sender := accountState.Object
|
||||
|
||||
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
|
||||
|
Loading…
Reference in New Issue
Block a user