forked from cerc-io/plugeth
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))
|
data := block.state.trie.Get(string(block.Coinbase))
|
||||||
|
|
||||||
// Get the ether (Coinbase) and add the fee (gief fee to miner)
|
// 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)
|
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
|
return true
|
||||||
}
|
}
|
||||||
|
@ -262,9 +262,9 @@ func AddTestNetFunds(block *Block) {
|
|||||||
} {
|
} {
|
||||||
//log.Println("2^200 Wei to", addr)
|
//log.Println("2^200 Wei to", addr)
|
||||||
codedAddr := ethutil.FromHex(addr)
|
codedAddr := ethutil.FromHex(addr)
|
||||||
addr := block.state.GetAccount(codedAddr)
|
account := block.state.GetAccount(codedAddr)
|
||||||
addr.Amount = ethutil.BigPow(2, 200)
|
account.Amount = ethutil.BigPow(2, 200)
|
||||||
block.state.UpdateAccount(codedAddr, addr)
|
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
|
PublicKey []byte
|
||||||
|
|
||||||
// The associated account
|
// The associated account
|
||||||
account *Account
|
account *StateObject
|
||||||
state *State
|
state *State
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -24,7 +24,7 @@ func (k *KeyPair) Address() []byte {
|
|||||||
return ethutil.Sha3Bin(k.PublicKey[1:])[12:]
|
return ethutil.Sha3Bin(k.PublicKey[1:])[12:]
|
||||||
}
|
}
|
||||||
|
|
||||||
func (k *KeyPair) Account() *Account {
|
func (k *KeyPair) Account() *StateObject {
|
||||||
if k.account == nil {
|
if k.account == nil {
|
||||||
k.account = k.state.GetAccount(k.Address())
|
k.account = k.state.GetAccount(k.Address())
|
||||||
}
|
}
|
||||||
|
@ -47,23 +47,14 @@ func (s *State) Purge() int {
|
|||||||
return s.trie.NewIterator().Purge()
|
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))
|
data := s.trie.Get(string(addr))
|
||||||
if data == "" {
|
if data == "" {
|
||||||
return nil
|
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
|
// build contract
|
||||||
contract := NewContractFromBytes(addr, []byte(data))
|
contract := NewStateObjectFromBytes(addr, []byte(data))
|
||||||
|
|
||||||
// Check if there's a cached state for this contract
|
// Check if there's a cached state for this contract
|
||||||
cachedState := s.states[string(addr)]
|
cachedState := s.states[string(addr)]
|
||||||
@ -77,28 +68,17 @@ func (s *State) GetContract(addr []byte) *Contract {
|
|||||||
return contract
|
return contract
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *State) UpdateContract(contract *Contract) {
|
func (s *State) GetAccount(addr []byte) (account *StateObject) {
|
||||||
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) {
|
|
||||||
data := s.trie.Get(string(addr))
|
data := s.trie.Get(string(addr))
|
||||||
if data == "" {
|
if data == "" {
|
||||||
account = NewAccount(addr, big.NewInt(0))
|
account = NewAccount(addr, big.NewInt(0))
|
||||||
} else {
|
} else {
|
||||||
account = NewAccountFromData(addr, []byte(data))
|
account = NewStateObjectFromBytes(addr, []byte(data))
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *State) UpdateAccount(addr []byte, account *Account) {
|
|
||||||
s.trie.Update(string(addr), string(account.RlpEncode()))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *State) Cmp(other *State) bool {
|
func (s *State) Cmp(other *State) bool {
|
||||||
return s.trie.Cmp(other.trie)
|
return s.trie.Cmp(other.trie)
|
||||||
}
|
}
|
||||||
@ -119,7 +99,7 @@ const (
|
|||||||
|
|
||||||
// Returns the object stored at key and the type stored at key
|
// Returns the object stored at key and the type stored at key
|
||||||
// Returns nil if nothing is stored
|
// 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
|
// Fetch data from the trie
|
||||||
data := s.trie.Get(string(key))
|
data := s.trie.Get(string(key))
|
||||||
// Returns the nil type, indicating nothing could be retrieved.
|
// 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
|
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) {
|
func (s *State) Put(key, object []byte) {
|
||||||
s.trie.Update(string(key), string(object))
|
s.trie.Update(string(key), string(object))
|
||||||
}
|
}
|
||||||
@ -152,27 +143,3 @@ func (s *State) Put(key, object []byte) {
|
|||||||
func (s *State) Root() interface{} {
|
func (s *State) Root() interface{} {
|
||||||
return s.trie.Root
|
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
|
bc *BlockChain
|
||||||
// States for addresses. You can watch any address
|
// States for addresses. You can watch any address
|
||||||
// at any given time
|
// at any given time
|
||||||
addrStateStore *AddrStateStore
|
stateObjectCache *StateObjectCache
|
||||||
|
|
||||||
// Stack for processing contracts
|
// Stack for processing contracts
|
||||||
stack *Stack
|
stack *Stack
|
||||||
@ -54,12 +54,12 @@ type StateManager struct {
|
|||||||
|
|
||||||
func NewStateManager(ethereum EthManager) *StateManager {
|
func NewStateManager(ethereum EthManager) *StateManager {
|
||||||
sm := &StateManager{
|
sm := &StateManager{
|
||||||
stack: NewStack(),
|
stack: NewStack(),
|
||||||
mem: make(map[string]*big.Int),
|
mem: make(map[string]*big.Int),
|
||||||
Pow: &EasyPow{},
|
Pow: &EasyPow{},
|
||||||
Ethereum: ethereum,
|
Ethereum: ethereum,
|
||||||
addrStateStore: NewAddrStateStore(),
|
stateObjectCache: NewStateObjectCache(),
|
||||||
bc: ethereum.BlockChain(),
|
bc: ethereum.BlockChain(),
|
||||||
}
|
}
|
||||||
sm.procState = ethereum.BlockChain().CurrentBlock.State()
|
sm.procState = ethereum.BlockChain().CurrentBlock.State()
|
||||||
return sm
|
return sm
|
||||||
@ -70,18 +70,18 @@ func (sm *StateManager) ProcState() *State {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Watches any given address and puts it in the address state store
|
// 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)
|
//XXX account := sm.bc.CurrentBlock.state.GetAccount(addr)
|
||||||
account := sm.procState.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 {
|
func (sm *StateManager) GetAddrState(addr []byte) *CachedStateObject {
|
||||||
account := sm.addrStateStore.Get(addr)
|
account := sm.stateObjectCache.Get(addr)
|
||||||
if account == nil {
|
if account == nil {
|
||||||
a := sm.procState.GetAccount(addr)
|
a := sm.procState.GetAccount(addr)
|
||||||
account = &AccountState{Nonce: a.Nonce, Account: a}
|
account = &CachedStateObject{Nonce: a.Nonce, Object: a}
|
||||||
}
|
}
|
||||||
|
|
||||||
return account
|
return account
|
||||||
@ -116,7 +116,7 @@ func (sm *StateManager) ApplyTransactions(block *Block, txs []*Transaction) {
|
|||||||
if contract := sm.procState.GetContract(tx.Recipient); contract != nil {
|
if contract := sm.procState.GetContract(tx.Recipient); contract != nil {
|
||||||
err = sm.Ethereum.TxPool().ProcessTransaction(tx, block, true)
|
err = sm.Ethereum.TxPool().ProcessTransaction(tx, block, true)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
sm.ProcessContract(contract, tx, block)
|
sm.EvalScript(contract.Script(), contract, tx, block)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
err = sm.Ethereum.TxPool().ProcessTransaction(tx, block, false)
|
err = sm.Ethereum.TxPool().ProcessTransaction(tx, block, false)
|
||||||
@ -180,7 +180,6 @@ func (sm *StateManager) ProcessBlock(block *Block, dontReact bool) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// if !sm.compState.Cmp(sm.procState)
|
|
||||||
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)
|
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
|
// Sync the current block's state to the database and cancelling out the deferred Undo
|
||||||
sm.procState.Sync()
|
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
|
// Add the block to the chain
|
||||||
sm.bc.Add(block)
|
sm.bc.Add(block)
|
||||||
|
|
||||||
@ -282,22 +278,20 @@ func CalculateUncleReward(block *Block) *big.Int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (sm *StateManager) AccumelateRewards(block *Block) error {
|
func (sm *StateManager) AccumelateRewards(block *Block) error {
|
||||||
|
// Get the account associated with the coinbase
|
||||||
// Get the coinbase rlp data
|
account := sm.procState.GetAccount(block.Coinbase)
|
||||||
acc := sm.procState.GetAccount(block.Coinbase)
|
|
||||||
// Reward amount of ether to the coinbase address
|
// 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))
|
addr := make([]byte, len(block.Coinbase))
|
||||||
copy(addr, block.Coinbase)
|
copy(addr, block.Coinbase)
|
||||||
sm.procState.UpdateAccount(addr, acc)
|
sm.procState.UpdateStateObject(account)
|
||||||
|
|
||||||
for _, uncle := range block.Uncles {
|
for _, uncle := range block.Uncles {
|
||||||
uncleAddr := sm.procState.GetAccount(uncle.Coinbase)
|
uncleAccount := sm.procState.GetAccount(uncle.Coinbase)
|
||||||
uncleAddr.AddFee(CalculateUncleReward(uncle))
|
uncleAccount.AddAmount(CalculateUncleReward(uncle))
|
||||||
|
|
||||||
//processor.state.UpdateAccount(uncle.Coinbase, uncleAddr)
|
sm.procState.UpdateStateObject(uncleAccount)
|
||||||
sm.procState.UpdateAccount(uncle.Coinbase, uncleAddr)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@ -307,7 +301,7 @@ func (sm *StateManager) Stop() {
|
|||||||
sm.bc.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
|
// Recovering function in case the VM had any errors
|
||||||
defer func() {
|
defer func() {
|
||||||
if r := recover(); r != nil {
|
if r := recover(); r != nil {
|
||||||
@ -316,7 +310,7 @@ func (sm *StateManager) ProcessContract(contract *Contract, tx *Transaction, blo
|
|||||||
}()
|
}()
|
||||||
|
|
||||||
caller := sm.procState.GetAccount(tx.Sender())
|
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{
|
vm := NewVm(sm.procState, RuntimeVars{
|
||||||
Origin: caller.Address(),
|
Origin: caller.Address(),
|
||||||
BlockNumber: block.BlockInfo().Number,
|
BlockNumber: block.BlockInfo().Number,
|
||||||
@ -324,11 +318,9 @@ func (sm *StateManager) ProcessContract(contract *Contract, tx *Transaction, blo
|
|||||||
Coinbase: block.Coinbase,
|
Coinbase: block.Coinbase,
|
||||||
Time: block.Time,
|
Time: block.Time,
|
||||||
Diff: block.Difficulty,
|
Diff: block.Difficulty,
|
||||||
// XXX Tx data? Could be just an argument to the closure instead
|
|
||||||
TxData: nil,
|
|
||||||
})
|
})
|
||||||
closure.Call(vm, nil, nil)
|
closure.Call(vm, nil, nil)
|
||||||
|
|
||||||
// Update the account (refunds)
|
// 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
|
contractCreation bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewContractCreationTx(value, gasprice *big.Int, data []byte) *Transaction {
|
func NewContractCreationTx(value, gasprice *big.Int, script []byte, init []byte) *Transaction {
|
||||||
return &Transaction{Value: value, Gasprice: gasprice, Data: data, contractCreation: true}
|
return &Transaction{Value: value, Gasprice: gasprice, Data: script, Init: init, contractCreation: true}
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewTransactionMessage(to []byte, value, gasprice, gas *big.Int, data []byte) *Transaction {
|
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
|
// Send Tx to self
|
||||||
if bytes.Compare(tx.Recipient, tx.Sender()) == 0 {
|
if bytes.Compare(tx.Recipient, tx.Sender()) == 0 {
|
||||||
// Subtract the fee
|
// 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 {
|
} else if toContract {
|
||||||
sender.Amount.Sub(sender.Amount, new(big.Int).Mul(TxFee, TxFeeRat))
|
sender.SubAmount(new(big.Int).Mul(TxFee, TxFeeRat))
|
||||||
} else {
|
} else {
|
||||||
// Subtract the amount from the senders account
|
// 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
|
// 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())
|
log.Printf("[TXPL] Processed Tx %x\n", tx.Hash())
|
||||||
|
|
||||||
@ -151,7 +151,7 @@ func (pool *TxPool) ValidateTransaction(tx *Transaction) error {
|
|||||||
|
|
||||||
// Get the sender
|
// Get the sender
|
||||||
accountState := pool.Ethereum.StateManager().GetAddrState(tx.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))
|
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
|
// Make sure there's enough in the sender's account. Having insufficient
|
||||||
|
Loading…
Reference in New Issue
Block a user