diff options
Diffstat (limited to 'core/vm/contract.go')
-rw-r--r-- | core/vm/contract.go | 170 |
1 files changed, 170 insertions, 0 deletions
diff --git a/core/vm/contract.go b/core/vm/contract.go new file mode 100644 index 000000000..37ec41cae --- /dev/null +++ b/core/vm/contract.go @@ -0,0 +1,170 @@ +// Copyright 2015 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. + +package vm + +import ( + "math/big" + + "github.com/dexon-foundation/dexon/common" + "github.com/dexon-foundation/dexon/crypto" +) + +// ContractRef is a reference to the contract's backing object +type ContractRef interface { + Address() common.Address +} + +// AccountRef implements ContractRef. +// +// Account references are used during EVM initialisation and +// it's primary use is to fetch addresses. Removing this object +// proves difficult because of the cached jump destinations which +// are fetched from the parent contract (i.e. the caller), which +// is a ContractRef. +type ( + AccountRef common.Address + Bitvec []byte +) + +func (bits *Bitvec) Set(pos uint64) { + (*bits)[pos/8] |= 0x80 >> (pos % 8) +} +func (bits *Bitvec) Set8(pos uint64) { + (*bits)[pos/8] |= 0xFF >> (pos % 8) + (*bits)[pos/8+1] |= ^(0xFF >> (pos % 8)) +} + +// codeSegment checks if the position is in a code segment. +func (bits *Bitvec) CodeSegment(pos uint64) bool { + return ((*bits)[pos/8] & (0x80 >> (pos % 8))) == 0 +} + +// Address casts AccountRef to a Address +func (ar AccountRef) Address() common.Address { return (common.Address)(ar) } + +// Contract represents an ethereum contract in the state database. It contains +// the contract code, calling arguments. Contract implements ContractRef +type Contract struct { + // CallerAddress is the result of the caller which initialised this + // contract. However when the "call method" is delegated this value + // needs to be initialised to that of the caller's caller. + CallerAddress common.Address + caller ContractRef + self ContractRef + + Jumpdests map[common.Hash]Bitvec // Aggregated result of JUMPDEST analysis. + Analysis Bitvec // Locally cached result of JUMPDEST analysis + + Code []byte + CodeHash common.Hash + CodeAddr *common.Address + Input []byte + + Gas uint64 + Value *big.Int +} + +// NewContract returns a new contract environment for the execution of EVM. +func NewContract(caller ContractRef, object ContractRef, value *big.Int, gas uint64) *Contract { + c := &Contract{CallerAddress: caller.Address(), caller: caller, self: object} + + if parent, ok := caller.(*Contract); ok { + // Reuse JUMPDEST analysis from parent context if available. + c.Jumpdests = parent.Jumpdests + } else { + c.Jumpdests = make(map[common.Hash]Bitvec) + } + + // Gas should be a pointer so it can safely be reduced through the run + // This pointer will be off the state transition + c.Gas = gas + // ensures a value is set + c.Value = value + + return c +} + +// AsDelegate sets the contract to be a delegate call and returns the current +// contract (for chaining calls) +func (c *Contract) AsDelegate() *Contract { + // NOTE: caller must, at all times be a contract. It should never happen + // that caller is something other than a Contract. + parent := c.caller.(*Contract) + c.CallerAddress = parent.CallerAddress + c.Value = parent.Value + + return c +} + +// GetByte returns the n'th byte in the contract's byte array +func (c *Contract) GetByte(n uint64) byte { + if n < uint64(len(c.Code)) { + return c.Code[n] + } + + return 0 +} + +// Caller returns the caller of the contract. +// +// Caller will recursively call caller when the contract is a delegate +// call, including that of caller's caller. +func (c *Contract) Caller() common.Address { + return c.CallerAddress +} + +// UseGas attempts the use gas and subtracts it and returns true on success +func (c *Contract) UseGas(gas uint64) (ok bool) { + if c.Gas < gas { + return false + } + c.Gas -= gas + return true +} + +// Address returns the contracts address +func (c *Contract) Address() common.Address { + return c.self.Address() +} + +// SetCallCode sets the code of the contract and address of the backing data +// object +func (c *Contract) SetCallCode(addr *common.Address, hash common.Hash, code []byte) { + c.Code = code + c.CodeHash = hash + c.CodeAddr = addr +} + +// SetCodeOptionalHash can be used to provide code, but it's optional to provide hash. +// In case hash is not provided, the jumpdest analysis will not be saved to the parent context +func (c *Contract) SetCodeOptionalHash(addr *common.Address, CodeAndHash *CodeAndHash) { + c.Code = CodeAndHash.Code + c.CodeHash = CodeAndHash.Hash() + c.CodeAddr = addr +} + +type CodeAndHash struct { + Code []byte + hash common.Hash +} + +func (c *CodeAndHash) Hash() common.Hash { + if c.hash == (common.Hash{}) { + c.hash = crypto.Keccak256Hash(c.Code) + } + return c.hash +} |