aboutsummaryrefslogtreecommitdiffstats
path: root/ethchain/state_object.go
diff options
context:
space:
mode:
Diffstat (limited to 'ethchain/state_object.go')
-rw-r--r--ethchain/state_object.go273
1 files changed, 273 insertions, 0 deletions
diff --git a/ethchain/state_object.go b/ethchain/state_object.go
new file mode 100644
index 000000000..edac4f6dc
--- /dev/null
+++ b/ethchain/state_object.go
@@ -0,0 +1,273 @@
+package ethchain
+
+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
+ // Shared attributes
+ Amount *big.Int
+ ScriptHash []byte
+ Nonce uint64
+ // Contract related attributes
+ state *State
+ script Code
+ initScript Code
+
+ // Total gas pool is the total amount of gas currently
+ // left if this object is the coinbase. Gas is directly
+ // purchased of the coinbase.
+ gasPool *big.Int
+}
+
+// Converts an transaction in to a state object
+func MakeContract(tx *Transaction, state *State) *StateObject {
+ // Create contract if there's no recipient
+ if tx.IsContract() {
+ addr := tx.CreationAddress()
+
+ contract := state.NewStateObject(addr)
+ contract.initScript = tx.Data
+ contract.state = NewState(ethutil.NewTrie(ethutil.Config.Db, ""))
+
+ return contract
+ }
+
+ return nil
+}
+
+func NewStateObject(addr []byte) *StateObject {
+ object := &StateObject{address: addr, Amount: new(big.Int), gasPool: new(big.Int)}
+ object.state = NewState(ethutil.NewTrie(ethutil.Config.Db, ""))
+
+ return object
+}
+
+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) State() *State {
+ return c.state
+}
+
+func (c *StateObject) N() *big.Int {
+ return big.NewInt(int64(c.Nonce))
+}
+
+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) SetStorage(num *big.Int, val *ethutil.Value) {
+ addr := ethutil.BigToBytes(num, 256)
+
+ if val.BigInt().Cmp(ethutil.Big0) == 0 {
+ c.state.trie.Delete(string(addr))
+
+ return
+ }
+
+ c.SetAddr(addr, val)
+}
+
+func (c *StateObject) GetStorage(num *big.Int) *ethutil.Value {
+ nb := ethutil.BigToBytes(num, 256)
+
+ return c.Addr(nb)
+}
+
+/* DEPRECATED */
+func (c *StateObject) GetMem(num *big.Int) *ethutil.Value {
+ return c.GetStorage(num)
+}
+
+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()]})
+}
+
+// Return the gas back to the origin. Used by the Virtual machine or Closures
+func (c *StateObject) ReturnGas(gas, price *big.Int, state *State) {
+ /*
+ remainder := new(big.Int).Mul(gas, price)
+ c.AddAmount(remainder)
+ */
+}
+
+func (c *StateObject) AddAmount(amount *big.Int) {
+ c.SetAmount(new(big.Int).Add(c.Amount, amount))
+
+ statelogger.Infof("%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))
+
+ statelogger.Infof("%x: #%d %v (- %v)\n", c.Address(), c.Nonce, c.Amount, amount)
+}
+
+func (c *StateObject) SetAmount(amount *big.Int) {
+ c.Amount = amount
+}
+
+func (c *StateObject) ConvertGas(gas, price *big.Int) error {
+ total := new(big.Int).Mul(gas, price)
+ if total.Cmp(c.Amount) > 0 {
+ return fmt.Errorf("insufficient amount: %v, %v", c.Amount, total)
+ }
+
+ c.SubAmount(total)
+
+ return nil
+}
+
+func (self *StateObject) SetGasPool(gasLimit *big.Int) {
+ self.gasPool = new(big.Int).Set(gasLimit)
+
+ statelogger.DebugDetailf("%x: fuel (+ %v)", self.Address(), self.gasPool)
+}
+
+func (self *StateObject) BuyGas(gas, price *big.Int) error {
+ if self.gasPool.Cmp(gas) < 0 {
+ return GasLimitError(self.gasPool, gas)
+ }
+
+ rGas := new(big.Int).Set(gas)
+ rGas.Mul(rGas, price)
+
+ self.AddAmount(rGas)
+
+ return nil
+}
+
+func (self *StateObject) RefundGas(gas, price *big.Int) {
+ self.gasPool.Add(self.gasPool, gas)
+
+ rGas := new(big.Int).Set(gas)
+ rGas.Mul(rGas, price)
+
+ self.Amount.Sub(self.Amount, rGas)
+}
+
+func (self *StateObject) Copy() *StateObject {
+ stateObject := NewStateObject(self.Address())
+ stateObject.Amount.Set(self.Amount)
+ stateObject.ScriptHash = ethutil.CopyBytes(self.ScriptHash)
+ stateObject.Nonce = self.Nonce
+ if self.state != nil {
+ stateObject.state = self.state.Copy()
+ }
+ stateObject.script = ethutil.CopyBytes(self.script)
+ stateObject.initScript = ethutil.CopyBytes(self.initScript)
+ //stateObject.gasPool.Set(self.gasPool)
+
+ return self
+}
+
+func (self *StateObject) Set(stateObject *StateObject) {
+ self = stateObject
+}
+
+/*
+func (self *StateObject) Copy() *StateObject {
+ stCopy := &StateObject{}
+ stCopy.address = make([]byte, len(self.address))
+ copy(stCopy.address, self.address)
+ stCopy.Amount = new(big.Int).Set(self.Amount)
+ stCopy.ScriptHash = make([]byte, len(self.ScriptHash))
+ copy(stCopy.ScriptHash, self.ScriptHash)
+ stCopy.Nonce = self.Nonce
+ if self.state != nil {
+ stCopy.state = self.state.Copy()
+ }
+ stCopy.script = make([]byte, len(self.script))
+ copy(stCopy.script, self.script)
+ stCopy.initScript = make([]byte, len(self.initScript))
+ copy(stCopy.initScript, self.initScript)
+
+ return stCopy
+}
+*/
+
+// Returns the address of the contract/account
+func (c *StateObject) Address() []byte {
+ return c.address
+}
+
+// Returns the main script body
+func (c *StateObject) Script() Code {
+ return c.script
+}
+
+// Returns the initialization script
+func (c *StateObject) Init() Code {
+ return c.initScript
+}
+
+// State object encoding methods
+func (c *StateObject) RlpEncode() []byte {
+ var root interface{}
+ if c.state != nil {
+ root = c.state.trie.Root
+ } else {
+ root = ""
+ }
+
+ return ethutil.Encode([]interface{}{c.Nonce, c.Amount, root, ethutil.Sha3Bin(c.script)})
+}
+
+func (c *StateObject) RlpDecode(data []byte) {
+ decoder := ethutil.NewValueFromBytes(data)
+
+ c.Nonce = decoder.Get(0).Uint()
+ c.Amount = decoder.Get(1).BigInt()
+ c.state = NewState(ethutil.NewTrie(ethutil.Config.Db, decoder.Get(2).Interface()))
+
+ c.ScriptHash = decoder.Get(3).Bytes()
+
+ c.script, _ = ethutil.Config.Db.Get(c.ScriptHash)
+}
+
+// Storage change object. Used by the manifest for notifying changes to
+// the sub channels.
+type StorageState struct {
+ StateAddress []byte
+ Address []byte
+ Value *big.Int
+}