mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-27 23:26:44 +00:00
Merge 43577cdf04 into 0ff35e170d
This commit is contained in:
commit
e45e4f75a5
17 changed files with 856 additions and 185 deletions
|
|
@ -289,6 +289,8 @@ func (ethash *Ethash) verifyHeader(chain consensus.ChainReader, header, parent *
|
||||||
func CalcDifficulty(config *params.ChainConfig, time uint64, parent *types.Header) *big.Int {
|
func CalcDifficulty(config *params.ChainConfig, time uint64, parent *types.Header) *big.Int {
|
||||||
next := new(big.Int).Add(parent.Number, common.Big1)
|
next := new(big.Int).Add(parent.Number, common.Big1)
|
||||||
switch {
|
switch {
|
||||||
|
case config.IsMetropolis(next):
|
||||||
|
return calcDifficultyMetropolis(time, parent)
|
||||||
case config.IsHomestead(next):
|
case config.IsHomestead(next):
|
||||||
return calcDifficultyHomestead(time, parent)
|
return calcDifficultyHomestead(time, parent)
|
||||||
default:
|
default:
|
||||||
|
|
@ -299,10 +301,56 @@ func CalcDifficulty(config *params.ChainConfig, time uint64, parent *types.Heade
|
||||||
// Some weird constants to avoid constant memory allocs for them.
|
// Some weird constants to avoid constant memory allocs for them.
|
||||||
var (
|
var (
|
||||||
expDiffPeriod = big.NewInt(100000)
|
expDiffPeriod = big.NewInt(100000)
|
||||||
|
big9 = big.NewInt(9)
|
||||||
big10 = big.NewInt(10)
|
big10 = big.NewInt(10)
|
||||||
bigMinus99 = big.NewInt(-99)
|
bigMinus99 = big.NewInt(-99)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func calcDifficultyMetropolis(time uint64, parent *types.Header) *big.Int {
|
||||||
|
bigTime := new(big.Int).SetUint64(time)
|
||||||
|
bigParentTime := new(big.Int).Set(parent.Time)
|
||||||
|
|
||||||
|
// adj_factor = max((2 if len(parent.uncles) else 1) - ((timestamp - parent.timestamp) // 9), -99)
|
||||||
|
var x *big.Int
|
||||||
|
if parent.UncleHash == types.EmptyUncleHash {
|
||||||
|
x = big.NewInt(1)
|
||||||
|
} else {
|
||||||
|
x = big.NewInt(2)
|
||||||
|
}
|
||||||
|
z := new(big.Int).Sub(bigTime, bigParentTime)
|
||||||
|
z.Div(z, big9)
|
||||||
|
x.Sub(x, z)
|
||||||
|
|
||||||
|
// max(1 - (block_timestamp - parent_timestamp) // 10, -99)))
|
||||||
|
if x.Cmp(bigMinus99) < 0 {
|
||||||
|
x.Set(bigMinus99)
|
||||||
|
}
|
||||||
|
|
||||||
|
// (parent_diff + parent_diff // 2048 * max(1 - (block_timestamp - parent_timestamp) // 10, -99))
|
||||||
|
y := new(big.Int).Div(parent.Difficulty, params.DifficultyBoundDivisor)
|
||||||
|
x.Mul(y, x)
|
||||||
|
x.Add(parent.Difficulty, x)
|
||||||
|
|
||||||
|
// minimum difficulty can ever be (before exponential factor)
|
||||||
|
if x.Cmp(params.MinimumDifficulty) < 0 {
|
||||||
|
x.Set(params.MinimumDifficulty)
|
||||||
|
}
|
||||||
|
|
||||||
|
// for the exponential factor
|
||||||
|
periodCount := new(big.Int).Add(parent.Number, common.Big1)
|
||||||
|
periodCount.Div(periodCount, expDiffPeriod)
|
||||||
|
|
||||||
|
// the exponential factor, commonly referred to as "the bomb"
|
||||||
|
// diff = diff + 2^(periodCount - 2)
|
||||||
|
if periodCount.Cmp(common.Big1) > 0 {
|
||||||
|
y.Sub(periodCount, common.Big2)
|
||||||
|
y.Exp(common.Big2, y, nil)
|
||||||
|
x.Add(x, y)
|
||||||
|
}
|
||||||
|
|
||||||
|
return x
|
||||||
|
}
|
||||||
|
|
||||||
// calcDifficultyHomestead is the difficulty adjustment algorithm. It returns
|
// calcDifficultyHomestead is the difficulty adjustment algorithm. It returns
|
||||||
// the difficulty that a new block should have when created at time given the
|
// the difficulty that a new block should have when created at time given the
|
||||||
// parent block's time and difficulty. The calculation uses the Homestead rules.
|
// parent block's time and difficulty. The calculation uses the Homestead rules.
|
||||||
|
|
|
||||||
|
|
@ -105,10 +105,15 @@ func ApplyTransaction(config *params.ChainConfig, bc *BlockChain, author *common
|
||||||
|
|
||||||
// Update the state with pending changes
|
// Update the state with pending changes
|
||||||
usedGas.Add(usedGas, gas)
|
usedGas.Add(usedGas, gas)
|
||||||
|
var root []byte
|
||||||
|
if config.IsMetropolis(header.Number) {
|
||||||
|
statedb.Finalise()
|
||||||
|
} else {
|
||||||
|
root = statedb.IntermediateRoot(config.IsEIP158(header.Number)).Bytes()
|
||||||
|
}
|
||||||
// Create a new receipt for the transaction, storing the intermediate root and gas used by the tx
|
// Create a new receipt for the transaction, storing the intermediate root and gas used by the tx
|
||||||
// based on the eip phase, we're passing wether the root touch-delete accounts.
|
// based on the eip phase, we're passing wether the root touch-delete accounts.
|
||||||
root := statedb.IntermediateRoot(config.IsEIP158(header.Number))
|
receipt := types.NewReceipt(root, usedGas)
|
||||||
receipt := types.NewReceipt(root.Bytes(), usedGas)
|
|
||||||
receipt.TxHash = tx.Hash()
|
receipt.TxHash = tx.Hash()
|
||||||
receipt.GasUsed = new(big.Int).Set(gas)
|
receipt.GasUsed = new(big.Int).Set(gas)
|
||||||
// if the transaction created a contract, store the creation address in the receipt.
|
// if the transaction created a contract, store the creation address in the receipt.
|
||||||
|
|
|
||||||
|
|
@ -236,7 +236,8 @@ func (st *StateTransition) TransitionDb() (ret []byte, requiredGas, usedGas *big
|
||||||
vmerr error
|
vmerr error
|
||||||
)
|
)
|
||||||
if contractCreation {
|
if contractCreation {
|
||||||
ret, _, st.gas, vmerr = evm.Create(sender, st.data, st.gas, st.value)
|
createAddressFn := vm.CreateAddressFn(st.evm.ChainConfig(), st.evm.BlockNumber, sender.Address(), st.state.GetNonce(sender.Address()), st.data)
|
||||||
|
ret, _, st.gas, vmerr = evm.Create(sender, createAddressFn, st.data, st.gas, st.value)
|
||||||
} else {
|
} else {
|
||||||
// Increment the nonce for the next transaction
|
// Increment the nonce for the next transaction
|
||||||
st.state.SetNonce(sender.Address(), st.state.GetNonce(sender.Address())+1)
|
st.state.SetNonce(sender.Address(), st.state.GetNonce(sender.Address())+1)
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ import (
|
||||||
|
|
||||||
func (r Receipt) MarshalJSON() ([]byte, error) {
|
func (r Receipt) MarshalJSON() ([]byte, error) {
|
||||||
type Receipt struct {
|
type Receipt struct {
|
||||||
PostState hexutil.Bytes `json:"root" gencodec:"required"`
|
PostState hexutil.Bytes `json:"root"`
|
||||||
CumulativeGasUsed *hexutil.Big `json:"cumulativeGasUsed" gencodec:"required"`
|
CumulativeGasUsed *hexutil.Big `json:"cumulativeGasUsed" gencodec:"required"`
|
||||||
Bloom Bloom `json:"logsBloom" gencodec:"required"`
|
Bloom Bloom `json:"logsBloom" gencodec:"required"`
|
||||||
Logs []*Log `json:"logs" gencodec:"required"`
|
Logs []*Log `json:"logs" gencodec:"required"`
|
||||||
|
|
@ -34,7 +34,7 @@ func (r Receipt) MarshalJSON() ([]byte, error) {
|
||||||
|
|
||||||
func (r *Receipt) UnmarshalJSON(input []byte) error {
|
func (r *Receipt) UnmarshalJSON(input []byte) error {
|
||||||
type Receipt struct {
|
type Receipt struct {
|
||||||
PostState hexutil.Bytes `json:"root" gencodec:"required"`
|
PostState hexutil.Bytes `json:"root"`
|
||||||
CumulativeGasUsed *hexutil.Big `json:"cumulativeGasUsed" gencodec:"required"`
|
CumulativeGasUsed *hexutil.Big `json:"cumulativeGasUsed" gencodec:"required"`
|
||||||
Bloom *Bloom `json:"logsBloom" gencodec:"required"`
|
Bloom *Bloom `json:"logsBloom" gencodec:"required"`
|
||||||
Logs []*Log `json:"logs" gencodec:"required"`
|
Logs []*Log `json:"logs" gencodec:"required"`
|
||||||
|
|
@ -46,10 +46,9 @@ func (r *Receipt) UnmarshalJSON(input []byte) error {
|
||||||
if err := json.Unmarshal(input, &dec); err != nil {
|
if err := json.Unmarshal(input, &dec); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if dec.PostState == nil {
|
if dec.PostState != nil {
|
||||||
return errors.New("missing required field 'root' for Receipt")
|
r.PostState = dec.PostState
|
||||||
}
|
}
|
||||||
r.PostState = dec.PostState
|
|
||||||
if dec.CumulativeGasUsed == nil {
|
if dec.CumulativeGasUsed == nil {
|
||||||
return errors.New("missing required field 'cumulativeGasUsed' for Receipt")
|
return errors.New("missing required field 'cumulativeGasUsed' for Receipt")
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,7 @@ import (
|
||||||
// Receipt represents the results of a transaction.
|
// Receipt represents the results of a transaction.
|
||||||
type Receipt struct {
|
type Receipt struct {
|
||||||
// Consensus fields
|
// Consensus fields
|
||||||
PostState []byte `json:"root" gencodec:"required"`
|
PostState []byte `json:"root"`
|
||||||
CumulativeGasUsed *big.Int `json:"cumulativeGasUsed" gencodec:"required"`
|
CumulativeGasUsed *big.Int `json:"cumulativeGasUsed" gencodec:"required"`
|
||||||
Bloom Bloom `json:"logsBloom" gencodec:"required"`
|
Bloom Bloom `json:"logsBloom" gencodec:"required"`
|
||||||
Logs []*Log `json:"logs" gencodec:"required"`
|
Logs []*Log `json:"logs" gencodec:"required"`
|
||||||
|
|
@ -48,6 +48,19 @@ type receiptMarshaling struct {
|
||||||
GasUsed *hexutil.Big
|
GasUsed *hexutil.Big
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type homesteadReceiptRLP struct {
|
||||||
|
PostState []byte
|
||||||
|
CumulativeGasUsed *big.Int
|
||||||
|
Bloom Bloom
|
||||||
|
Logs []*Log
|
||||||
|
}
|
||||||
|
|
||||||
|
type metropolisReceiptRLP struct {
|
||||||
|
CumulativeGasUsed *big.Int
|
||||||
|
Bloom Bloom
|
||||||
|
Logs []*Log
|
||||||
|
}
|
||||||
|
|
||||||
// NewReceipt creates a barebone transaction receipt, copying the init fields.
|
// NewReceipt creates a barebone transaction receipt, copying the init fields.
|
||||||
func NewReceipt(root []byte, cumulativeGasUsed *big.Int) *Receipt {
|
func NewReceipt(root []byte, cumulativeGasUsed *big.Int) *Receipt {
|
||||||
return &Receipt{PostState: common.CopyBytes(root), CumulativeGasUsed: new(big.Int).Set(cumulativeGasUsed)}
|
return &Receipt{PostState: common.CopyBytes(root), CumulativeGasUsed: new(big.Int).Set(cumulativeGasUsed)}
|
||||||
|
|
@ -56,23 +69,28 @@ func NewReceipt(root []byte, cumulativeGasUsed *big.Int) *Receipt {
|
||||||
// EncodeRLP implements rlp.Encoder, and flattens the consensus fields of a receipt
|
// EncodeRLP implements rlp.Encoder, and flattens the consensus fields of a receipt
|
||||||
// into an RLP stream.
|
// into an RLP stream.
|
||||||
func (r *Receipt) EncodeRLP(w io.Writer) error {
|
func (r *Receipt) EncodeRLP(w io.Writer) error {
|
||||||
return rlp.Encode(w, []interface{}{r.PostState, r.CumulativeGasUsed, r.Bloom, r.Logs})
|
if r.PostState == nil {
|
||||||
|
return rlp.Encode(w, &metropolisReceiptRLP{r.CumulativeGasUsed, r.Bloom, r.Logs})
|
||||||
|
} else {
|
||||||
|
return rlp.Encode(w, &homesteadReceiptRLP{r.PostState, r.CumulativeGasUsed, r.Bloom, r.Logs})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// DecodeRLP implements rlp.Decoder, and loads the consensus fields of a receipt
|
// DecodeRLP implements rlp.Decoder, and loads the consensus fields of a receipt
|
||||||
// from an RLP stream.
|
// from an RLP stream.
|
||||||
func (r *Receipt) DecodeRLP(s *rlp.Stream) error {
|
func (r *Receipt) DecodeRLP(s *rlp.Stream) error {
|
||||||
var receipt struct {
|
raw, err := s.Raw()
|
||||||
PostState []byte
|
if err != nil {
|
||||||
CumulativeGasUsed *big.Int
|
|
||||||
Bloom Bloom
|
|
||||||
Logs []*Log
|
|
||||||
}
|
|
||||||
if err := s.Decode(&receipt); err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
r.PostState, r.CumulativeGasUsed, r.Bloom, r.Logs = receipt.PostState, receipt.CumulativeGasUsed, receipt.Bloom, receipt.Logs
|
var hr homesteadReceiptRLP
|
||||||
return nil
|
var mr metropolisReceiptRLP
|
||||||
|
if err = rlp.DecodeBytes(raw, &mr); err == nil {
|
||||||
|
r.CumulativeGasUsed, r.Bloom, r.Logs = mr.CumulativeGasUsed, mr.Bloom, mr.Logs
|
||||||
|
} else if err = rlp.DecodeBytes(raw, &hr); err == nil {
|
||||||
|
r.PostState, r.CumulativeGasUsed, r.Bloom, r.Logs = hr.PostState[:], hr.CumulativeGasUsed, hr.Bloom, hr.Logs
|
||||||
|
}
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// String implements the Stringer interface.
|
// String implements the Stringer interface.
|
||||||
|
|
|
||||||
|
|
@ -45,6 +45,8 @@ type sigCache struct {
|
||||||
func MakeSigner(config *params.ChainConfig, blockNumber *big.Int) Signer {
|
func MakeSigner(config *params.ChainConfig, blockNumber *big.Int) Signer {
|
||||||
var signer Signer
|
var signer Signer
|
||||||
switch {
|
switch {
|
||||||
|
case config.IsMetropolis(blockNumber):
|
||||||
|
signer = NewEIP86Signer(config.ChainId)
|
||||||
case config.IsEIP155(blockNumber):
|
case config.IsEIP155(blockNumber):
|
||||||
signer = NewEIP155Signer(config.ChainId)
|
signer = NewEIP155Signer(config.ChainId)
|
||||||
case config.IsHomestead(blockNumber):
|
case config.IsHomestead(blockNumber):
|
||||||
|
|
@ -88,6 +90,10 @@ func Sender(signer Signer, tx *Transaction) (common.Address, error) {
|
||||||
|
|
||||||
pubkey, err := signer.PublicKey(tx)
|
pubkey, err := signer.PublicKey(tx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if err == errAbstractSigner {
|
||||||
|
return abstractSignerAddress, nil
|
||||||
|
}
|
||||||
|
|
||||||
return common.Address{}, err
|
return common.Address{}, err
|
||||||
}
|
}
|
||||||
var addr common.Address
|
var addr common.Address
|
||||||
|
|
@ -108,6 +114,37 @@ type Signer interface {
|
||||||
Equal(Signer) bool
|
Equal(Signer) bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// EIP86Signer implements the the abstract signing feature
|
||||||
|
type EIP86Signer struct {
|
||||||
|
EIP155Signer
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewEIP86Signer(chainId *big.Int) EIP86Signer {
|
||||||
|
return EIP86Signer{
|
||||||
|
EIP155Signer: NewEIP155Signer(chainId),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s EIP86Signer) Equal(s2 Signer) bool {
|
||||||
|
_, ok := s2.(EIP86Signer)
|
||||||
|
return ok && s.EIP155Signer.Equal(s2)
|
||||||
|
}
|
||||||
|
|
||||||
|
// isAbstractSigner checks whether the transaction signature is that of
|
||||||
|
// the abstract signer. The abstract signer is determined by V being equal
|
||||||
|
// to the chain identifier and r and s being 0.
|
||||||
|
func isAbstractSigner(tx *Transaction, chainId *big.Int) bool {
|
||||||
|
v, r, s := tx.RawSignatureValues()
|
||||||
|
return v.Cmp(chainId) == 0 && r.BitLen() == 0 && s.BitLen() == 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s EIP86Signer) PublicKey(tx *Transaction) ([]byte, error) {
|
||||||
|
if isAbstractSigner(tx, s.chainId) {
|
||||||
|
return nil, errAbstractSigner
|
||||||
|
}
|
||||||
|
return s.EIP155Signer.PublicKey(tx)
|
||||||
|
}
|
||||||
|
|
||||||
// EIP155Transaction implements TransactionInterface using the
|
// EIP155Transaction implements TransactionInterface using the
|
||||||
// EIP155 rules
|
// EIP155 rules
|
||||||
type EIP155Signer struct {
|
type EIP155Signer struct {
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,9 @@ import (
|
||||||
"math/big"
|
"math/big"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/common/math"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
|
"github.com/ethereum/go-ethereum/crypto/bn256"
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
"golang.org/x/crypto/ripemd160"
|
"golang.org/x/crypto/ripemd160"
|
||||||
|
|
@ -46,6 +48,19 @@ var PrecompiledContracts = map[common.Address]PrecompiledContract{
|
||||||
common.BytesToAddress([]byte{4}): &dataCopy{},
|
common.BytesToAddress([]byte{4}): &dataCopy{},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PrecompiledContractsMetropolis contains the default set of ethereum contracts
|
||||||
|
// for metropolis hardfork
|
||||||
|
var PrecompiledContractsMetropolis = map[common.Address]PrecompiledContract{
|
||||||
|
common.BytesToAddress([]byte{1}): &ecrecover{},
|
||||||
|
common.BytesToAddress([]byte{2}): &sha256hash{},
|
||||||
|
common.BytesToAddress([]byte{3}): &ripemd160hash{},
|
||||||
|
common.BytesToAddress([]byte{4}): &dataCopy{},
|
||||||
|
common.BytesToAddress([]byte{5}): &bigModexp{},
|
||||||
|
common.BytesToAddress([]byte{6}): &bn256Add{},
|
||||||
|
common.BytesToAddress([]byte{7}): &bn256ScalarMul{},
|
||||||
|
common.BytesToAddress([]byte{8}): &pairing{},
|
||||||
|
}
|
||||||
|
|
||||||
// RunPrecompile runs and evaluate the output of a precompiled contract defined in contracts.go
|
// RunPrecompile runs and evaluate the output of a precompiled contract defined in contracts.go
|
||||||
func RunPrecompiledContract(p PrecompiledContract, input []byte, contract *Contract) (ret []byte, err error) {
|
func RunPrecompiledContract(p PrecompiledContract, input []byte, contract *Contract) (ret []byte, err error) {
|
||||||
gas := p.RequiredGas(input)
|
gas := p.RequiredGas(input)
|
||||||
|
|
@ -135,3 +150,188 @@ func (c *dataCopy) RequiredGas(input []byte) uint64 {
|
||||||
func (c *dataCopy) Run(in []byte) ([]byte, error) {
|
func (c *dataCopy) Run(in []byte) ([]byte, error) {
|
||||||
return in, nil
|
return in, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// bigModexp implements a native big integer exponential modular operation.
|
||||||
|
type bigModexp struct{}
|
||||||
|
|
||||||
|
// RequiredGas returns the gas required to execute the pre-compiled contract.
|
||||||
|
//
|
||||||
|
// This method does not require any overflow checking as the input size gas costs
|
||||||
|
// required for anything significant is so high it's impossible to pay for.
|
||||||
|
func (c *bigModexp) RequiredGas(input []byte) uint64 {
|
||||||
|
// TODO reword required gas to have error reporting and convert arithmetic
|
||||||
|
// to uint64.
|
||||||
|
if len(input) < 3*32 {
|
||||||
|
input = append(input, make([]byte, 3*32-len(input))...)
|
||||||
|
}
|
||||||
|
var (
|
||||||
|
baseLen = new(big.Int).SetBytes(input[:31])
|
||||||
|
expLen = math.BigMax(new(big.Int).SetBytes(input[32:64]), big.NewInt(1))
|
||||||
|
modLen = new(big.Int).SetBytes(input[65:97])
|
||||||
|
)
|
||||||
|
x := new(big.Int).Set(math.BigMax(baseLen, modLen))
|
||||||
|
x.Mul(x, x)
|
||||||
|
x.Mul(x, expLen)
|
||||||
|
x.Div(x, new(big.Int).SetUint64(params.QuadCoeffDiv))
|
||||||
|
|
||||||
|
return x.Uint64()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *bigModexp) Run(input []byte) ([]byte, error) {
|
||||||
|
if len(input) < 3*32 {
|
||||||
|
input = append(input, make([]byte, 3*32-len(input))...)
|
||||||
|
}
|
||||||
|
// why 32-byte? These values won't fit anyway
|
||||||
|
var (
|
||||||
|
baseLen = new(big.Int).SetBytes(input[:32]).Uint64()
|
||||||
|
expLen = new(big.Int).SetBytes(input[32:64]).Uint64()
|
||||||
|
modLen = new(big.Int).SetBytes(input[64:96]).Uint64()
|
||||||
|
)
|
||||||
|
|
||||||
|
input = input[96:]
|
||||||
|
if uint64(len(input)) < baseLen {
|
||||||
|
input = append(input, make([]byte, baseLen-uint64(len(input)))...)
|
||||||
|
}
|
||||||
|
base := new(big.Int).SetBytes(input[:baseLen])
|
||||||
|
|
||||||
|
input = input[baseLen:]
|
||||||
|
if uint64(len(input)) < expLen {
|
||||||
|
input = append(input, make([]byte, expLen-uint64(len(input)))...)
|
||||||
|
}
|
||||||
|
exp := new(big.Int).SetBytes(input[:expLen])
|
||||||
|
|
||||||
|
input = input[expLen:]
|
||||||
|
if uint64(len(input)) < modLen {
|
||||||
|
input = append(input, make([]byte, modLen-uint64(len(input)))...)
|
||||||
|
}
|
||||||
|
mod := new(big.Int).SetBytes(input[:modLen])
|
||||||
|
|
||||||
|
return common.LeftPadBytes(base.Exp(base, exp, mod).Bytes(), len(input[:modLen])), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type bn256Add struct{}
|
||||||
|
|
||||||
|
// RequiredGas returns the gas required to execute the pre-compiled contract.
|
||||||
|
//
|
||||||
|
// This method does not require any overflow checking as the input size gas costs
|
||||||
|
// required for anything significant is so high it's impossible to pay for.
|
||||||
|
func (c *bn256Add) RequiredGas(input []byte) uint64 {
|
||||||
|
return 0 // TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *bn256Add) Run(in []byte) ([]byte, error) {
|
||||||
|
in = common.RightPadBytes(in, 128)
|
||||||
|
|
||||||
|
x, onCurve := new(bn256.G1).Unmarshal(in[:64])
|
||||||
|
if !onCurve {
|
||||||
|
return nil, errNotOnCurve
|
||||||
|
}
|
||||||
|
gx, gy, _, _ := x.CurvePoints()
|
||||||
|
if gx.Cmp(bn256.P) >= 0 || gy.Cmp(bn256.P) >= 0 {
|
||||||
|
return nil, errInvalidCurvePoint
|
||||||
|
}
|
||||||
|
|
||||||
|
y, onCurve := new(bn256.G1).Unmarshal(in[:64])
|
||||||
|
if !onCurve {
|
||||||
|
return nil, errNotOnCurve
|
||||||
|
}
|
||||||
|
gx, gy, _, _ = x.CurvePoints()
|
||||||
|
if gx.Cmp(bn256.P) >= 0 || gy.Cmp(bn256.P) >= 0 {
|
||||||
|
return nil, errInvalidCurvePoint
|
||||||
|
}
|
||||||
|
x.Add(x, y)
|
||||||
|
|
||||||
|
return x.Marshal(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type bn256ScalarMul struct{}
|
||||||
|
|
||||||
|
// RequiredGas returns the gas required to execute the pre-compiled contract.
|
||||||
|
//
|
||||||
|
// This method does not require any overflow checking as the input size gas costs
|
||||||
|
// required for anything significant is so high it's impossible to pay for.
|
||||||
|
func (c *bn256ScalarMul) RequiredGas(input []byte) uint64 {
|
||||||
|
return 0 // TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *bn256ScalarMul) Run(in []byte) ([]byte, error) {
|
||||||
|
in = common.RightPadBytes(in, 96)
|
||||||
|
|
||||||
|
g1, onCurve := new(bn256.G1).Unmarshal(in[:64])
|
||||||
|
if !onCurve {
|
||||||
|
return nil, errNotOnCurve
|
||||||
|
}
|
||||||
|
x, y, _, _ := g1.CurvePoints()
|
||||||
|
if x.Cmp(bn256.P) >= 0 || y.Cmp(bn256.P) >= 0 {
|
||||||
|
return nil, errInvalidCurvePoint
|
||||||
|
}
|
||||||
|
g1.ScalarMult(g1, new(big.Int).SetBytes(in[64:96]))
|
||||||
|
|
||||||
|
return g1.Marshal(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// pairing implements a pairing pre-compile for the bn256 curve
|
||||||
|
type pairing struct{}
|
||||||
|
|
||||||
|
// RequiredGas returns the gas required to execute the pre-compiled contract.
|
||||||
|
//
|
||||||
|
// This method does not require any overflow checking as the input size gas costs
|
||||||
|
// required for anything significant is so high it's impossible to pay for.
|
||||||
|
func (c *pairing) RequiredGas(input []byte) uint64 {
|
||||||
|
return 0 // TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
const pairSize = 192
|
||||||
|
|
||||||
|
var (
|
||||||
|
true32Byte = []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}
|
||||||
|
fals32Byte = make([]byte, 32)
|
||||||
|
errNotOnCurve = errors.New("point not on elliptic curve")
|
||||||
|
errInvalidCurvePoint = errors.New("invalid elliptic curve point")
|
||||||
|
)
|
||||||
|
|
||||||
|
func (c *pairing) Run(in []byte) ([]byte, error) {
|
||||||
|
if len(in) == 0 {
|
||||||
|
return true32Byte, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(in)%pairSize > 0 {
|
||||||
|
return nil, errBadPrecompileInput
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
g1s []*bn256.G1
|
||||||
|
g2s []*bn256.G2
|
||||||
|
)
|
||||||
|
for i := 0; i < len(in); i += pairSize {
|
||||||
|
g1, onCurve := new(bn256.G1).Unmarshal(in[i : i+64])
|
||||||
|
if !onCurve {
|
||||||
|
return nil, errNotOnCurve
|
||||||
|
}
|
||||||
|
|
||||||
|
x, y, _, _ := g1.CurvePoints()
|
||||||
|
if x.Cmp(bn256.P) >= 0 || y.Cmp(bn256.P) >= 0 {
|
||||||
|
return nil, errInvalidCurvePoint
|
||||||
|
}
|
||||||
|
|
||||||
|
g2, onCurve := new(bn256.G2).Unmarshal(in[i+64 : i+192])
|
||||||
|
if !onCurve {
|
||||||
|
return nil, errNotOnCurve
|
||||||
|
}
|
||||||
|
x2, y2, _, _ := g2.CurvePoints()
|
||||||
|
if x2.Real().Cmp(bn256.P) >= 0 || x2.Imag().Cmp(bn256.P) >= 0 ||
|
||||||
|
y2.Real().Cmp(bn256.P) >= 0 || y2.Imag().Cmp(bn256.P) >= 0 {
|
||||||
|
return nil, errInvalidCurvePoint
|
||||||
|
}
|
||||||
|
|
||||||
|
g1s = append(g1s, g1)
|
||||||
|
g2s = append(g2s, g2)
|
||||||
|
}
|
||||||
|
|
||||||
|
isOne := bn256.PairingCheck(g1s, g2s)
|
||||||
|
if isOne {
|
||||||
|
return true32Byte, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return fals32Byte, nil
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1 +1,35 @@
|
||||||
package vm
|
package vm
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
)
|
||||||
|
|
||||||
|
const input = ""
|
||||||
|
|
||||||
|
func TestPairing(t *testing.T) {
|
||||||
|
pairing := &pairing{}
|
||||||
|
|
||||||
|
for i, test := range []struct {
|
||||||
|
input string
|
||||||
|
valid int
|
||||||
|
}{
|
||||||
|
{"1c76476f4def4bb94541d57ebba1193381ffa7aa76ada664dd31c16024c43f593034dd2920f673e204fee2811c678745fc819b55d3e9d294e45c9b03a76aef41209dd15ebff5d46c4bd888e51a93cf99a7329636c63514396b4a452003a35bf704bf11ca01483bfa8b34b43561848d28905960114c8ac04049af4b6315a416782bb8324af6cfc93537a2ad1a445cfd0ca2a71acd7ac41fadbf933c2a51be344d120a2a4cf30c1bf9845f20c6fe39e07ea2cce61f0c9bb048165fe5e4de877550111e129f1cf1097710d41c4ac70fcdfa5ba2023c6ff1cbeac322de49d1b6df7c2032c61a830e3c17286de9462bf242fca2883585b93870a73853face6a6bf411198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa", 1},
|
||||||
|
{"2eca0c7238bf16e83e7a1e6c5d49540685ff51380f309842a98561558019fc0203d3260361bb8451de5ff5ecd17f010ff22f5c31cdf184e9020b06fa5997db841213d2149b006137fcfb23036606f848d638d576a120ca981b5b1a5f9300b3ee2276cf730cf493cd95d64677bbb75fc42db72513a4c1e387b476d056f80aa75f21ee6226d31426322afcda621464d0611d226783262e21bb3bc86b537e986237096df1f82dff337dd5972e32a8ad43e28a78a96a823ef1cd4debe12b6552ea5f06967a1237ebfeca9aaae0d6d0bab8e28c198c5a339ef8a2407e31cdac516db922160fa257a5fd5b280642ff47b65eca77e626cb685c84fa6d3b6882a283ddd1198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa", 1},
|
||||||
|
{"0f25929bcb43d5a57391564615c9e70a992b10eafa4db109709649cf48c50dd216da2f5cb6be7a0aa72c440c53c9bbdfec6c36c7d515536431b3a865468acbba2e89718ad33c8bed92e210e81d1853435399a271913a6520736a4729cf0d51eb01a9e2ffa2e92599b68e44de5bcf354fa2642bd4f26b259daa6f7ce3ed57aeb314a9a87b789a58af499b314e13c3d65bede56c07ea2d418d6874857b70763713178fb49a2d6cd347dc58973ff49613a20757d0fcc22079f9abd10c3baee245901b9e027bd5cfc2cb5db82d4dc9677ac795ec500ecd47deee3b5da006d6d049b811d7511c78158de484232fc68daf8a45cf217d1c2fae693ff5871e8752d73b21198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa", 1},
|
||||||
|
{"2f2ea0b3da1e8ef11914acf8b2e1b32d99df51f5f4f206fc6b947eae860eddb6068134ddb33dc888ef446b648d72338684d678d2eb2371c61a50734d78da4b7225f83c8b6ab9de74e7da488ef02645c5a16a6652c3c71a15dc37fe3a5dcb7cb122acdedd6308e3bb230d226d16a105295f523a8a02bfc5e8bd2da135ac4c245d065bbad92e7c4e31bf3757f1fe7362a63fbfee50e7dc68da116e67d600d9bf6806d302580dc0661002994e7cd3a7f224e7ddc27802777486bf80f40e4ca3cfdb186bac5188a98c45e6016873d107f5cd131f3a3e339d0375e58bd6219347b008122ae2b09e539e152ec5364e7e2204b03d11d3caa038bfc7cd499f8176aacbee1f39e4e4afc4bc74790a4a028aff2c3d2538731fb755edefd8cb48d6ea589b5e283f150794b6736f670d6a1033f9b46c6f5204f50813eb85c8dc4b59db1c5d39140d97ee4d2b36d99bc49974d18ecca3e7ad51011956051b464d9e27d46cc25e0764bb98575bd466d32db7b15f582b2d5c452b36aa394b789366e5e3ca5aabd415794ab061441e51d01e94640b7e3084a07e02c78cf3103c542bc5b298669f211b88da1679b0b64a63b7e0e7bfe52aae524f73a55be7fe70c7e9bfc94b4cf0da1213d2149b006137fcfb23036606f848d638d576a120ca981b5b1a5f9300b3ee2276cf730cf493cd95d64677bbb75fc42db72513a4c1e387b476d056f80aa75f21ee6226d31426322afcda621464d0611d226783262e21bb3bc86b537e986237096df1f82dff337dd5972e32a8ad43e28a78a96a823ef1cd4debe12b6552ea5f", 1},
|
||||||
|
{"20a754d2071d4d53903e3b31a7e98ad6882d58aec240ef981fdf0a9d22c5926a29c853fcea789887315916bbeb89ca37edb355b4f980c9a12a94f30deeed30211213d2149b006137fcfb23036606f848d638d576a120ca981b5b1a5f9300b3ee2276cf730cf493cd95d64677bbb75fc42db72513a4c1e387b476d056f80aa75f21ee6226d31426322afcda621464d0611d226783262e21bb3bc86b537e986237096df1f82dff337dd5972e32a8ad43e28a78a96a823ef1cd4debe12b6552ea5f1abb4a25eb9379ae96c84fff9f0540abcfc0a0d11aeda02d4f37e4baf74cb0c11073b3ff2cdbb38755f8691ea59e9606696b3ff278acfc098fa8226470d03869217cee0a9ad79a4493b5253e2e4e3a39fc2df38419f230d341f60cb064a0ac290a3d76f140db8418ba512272381446eb73958670f00cf46f1d9e64cba057b53c26f64a8ec70387a13e41430ed3ee4a7db2059cc5fc13c067194bcc0cb49a98552fd72bd9edb657346127da132e5b82ab908f5816c826acb499e22f2412d1a2d70f25929bcb43d5a57391564615c9e70a992b10eafa4db109709649cf48c50dd2198a1f162a73261f112401aa2db79c7dab1533c9935c77290a6ce3b191f2318d198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa", 1},
|
||||||
|
{"1c76476f4def4bb94541d57ebba1193381ffa7aa76ada664dd31c16024c43f593034dd2920f673e204fee2811c678745fc819b55d3e9d294e45c9b03a76aef41209dd15ebff5d46c4bd888e51a93cf99a7329636c63514396b4a452003a35bf704bf11ca01483bfa8b34b43561848d28905960114c8ac04049af4b6315a416782bb8324af6cfc93537a2ad1a445cfd0ca2a71acd7ac41fadbf933c2a51be344d120a2a4cf30c1bf9845f20c6fe39e07ea2cce61f0c9bb048165fe5e4de877550111e129f1cf1097710d41c4ac70fcdfa5ba2023c6ff1cbeac322de49d1b6df7c103188585e2364128fe25c70558f1560f4f9350baf3959e603cc91486e110936198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa", 0},
|
||||||
|
} {
|
||||||
|
r, err := pairing.Run(common.FromHex(test.input))
|
||||||
|
if err != nil {
|
||||||
|
t.Error(i, ":", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if int(r[31]) != test.valid {
|
||||||
|
t.Error(i, "expected", test.valid, "but was", r[31])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -37,6 +37,10 @@ type (
|
||||||
func run(evm *EVM, snapshot int, contract *Contract, input []byte) ([]byte, error) {
|
func run(evm *EVM, snapshot int, contract *Contract, input []byte) ([]byte, error) {
|
||||||
if contract.CodeAddr != nil {
|
if contract.CodeAddr != nil {
|
||||||
precompiledContracts := PrecompiledContracts
|
precompiledContracts := PrecompiledContracts
|
||||||
|
if evm.ChainConfig().IsMetropolis(evm.BlockNumber) {
|
||||||
|
precompiledContracts = PrecompiledContractsMetropolis
|
||||||
|
}
|
||||||
|
|
||||||
if p := precompiledContracts[*contract.CodeAddr]; p != nil {
|
if p := precompiledContracts[*contract.CodeAddr]; p != nil {
|
||||||
return RunPrecompiledContract(p, input, contract)
|
return RunPrecompiledContract(p, input, contract)
|
||||||
}
|
}
|
||||||
|
|
@ -100,8 +104,8 @@ type EVM struct {
|
||||||
abort int32
|
abort int32
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewEVM retutrns a new EVM evmironment. The returned EVM is not thread safe
|
// NewEVM retutrns a new EVM . The returned EVM is not thread safe and should
|
||||||
// and should only ever be used *once*.
|
// only ever be used *once*.
|
||||||
func NewEVM(ctx Context, statedb StateDB, chainConfig *params.ChainConfig, vmConfig Config) *EVM {
|
func NewEVM(ctx Context, statedb StateDB, chainConfig *params.ChainConfig, vmConfig Config) *EVM {
|
||||||
evm := &EVM{
|
evm := &EVM{
|
||||||
Context: ctx,
|
Context: ctx,
|
||||||
|
|
@ -121,6 +125,51 @@ func (evm *EVM) Cancel() {
|
||||||
atomic.StoreInt32(&evm.abort, 1)
|
atomic.StoreInt32(&evm.abort, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (evm *EVM) StaticCall(caller ContractRef, addr common.Address, input []byte, gas uint64) (ret []byte, leftOverGas uint64, err error) {
|
||||||
|
if evm.vmConfig.NoRecursion && evm.depth > 0 {
|
||||||
|
return nil, gas, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Depth check execution. Fail if we're trying to execute above the
|
||||||
|
// limit.
|
||||||
|
if evm.depth > int(params.CallCreateDepth) {
|
||||||
|
return nil, gas, ErrDepth
|
||||||
|
}
|
||||||
|
|
||||||
|
// make sure the readonly is only set if we aren't in readonly yet
|
||||||
|
// this makes also sure that the readonly flag isn't removed for
|
||||||
|
// child calls.
|
||||||
|
if !evm.interpreter.readonly {
|
||||||
|
evm.interpreter.readonly = true
|
||||||
|
defer func() { evm.interpreter.readonly = false }()
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
to = AccountRef(addr)
|
||||||
|
snapshot = evm.StateDB.Snapshot()
|
||||||
|
)
|
||||||
|
if !evm.StateDB.Exist(addr) {
|
||||||
|
return nil, gas, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// initialise a new contract and set the code that is to be used by the
|
||||||
|
// EVM. The contract is a scoped evmironment for this execution context
|
||||||
|
// only.
|
||||||
|
contract := NewContract(caller, to, new(big.Int), gas)
|
||||||
|
contract.SetCallCode(&addr, evm.StateDB.GetCodeHash(addr), evm.StateDB.GetCode(addr))
|
||||||
|
|
||||||
|
ret, err = evm.interpreter.Run(snapshot, contract, input)
|
||||||
|
// When an error was returned by the EVM or when setting the creation code
|
||||||
|
// above we revert to the snapshot and consume any gas remaining. Additionally
|
||||||
|
// when we're in homestead this also counts for code storage gas errors.
|
||||||
|
if err != nil {
|
||||||
|
contract.UseGas(contract.Gas)
|
||||||
|
|
||||||
|
evm.StateDB.RevertToSnapshot(snapshot)
|
||||||
|
}
|
||||||
|
return ret, contract.Gas, err
|
||||||
|
}
|
||||||
|
|
||||||
// Call executes the contract associated with the addr with the given input as parameters. It also handles any
|
// Call executes the contract associated with the addr with the given input as parameters. It also handles any
|
||||||
// necessary value transfer required and takes the necessary steps to create accounts and reverses the state in
|
// necessary value transfer required and takes the necessary steps to create accounts and reverses the state in
|
||||||
// case of an execution error or failed value transfer.
|
// case of an execution error or failed value transfer.
|
||||||
|
|
@ -241,7 +290,7 @@ func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []by
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create creates a new contract using code as deployment code.
|
// Create creates a new contract using code as deployment code.
|
||||||
func (evm *EVM) Create(caller ContractRef, code []byte, gas uint64, value *big.Int) (ret []byte, contractAddr common.Address, leftOverGas uint64, err error) {
|
func (evm *EVM) Create(caller ContractRef, createAddress addressCreationFn, code []byte, gas uint64, value *big.Int) (ret []byte, _ common.Address, leftOverGas uint64, err error) {
|
||||||
if evm.vmConfig.NoRecursion && evm.depth > 0 {
|
if evm.vmConfig.NoRecursion && evm.depth > 0 {
|
||||||
return nil, common.Address{}, gas, nil
|
return nil, common.Address{}, gas, nil
|
||||||
}
|
}
|
||||||
|
|
@ -260,7 +309,9 @@ func (evm *EVM) Create(caller ContractRef, code []byte, gas uint64, value *big.I
|
||||||
evm.StateDB.SetNonce(caller.Address(), nonce+1)
|
evm.StateDB.SetNonce(caller.Address(), nonce+1)
|
||||||
|
|
||||||
snapshot := evm.StateDB.Snapshot()
|
snapshot := evm.StateDB.Snapshot()
|
||||||
contractAddr = crypto.CreateAddress(caller.Address(), nonce)
|
|
||||||
|
contractAddr := createAddress()
|
||||||
|
|
||||||
evm.StateDB.CreateAccount(contractAddr)
|
evm.StateDB.CreateAccount(contractAddr)
|
||||||
if evm.ChainConfig().IsEIP158(evm.BlockNumber) {
|
if evm.ChainConfig().IsEIP158(evm.BlockNumber) {
|
||||||
evm.StateDB.SetNonce(contractAddr, 1)
|
evm.StateDB.SetNonce(contractAddr, 1)
|
||||||
|
|
@ -312,3 +363,5 @@ func (evm *EVM) ChainConfig() *params.ChainConfig { return evm.chainConfig }
|
||||||
|
|
||||||
// Interpreter returns the EVM interpreter
|
// Interpreter returns the EVM interpreter
|
||||||
func (evm *EVM) Interpreter() *Interpreter { return evm.interpreter }
|
func (evm *EVM) Interpreter() *Interpreter { return evm.interpreter }
|
||||||
|
|
||||||
|
type addressCreationFn func() common.Address
|
||||||
|
|
|
||||||
|
|
@ -91,6 +91,32 @@ func gasCalldataCopy(gt params.GasTable, evm *EVM, contract *Contract, stack *St
|
||||||
return gas, nil
|
return gas, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func gasReturnDataCopy(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
||||||
|
gas, err := memoryGasCost(mem, memorySize)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var overflow bool
|
||||||
|
if gas, overflow = math.SafeAdd(gas, GasFastestStep); overflow {
|
||||||
|
return 0, errGasUintOverflow
|
||||||
|
}
|
||||||
|
|
||||||
|
words, overflow := bigUint64(stack.Back(2))
|
||||||
|
if overflow {
|
||||||
|
return 0, errGasUintOverflow
|
||||||
|
}
|
||||||
|
|
||||||
|
if words, overflow = math.SafeMul(toWordSize(words), params.CopyGas); overflow {
|
||||||
|
return 0, errGasUintOverflow
|
||||||
|
}
|
||||||
|
|
||||||
|
if gas, overflow = math.SafeAdd(gas, words); overflow {
|
||||||
|
return 0, errGasUintOverflow
|
||||||
|
}
|
||||||
|
return gas, nil
|
||||||
|
}
|
||||||
|
|
||||||
func gasSStore(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
func gasSStore(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
||||||
var (
|
var (
|
||||||
y, x = stack.Back(1), stack.Back(0)
|
y, x = stack.Back(1), stack.Back(0)
|
||||||
|
|
@ -423,6 +449,35 @@ func gasDelegateCall(gt params.GasTable, evm *EVM, contract *Contract, stack *St
|
||||||
return gas, nil
|
return gas, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func gasStaticCall(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
||||||
|
panic("verify this one")
|
||||||
|
|
||||||
|
gas, err := memoryGasCost(mem, memorySize)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
var overflow bool
|
||||||
|
if gas, overflow = math.SafeAdd(gas, gt.Calls); overflow {
|
||||||
|
return 0, errGasUintOverflow
|
||||||
|
}
|
||||||
|
|
||||||
|
cg, err := callGas(gt, contract.Gas, gas, stack.Back(0))
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
// Replace the stack item with the new gas calculation. This means that
|
||||||
|
// either the original item is left on the stack or the item is replaced by:
|
||||||
|
// (availableGas - gas) * 63 / 64
|
||||||
|
// We replace the stack item so that it's available when the opCall instruction is
|
||||||
|
// called.
|
||||||
|
stack.data[stack.len()-1] = new(big.Int).SetUint64(cg)
|
||||||
|
|
||||||
|
if gas, overflow = math.SafeAdd(gas, cg); overflow {
|
||||||
|
return 0, errGasUintOverflow
|
||||||
|
}
|
||||||
|
return gas, nil
|
||||||
|
}
|
||||||
|
|
||||||
func gasPush(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
func gasPush(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
||||||
return GasFastestStep, nil
|
return GasFastestStep, nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@
|
||||||
package vm
|
package vm
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
|
||||||
|
|
@ -28,7 +29,9 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
bigZero = new(big.Int)
|
bigZero = new(big.Int)
|
||||||
|
errWriteProtection = errors.New("evm: write protection")
|
||||||
|
errReadOutOfBound = errors.New("evm: read out of bound")
|
||||||
)
|
)
|
||||||
|
|
||||||
func opAdd(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
func opAdd(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
|
|
@ -539,6 +542,18 @@ func opGas(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stac
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func CreateAddressFn(chainConfig *params.ChainConfig, blockNumber *big.Int, senderAddress common.Address, nonce uint64, input []byte) func() common.Address {
|
||||||
|
if chainConfig.IsMetropolis(blockNumber) {
|
||||||
|
return func() common.Address {
|
||||||
|
return common.BytesToAddress(crypto.Keccak256(senderAddress.Bytes(), crypto.Keccak256(input))[12:])
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return func() common.Address {
|
||||||
|
return crypto.CreateAddress(senderAddress, nonce)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func opCreate(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
func opCreate(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
var (
|
var (
|
||||||
value = stack.pop()
|
value = stack.pop()
|
||||||
|
|
@ -550,8 +565,10 @@ func opCreate(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *S
|
||||||
gas -= gas / 64
|
gas -= gas / 64
|
||||||
}
|
}
|
||||||
|
|
||||||
|
createAddressFn := CreateAddressFn(evm.ChainConfig(), evm.BlockNumber, contract.Address(), evm.StateDB.GetNonce(contract.Address()), input)
|
||||||
|
|
||||||
contract.UseGas(gas)
|
contract.UseGas(gas)
|
||||||
_, addr, returnGas, suberr := evm.Create(contract, input, gas, value)
|
_, addr, returnGas, suberr := evm.Create(contract, createAddressFn, input, gas, value)
|
||||||
// Push item on the stack based on the returned error. If the ruleset is
|
// Push item on the stack based on the returned error. If the ruleset is
|
||||||
// homestead we must check for CodeStoreOutOfGasError (homestead only
|
// homestead we must check for CodeStoreOutOfGasError (homestead only
|
||||||
// rule) and treat as an error, if the ruleset is frontier we must
|
// rule) and treat as an error, if the ruleset is frontier we must
|
||||||
|
|
@ -570,6 +587,71 @@ func opCreate(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *S
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func opCreate2(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
|
var (
|
||||||
|
value = stack.pop()
|
||||||
|
salt = stack.pop()
|
||||||
|
offset, size = stack.pop(), stack.pop()
|
||||||
|
input = memory.Get(offset.Int64(), size.Int64())
|
||||||
|
gas = contract.Gas
|
||||||
|
)
|
||||||
|
if evm.ChainConfig().IsEIP150(evm.BlockNumber) {
|
||||||
|
gas -= gas / 64
|
||||||
|
}
|
||||||
|
|
||||||
|
createAddress := func() common.Address {
|
||||||
|
return common.BytesToAddress(crypto.Keccak256(contract.Address().Bytes(), salt.Bytes(), crypto.Keccak256(input))[12:])
|
||||||
|
}
|
||||||
|
|
||||||
|
contract.UseGas(gas)
|
||||||
|
_, addr, returnGas, suberr := evm.Create(contract, createAddress, input, gas, value)
|
||||||
|
// Push item on the stack based on the returned error. If the ruleset is
|
||||||
|
// homestead we must check for CodeStoreOutOfGasError (homestead only
|
||||||
|
// rule) and treat as an error, if the ruleset is frontier we must
|
||||||
|
// ignore this error and pretend the operation was successful.
|
||||||
|
if evm.ChainConfig().IsHomestead(evm.BlockNumber) && suberr == ErrCodeStoreOutOfGas {
|
||||||
|
stack.push(new(big.Int))
|
||||||
|
} else if suberr != nil && suberr != ErrCodeStoreOutOfGas {
|
||||||
|
stack.push(new(big.Int))
|
||||||
|
} else {
|
||||||
|
stack.push(addr.Big())
|
||||||
|
}
|
||||||
|
contract.Gas += returnGas
|
||||||
|
|
||||||
|
evm.interpreter.intPool.put(value, offset, size)
|
||||||
|
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func opStaticCall(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
|
// pop gas
|
||||||
|
gas := stack.pop().Uint64()
|
||||||
|
// pop address
|
||||||
|
addr := stack.pop()
|
||||||
|
// pop input size and offset
|
||||||
|
inOffset, inSize := stack.pop(), stack.pop()
|
||||||
|
// pop return size and offset
|
||||||
|
retOffset, retSize := stack.pop(), stack.pop()
|
||||||
|
|
||||||
|
address := common.BigToAddress(addr)
|
||||||
|
|
||||||
|
// Get the arguments from the memory
|
||||||
|
args := memory.Get(inOffset.Int64(), inSize.Int64())
|
||||||
|
|
||||||
|
ret, returnGas, err := evm.StaticCall(contract, address, args, gas)
|
||||||
|
if err != nil {
|
||||||
|
stack.push(new(big.Int))
|
||||||
|
} else {
|
||||||
|
stack.push(big.NewInt(1))
|
||||||
|
|
||||||
|
memory.Set(retOffset.Uint64(), retSize.Uint64(), ret)
|
||||||
|
}
|
||||||
|
contract.Gas += returnGas
|
||||||
|
|
||||||
|
evm.interpreter.intPool.put(addr, inOffset, inSize, retOffset, retSize)
|
||||||
|
return ret, nil
|
||||||
|
}
|
||||||
|
|
||||||
func opCall(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
func opCall(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
gas := stack.pop().Uint64()
|
gas := stack.pop().Uint64()
|
||||||
// pop gas and value of the stack.
|
// pop gas and value of the stack.
|
||||||
|
|
@ -665,6 +747,14 @@ func opReturn(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *S
|
||||||
return ret, nil
|
return ret, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func opRevert(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
|
offset, size := stack.pop(), stack.pop()
|
||||||
|
ret := memory.GetPtr(offset.Int64(), size.Int64())
|
||||||
|
|
||||||
|
evm.interpreter.intPool.put(offset, size)
|
||||||
|
return ret, nil
|
||||||
|
}
|
||||||
|
|
||||||
func opStop(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
func opStop(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
@ -678,6 +768,28 @@ func opSuicide(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func opReturnDataSize(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
|
stack.push(evm.interpreter.intPool.get().SetUint64(uint64(len(evm.interpreter.returnData))))
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func opReturnDataCopy(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
|
||||||
|
var (
|
||||||
|
mOff = stack.pop()
|
||||||
|
cOff = stack.pop()
|
||||||
|
l = stack.pop()
|
||||||
|
)
|
||||||
|
defer evm.interpreter.intPool.put(mOff, cOff, l)
|
||||||
|
|
||||||
|
cEnd := new(big.Int).Add(cOff, l)
|
||||||
|
if cEnd.BitLen() > 64 || uint64(len(evm.interpreter.returnData)) < cEnd.Uint64() {
|
||||||
|
return nil, errReadOutOfBound
|
||||||
|
}
|
||||||
|
memory.Set(mOff.Uint64(), l.Uint64(), evm.interpreter.returnData[cOff.Uint64():cEnd.Uint64()])
|
||||||
|
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
// following functions are used by the instruction jump table
|
// following functions are used by the instruction jump table
|
||||||
|
|
||||||
// make log instruction function
|
// make log instruction function
|
||||||
|
|
|
||||||
|
|
@ -51,10 +51,9 @@ type Config struct {
|
||||||
JumpTable [256]operation
|
JumpTable [256]operation
|
||||||
}
|
}
|
||||||
|
|
||||||
// Interpreter is used to run Ethereum based contracts and will utilise the
|
// Interpreter is capable of interpreting Ethereum Byte code and uses the passed
|
||||||
// passed evmironment to query external sources for state information.
|
// Ethereum Virtual Machine to query for auxiliary data such as state, block and
|
||||||
// The Interpreter will run the byte code VM or JIT VM based on the passed
|
// caller information.
|
||||||
// configuration.
|
|
||||||
type Interpreter struct {
|
type Interpreter struct {
|
||||||
evm *EVM
|
evm *EVM
|
||||||
cfg Config
|
cfg Config
|
||||||
|
|
@ -62,6 +61,8 @@ type Interpreter struct {
|
||||||
intPool *intPool
|
intPool *intPool
|
||||||
|
|
||||||
readonly bool
|
readonly bool
|
||||||
|
// returnData contains the last call's return data
|
||||||
|
returnData []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewInterpreter returns a new instance of the Interpreter.
|
// NewInterpreter returns a new instance of the Interpreter.
|
||||||
|
|
@ -71,6 +72,8 @@ func NewInterpreter(evm *EVM, cfg Config) *Interpreter {
|
||||||
// we'll set the default jump table.
|
// we'll set the default jump table.
|
||||||
if !cfg.JumpTable[STOP].valid {
|
if !cfg.JumpTable[STOP].valid {
|
||||||
switch {
|
switch {
|
||||||
|
case evm.ChainConfig().IsMetropolis(evm.BlockNumber):
|
||||||
|
cfg.JumpTable = metropolisInstructionSet
|
||||||
case evm.ChainConfig().IsHomestead(evm.BlockNumber):
|
case evm.ChainConfig().IsHomestead(evm.BlockNumber):
|
||||||
cfg.JumpTable = homesteadInstructionSet
|
cfg.JumpTable = homesteadInstructionSet
|
||||||
default:
|
default:
|
||||||
|
|
@ -87,6 +90,19 @@ func NewInterpreter(evm *EVM, cfg Config) *Interpreter {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (in *Interpreter) enforceRestrictions(op OpCode, operation operation, stack *Stack) error {
|
func (in *Interpreter) enforceRestrictions(op OpCode, operation operation, stack *Stack) error {
|
||||||
|
if in.evm.chainRules.IsMetropolis {
|
||||||
|
if in.readonly {
|
||||||
|
// if the interpreter is operating in readonly mode, make sure no
|
||||||
|
// state-modifying operation is performed. The 4th stack item
|
||||||
|
// for a call operation is the value. Transfering value from one
|
||||||
|
// account to the others means the state is modified and should also
|
||||||
|
// return with an error.
|
||||||
|
if operation.writes ||
|
||||||
|
((op == CALL || op == CALLCODE) && stack.Back(3).BitLen() > 0) {
|
||||||
|
return errWriteProtection
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -97,8 +113,12 @@ func (in *Interpreter) enforceRestrictions(op OpCode, operation operation, stack
|
||||||
// considered a revert-and-consume-all-gas operation. No error specific checks
|
// considered a revert-and-consume-all-gas operation. No error specific checks
|
||||||
// should be handled to reduce complexity and errors further down the in.
|
// should be handled to reduce complexity and errors further down the in.
|
||||||
func (in *Interpreter) Run(snapshot int, contract *Contract, input []byte) (ret []byte, err error) {
|
func (in *Interpreter) Run(snapshot int, contract *Contract, input []byte) (ret []byte, err error) {
|
||||||
|
// Increment the call depth which is restricted to 1024.
|
||||||
in.evm.depth++
|
in.evm.depth++
|
||||||
defer func() { in.evm.depth-- }()
|
defer func() { in.evm.depth-- }()
|
||||||
|
// Reset the previous call's return data. It's unimportant to preserve the old buffer
|
||||||
|
// as every returning call will return new data anyway.
|
||||||
|
in.returnData = nil
|
||||||
|
|
||||||
// Don't bother with the execution if there's no code.
|
// Don't bother with the execution if there's no code.
|
||||||
if len(contract.Code) == 0 {
|
if len(contract.Code) == 0 {
|
||||||
|
|
@ -201,6 +221,11 @@ func (in *Interpreter) Run(snapshot int, contract *Contract, input []byte) (ret
|
||||||
verifyIntegerPool(in.intPool)
|
verifyIntegerPool(in.intPool)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// checks whether the operation should revert state.
|
||||||
|
if operation.reverts {
|
||||||
|
in.evm.StateDB.RevertToSnapshot(snapshot)
|
||||||
|
}
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
case err != nil:
|
case err != nil:
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
@ -209,10 +234,10 @@ func (in *Interpreter) Run(snapshot int, contract *Contract, input []byte) (ret
|
||||||
case !operation.jumps:
|
case !operation.jumps:
|
||||||
pc++
|
pc++
|
||||||
}
|
}
|
||||||
// if the operation returned a value make sure that is also set
|
// if the operation clears the return data (e.g. it has returning data)
|
||||||
// the last return data.
|
// set the last return to the result of the operation.
|
||||||
if res != nil {
|
if operation.clearsReturndata {
|
||||||
mem.lastReturn = ret
|
in.returnData = res
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil, nil
|
return nil, nil
|
||||||
|
|
|
||||||
|
|
@ -53,13 +53,51 @@ type operation struct {
|
||||||
valid bool
|
valid bool
|
||||||
// reverts determined whether the operation reverts state
|
// reverts determined whether the operation reverts state
|
||||||
reverts bool
|
reverts bool
|
||||||
|
// clearsReturndata determines whether the opertions clears the return data
|
||||||
|
clearsReturndata bool
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
frontierInstructionSet = NewFrontierInstructionSet()
|
frontierInstructionSet = NewFrontierInstructionSet()
|
||||||
homesteadInstructionSet = NewHomesteadInstructionSet()
|
homesteadInstructionSet = NewHomesteadInstructionSet()
|
||||||
|
metropolisInstructionSet = NewMetropolisInstructionSet()
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// NewMetropolisInstructionSet returns the frontier, homestead and
|
||||||
|
// metropolis instructions.
|
||||||
|
func NewMetropolisInstructionSet() [256]operation {
|
||||||
|
// instructions that can be executed during the homestead phase.
|
||||||
|
instructionSet := NewHomesteadInstructionSet()
|
||||||
|
instructionSet[STATIC_CALL] = operation{
|
||||||
|
execute: opStaticCall,
|
||||||
|
gasCost: gasStaticCall,
|
||||||
|
validateStack: makeStackFunc(6, 1),
|
||||||
|
memorySize: memoryStaticCall,
|
||||||
|
valid: true,
|
||||||
|
}
|
||||||
|
instructionSet[REVERT] = operation{
|
||||||
|
execute: opRevert,
|
||||||
|
gasCost: constGasFunc(GasFastestStep),
|
||||||
|
validateStack: makeStackFunc(2, 0),
|
||||||
|
valid: true,
|
||||||
|
reverts: true,
|
||||||
|
}
|
||||||
|
instructionSet[RETURNDATASIZE] = operation{
|
||||||
|
execute: opReturnDataSize,
|
||||||
|
gasCost: constGasFunc(GasQuickStep),
|
||||||
|
validateStack: makeStackFunc(0, 1),
|
||||||
|
valid: true,
|
||||||
|
}
|
||||||
|
instructionSet[RETURNDATACOPY] = operation{
|
||||||
|
execute: opReturnDataCopy,
|
||||||
|
gasCost: gasReturnDataCopy,
|
||||||
|
validateStack: makeStackFunc(3, 0),
|
||||||
|
memorySize: memoryReturnDataCopy,
|
||||||
|
valid: true,
|
||||||
|
}
|
||||||
|
return instructionSet
|
||||||
|
}
|
||||||
|
|
||||||
// NewHomesteadInstructionSet returns the frontier and homestead
|
// NewHomesteadInstructionSet returns the frontier and homestead
|
||||||
// instructions that can be executed during the homestead phase.
|
// instructions that can be executed during the homestead phase.
|
||||||
func NewHomesteadInstructionSet() [256]operation {
|
func NewHomesteadInstructionSet() [256]operation {
|
||||||
|
|
@ -810,6 +848,7 @@ func NewFrontierInstructionSet() [256]operation {
|
||||||
validateStack: makeStackFunc(2, 0),
|
validateStack: makeStackFunc(2, 0),
|
||||||
memorySize: memoryLog,
|
memorySize: memoryLog,
|
||||||
valid: true,
|
valid: true,
|
||||||
|
writes: true,
|
||||||
},
|
},
|
||||||
LOG1: {
|
LOG1: {
|
||||||
execute: makeLog(1),
|
execute: makeLog(1),
|
||||||
|
|
@ -817,6 +856,7 @@ func NewFrontierInstructionSet() [256]operation {
|
||||||
validateStack: makeStackFunc(3, 0),
|
validateStack: makeStackFunc(3, 0),
|
||||||
memorySize: memoryLog,
|
memorySize: memoryLog,
|
||||||
valid: true,
|
valid: true,
|
||||||
|
writes: true,
|
||||||
},
|
},
|
||||||
LOG2: {
|
LOG2: {
|
||||||
execute: makeLog(2),
|
execute: makeLog(2),
|
||||||
|
|
@ -824,6 +864,7 @@ func NewFrontierInstructionSet() [256]operation {
|
||||||
validateStack: makeStackFunc(4, 0),
|
validateStack: makeStackFunc(4, 0),
|
||||||
memorySize: memoryLog,
|
memorySize: memoryLog,
|
||||||
valid: true,
|
valid: true,
|
||||||
|
writes: true,
|
||||||
},
|
},
|
||||||
LOG3: {
|
LOG3: {
|
||||||
execute: makeLog(3),
|
execute: makeLog(3),
|
||||||
|
|
@ -831,6 +872,7 @@ func NewFrontierInstructionSet() [256]operation {
|
||||||
validateStack: makeStackFunc(5, 0),
|
validateStack: makeStackFunc(5, 0),
|
||||||
memorySize: memoryLog,
|
memorySize: memoryLog,
|
||||||
valid: true,
|
valid: true,
|
||||||
|
writes: true,
|
||||||
},
|
},
|
||||||
LOG4: {
|
LOG4: {
|
||||||
execute: makeLog(4),
|
execute: makeLog(4),
|
||||||
|
|
@ -838,28 +880,41 @@ func NewFrontierInstructionSet() [256]operation {
|
||||||
validateStack: makeStackFunc(6, 0),
|
validateStack: makeStackFunc(6, 0),
|
||||||
memorySize: memoryLog,
|
memorySize: memoryLog,
|
||||||
valid: true,
|
valid: true,
|
||||||
},
|
|
||||||
CREATE: {
|
|
||||||
execute: opCreate,
|
|
||||||
gasCost: gasCreate,
|
|
||||||
validateStack: makeStackFunc(3, 1),
|
|
||||||
memorySize: memoryCreate,
|
|
||||||
valid: true,
|
|
||||||
writes: true,
|
writes: true,
|
||||||
},
|
},
|
||||||
|
CREATE: {
|
||||||
|
execute: opCreate,
|
||||||
|
gasCost: gasCreate,
|
||||||
|
validateStack: makeStackFunc(3, 1),
|
||||||
|
memorySize: memoryCreate,
|
||||||
|
valid: true,
|
||||||
|
writes: true,
|
||||||
|
clearsReturndata: true,
|
||||||
|
},
|
||||||
|
CREATE2: {
|
||||||
|
execute: opCreate2,
|
||||||
|
gasCost: gasCreate,
|
||||||
|
validateStack: makeStackFunc(4, 1),
|
||||||
|
memorySize: memoryCreate2,
|
||||||
|
valid: true,
|
||||||
|
writes: true,
|
||||||
|
clearsReturndata: true,
|
||||||
|
},
|
||||||
CALL: {
|
CALL: {
|
||||||
execute: opCall,
|
execute: opCall,
|
||||||
gasCost: gasCall,
|
gasCost: gasCall,
|
||||||
validateStack: makeStackFunc(7, 1),
|
validateStack: makeStackFunc(7, 1),
|
||||||
memorySize: memoryCall,
|
memorySize: memoryCall,
|
||||||
valid: true,
|
valid: true,
|
||||||
|
clearsReturndata: true,
|
||||||
},
|
},
|
||||||
CALLCODE: {
|
CALLCODE: {
|
||||||
execute: opCallCode,
|
execute: opCallCode,
|
||||||
gasCost: gasCallCode,
|
gasCost: gasCallCode,
|
||||||
validateStack: makeStackFunc(7, 1),
|
validateStack: makeStackFunc(7, 1),
|
||||||
memorySize: memoryCall,
|
memorySize: memoryCall,
|
||||||
valid: true,
|
valid: true,
|
||||||
|
clearsReturndata: true,
|
||||||
},
|
},
|
||||||
RETURN: {
|
RETURN: {
|
||||||
execute: opReturn,
|
execute: opReturn,
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,6 @@ import "fmt"
|
||||||
type Memory struct {
|
type Memory struct {
|
||||||
store []byte
|
store []byte
|
||||||
lastGasCost uint64
|
lastGasCost uint64
|
||||||
lastReturn []byte
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewMemory() *Memory {
|
func NewMemory() *Memory {
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,10 @@ func memoryCalldataCopy(stack *Stack) *big.Int {
|
||||||
return calcMemSize(stack.Back(0), stack.Back(2))
|
return calcMemSize(stack.Back(0), stack.Back(2))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func memoryReturnDataCopy(stack *Stack) *big.Int {
|
||||||
|
return calcMemSize(stack.Back(0), stack.Back(2))
|
||||||
|
}
|
||||||
|
|
||||||
func memoryCodeCopy(stack *Stack) *big.Int {
|
func memoryCodeCopy(stack *Stack) *big.Int {
|
||||||
return calcMemSize(stack.Back(0), stack.Back(2))
|
return calcMemSize(stack.Back(0), stack.Back(2))
|
||||||
}
|
}
|
||||||
|
|
@ -54,6 +58,10 @@ func memoryCreate(stack *Stack) *big.Int {
|
||||||
return calcMemSize(stack.Back(1), stack.Back(2))
|
return calcMemSize(stack.Back(1), stack.Back(2))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func memoryCreate2(stack *Stack) *big.Int {
|
||||||
|
return calcMemSize(stack.Back(2), stack.Back(3))
|
||||||
|
}
|
||||||
|
|
||||||
func memoryCall(stack *Stack) *big.Int {
|
func memoryCall(stack *Stack) *big.Int {
|
||||||
x := calcMemSize(stack.Back(5), stack.Back(6))
|
x := calcMemSize(stack.Back(5), stack.Back(6))
|
||||||
y := calcMemSize(stack.Back(3), stack.Back(4))
|
y := calcMemSize(stack.Back(3), stack.Back(4))
|
||||||
|
|
@ -74,6 +82,13 @@ func memoryDelegateCall(stack *Stack) *big.Int {
|
||||||
return math.BigMax(x, y)
|
return math.BigMax(x, y)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func memoryStaticCall(stack *Stack) *big.Int {
|
||||||
|
x := calcMemSize(stack.Back(4), stack.Back(5))
|
||||||
|
y := calcMemSize(stack.Back(2), stack.Back(3))
|
||||||
|
|
||||||
|
return math.BigMax(x, y)
|
||||||
|
}
|
||||||
|
|
||||||
func memoryReturn(stack *Stack) *big.Int {
|
func memoryReturn(stack *Stack) *big.Int {
|
||||||
return calcMemSize(stack.Back(0), stack.Back(1))
|
return calcMemSize(stack.Back(0), stack.Back(1))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -194,6 +194,11 @@ const (
|
||||||
SWAP
|
SWAP
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
RETURNDATASIZE OpCode = 0xd0 + iota
|
||||||
|
RETURNDATACOPY
|
||||||
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// 0xf0 range - closures
|
// 0xf0 range - closures
|
||||||
CREATE OpCode = 0xf0 + iota
|
CREATE OpCode = 0xf0 + iota
|
||||||
|
|
@ -201,7 +206,11 @@ const (
|
||||||
CALLCODE
|
CALLCODE
|
||||||
RETURN
|
RETURN
|
||||||
DELEGATECALL
|
DELEGATECALL
|
||||||
|
STATIC_CALL
|
||||||
|
|
||||||
|
CREATE2 OpCode = 0xfb
|
||||||
|
|
||||||
|
REVERT = 0xfd
|
||||||
SELFDESTRUCT = 0xff
|
SELFDESTRUCT = 0xff
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -349,13 +358,17 @@ var opCodeToString = map[OpCode]string{
|
||||||
LOG3: "LOG3",
|
LOG3: "LOG3",
|
||||||
LOG4: "LOG4",
|
LOG4: "LOG4",
|
||||||
|
|
||||||
|
RETURNDATASIZE: "RETURNDATASIZE",
|
||||||
|
RETURNDATACOPY: "RETURNDATACOPY",
|
||||||
// 0xf0 range
|
// 0xf0 range
|
||||||
CREATE: "CREATE",
|
CREATE: "CREATE",
|
||||||
CALL: "CALL",
|
CALL: "CALL",
|
||||||
RETURN: "RETURN",
|
RETURN: "RETURN",
|
||||||
|
REVERT: "REVERT",
|
||||||
CALLCODE: "CALLCODE",
|
CALLCODE: "CALLCODE",
|
||||||
DELEGATECALL: "DELEGATECALL",
|
DELEGATECALL: "DELEGATECALL",
|
||||||
SELFDESTRUCT: "SELFDESTRUCT",
|
SELFDESTRUCT: "SELFDESTRUCT",
|
||||||
|
STATIC_CALL: "STATIC_CALL",
|
||||||
|
|
||||||
PUSH: "PUSH",
|
PUSH: "PUSH",
|
||||||
DUP: "DUP",
|
DUP: "DUP",
|
||||||
|
|
@ -372,136 +385,140 @@ func (o OpCode) String() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
var stringToOp = map[string]OpCode{
|
var stringToOp = map[string]OpCode{
|
||||||
"STOP": STOP,
|
"STOP": STOP,
|
||||||
"ADD": ADD,
|
"ADD": ADD,
|
||||||
"MUL": MUL,
|
"MUL": MUL,
|
||||||
"SUB": SUB,
|
"SUB": SUB,
|
||||||
"DIV": DIV,
|
"DIV": DIV,
|
||||||
"SDIV": SDIV,
|
"SDIV": SDIV,
|
||||||
"MOD": MOD,
|
"MOD": MOD,
|
||||||
"SMOD": SMOD,
|
"SMOD": SMOD,
|
||||||
"EXP": EXP,
|
"EXP": EXP,
|
||||||
"NOT": NOT,
|
"NOT": NOT,
|
||||||
"LT": LT,
|
"LT": LT,
|
||||||
"GT": GT,
|
"GT": GT,
|
||||||
"SLT": SLT,
|
"SLT": SLT,
|
||||||
"SGT": SGT,
|
"SGT": SGT,
|
||||||
"EQ": EQ,
|
"EQ": EQ,
|
||||||
"ISZERO": ISZERO,
|
"ISZERO": ISZERO,
|
||||||
"SIGNEXTEND": SIGNEXTEND,
|
"SIGNEXTEND": SIGNEXTEND,
|
||||||
"AND": AND,
|
"AND": AND,
|
||||||
"OR": OR,
|
"OR": OR,
|
||||||
"XOR": XOR,
|
"XOR": XOR,
|
||||||
"BYTE": BYTE,
|
"BYTE": BYTE,
|
||||||
"ADDMOD": ADDMOD,
|
"ADDMOD": ADDMOD,
|
||||||
"MULMOD": MULMOD,
|
"MULMOD": MULMOD,
|
||||||
"SHA3": SHA3,
|
"SHA3": SHA3,
|
||||||
"ADDRESS": ADDRESS,
|
"ADDRESS": ADDRESS,
|
||||||
"BALANCE": BALANCE,
|
"BALANCE": BALANCE,
|
||||||
"ORIGIN": ORIGIN,
|
"ORIGIN": ORIGIN,
|
||||||
"CALLER": CALLER,
|
"CALLER": CALLER,
|
||||||
"CALLVALUE": CALLVALUE,
|
"CALLVALUE": CALLVALUE,
|
||||||
"CALLDATALOAD": CALLDATALOAD,
|
"CALLDATALOAD": CALLDATALOAD,
|
||||||
"CALLDATASIZE": CALLDATASIZE,
|
"CALLDATASIZE": CALLDATASIZE,
|
||||||
"CALLDATACOPY": CALLDATACOPY,
|
"CALLDATACOPY": CALLDATACOPY,
|
||||||
"DELEGATECALL": DELEGATECALL,
|
"DELEGATECALL": DELEGATECALL,
|
||||||
"CODESIZE": CODESIZE,
|
"STATIC_CALL": STATIC_CALL,
|
||||||
"CODECOPY": CODECOPY,
|
"CODESIZE": CODESIZE,
|
||||||
"GASPRICE": GASPRICE,
|
"CODECOPY": CODECOPY,
|
||||||
"BLOCKHASH": BLOCKHASH,
|
"GASPRICE": GASPRICE,
|
||||||
"COINBASE": COINBASE,
|
"BLOCKHASH": BLOCKHASH,
|
||||||
"TIMESTAMP": TIMESTAMP,
|
"COINBASE": COINBASE,
|
||||||
"NUMBER": NUMBER,
|
"TIMESTAMP": TIMESTAMP,
|
||||||
"DIFFICULTY": DIFFICULTY,
|
"NUMBER": NUMBER,
|
||||||
"GASLIMIT": GASLIMIT,
|
"DIFFICULTY": DIFFICULTY,
|
||||||
"EXTCODESIZE": EXTCODESIZE,
|
"GASLIMIT": GASLIMIT,
|
||||||
"EXTCODECOPY": EXTCODECOPY,
|
"EXTCODESIZE": EXTCODESIZE,
|
||||||
"POP": POP,
|
"EXTCODECOPY": EXTCODECOPY,
|
||||||
"MLOAD": MLOAD,
|
"POP": POP,
|
||||||
"MSTORE": MSTORE,
|
"MLOAD": MLOAD,
|
||||||
"MSTORE8": MSTORE8,
|
"MSTORE": MSTORE,
|
||||||
"SLOAD": SLOAD,
|
"MSTORE8": MSTORE8,
|
||||||
"SSTORE": SSTORE,
|
"SLOAD": SLOAD,
|
||||||
"JUMP": JUMP,
|
"SSTORE": SSTORE,
|
||||||
"JUMPI": JUMPI,
|
"JUMP": JUMP,
|
||||||
"PC": PC,
|
"JUMPI": JUMPI,
|
||||||
"MSIZE": MSIZE,
|
"PC": PC,
|
||||||
"GAS": GAS,
|
"MSIZE": MSIZE,
|
||||||
"JUMPDEST": JUMPDEST,
|
"GAS": GAS,
|
||||||
"PUSH1": PUSH1,
|
"JUMPDEST": JUMPDEST,
|
||||||
"PUSH2": PUSH2,
|
"PUSH1": PUSH1,
|
||||||
"PUSH3": PUSH3,
|
"PUSH2": PUSH2,
|
||||||
"PUSH4": PUSH4,
|
"PUSH3": PUSH3,
|
||||||
"PUSH5": PUSH5,
|
"PUSH4": PUSH4,
|
||||||
"PUSH6": PUSH6,
|
"PUSH5": PUSH5,
|
||||||
"PUSH7": PUSH7,
|
"PUSH6": PUSH6,
|
||||||
"PUSH8": PUSH8,
|
"PUSH7": PUSH7,
|
||||||
"PUSH9": PUSH9,
|
"PUSH8": PUSH8,
|
||||||
"PUSH10": PUSH10,
|
"PUSH9": PUSH9,
|
||||||
"PUSH11": PUSH11,
|
"PUSH10": PUSH10,
|
||||||
"PUSH12": PUSH12,
|
"PUSH11": PUSH11,
|
||||||
"PUSH13": PUSH13,
|
"PUSH12": PUSH12,
|
||||||
"PUSH14": PUSH14,
|
"PUSH13": PUSH13,
|
||||||
"PUSH15": PUSH15,
|
"PUSH14": PUSH14,
|
||||||
"PUSH16": PUSH16,
|
"PUSH15": PUSH15,
|
||||||
"PUSH17": PUSH17,
|
"PUSH16": PUSH16,
|
||||||
"PUSH18": PUSH18,
|
"PUSH17": PUSH17,
|
||||||
"PUSH19": PUSH19,
|
"PUSH18": PUSH18,
|
||||||
"PUSH20": PUSH20,
|
"PUSH19": PUSH19,
|
||||||
"PUSH21": PUSH21,
|
"PUSH20": PUSH20,
|
||||||
"PUSH22": PUSH22,
|
"PUSH21": PUSH21,
|
||||||
"PUSH23": PUSH23,
|
"PUSH22": PUSH22,
|
||||||
"PUSH24": PUSH24,
|
"PUSH23": PUSH23,
|
||||||
"PUSH25": PUSH25,
|
"PUSH24": PUSH24,
|
||||||
"PUSH26": PUSH26,
|
"PUSH25": PUSH25,
|
||||||
"PUSH27": PUSH27,
|
"PUSH26": PUSH26,
|
||||||
"PUSH28": PUSH28,
|
"PUSH27": PUSH27,
|
||||||
"PUSH29": PUSH29,
|
"PUSH28": PUSH28,
|
||||||
"PUSH30": PUSH30,
|
"PUSH29": PUSH29,
|
||||||
"PUSH31": PUSH31,
|
"PUSH30": PUSH30,
|
||||||
"PUSH32": PUSH32,
|
"PUSH31": PUSH31,
|
||||||
"DUP1": DUP1,
|
"PUSH32": PUSH32,
|
||||||
"DUP2": DUP2,
|
"DUP1": DUP1,
|
||||||
"DUP3": DUP3,
|
"DUP2": DUP2,
|
||||||
"DUP4": DUP4,
|
"DUP3": DUP3,
|
||||||
"DUP5": DUP5,
|
"DUP4": DUP4,
|
||||||
"DUP6": DUP6,
|
"DUP5": DUP5,
|
||||||
"DUP7": DUP7,
|
"DUP6": DUP6,
|
||||||
"DUP8": DUP8,
|
"DUP7": DUP7,
|
||||||
"DUP9": DUP9,
|
"DUP8": DUP8,
|
||||||
"DUP10": DUP10,
|
"DUP9": DUP9,
|
||||||
"DUP11": DUP11,
|
"DUP10": DUP10,
|
||||||
"DUP12": DUP12,
|
"DUP11": DUP11,
|
||||||
"DUP13": DUP13,
|
"DUP12": DUP12,
|
||||||
"DUP14": DUP14,
|
"DUP13": DUP13,
|
||||||
"DUP15": DUP15,
|
"DUP14": DUP14,
|
||||||
"DUP16": DUP16,
|
"DUP15": DUP15,
|
||||||
"SWAP1": SWAP1,
|
"DUP16": DUP16,
|
||||||
"SWAP2": SWAP2,
|
"SWAP1": SWAP1,
|
||||||
"SWAP3": SWAP3,
|
"SWAP2": SWAP2,
|
||||||
"SWAP4": SWAP4,
|
"SWAP3": SWAP3,
|
||||||
"SWAP5": SWAP5,
|
"SWAP4": SWAP4,
|
||||||
"SWAP6": SWAP6,
|
"SWAP5": SWAP5,
|
||||||
"SWAP7": SWAP7,
|
"SWAP6": SWAP6,
|
||||||
"SWAP8": SWAP8,
|
"SWAP7": SWAP7,
|
||||||
"SWAP9": SWAP9,
|
"SWAP8": SWAP8,
|
||||||
"SWAP10": SWAP10,
|
"SWAP9": SWAP9,
|
||||||
"SWAP11": SWAP11,
|
"SWAP10": SWAP10,
|
||||||
"SWAP12": SWAP12,
|
"SWAP11": SWAP11,
|
||||||
"SWAP13": SWAP13,
|
"SWAP12": SWAP12,
|
||||||
"SWAP14": SWAP14,
|
"SWAP13": SWAP13,
|
||||||
"SWAP15": SWAP15,
|
"SWAP14": SWAP14,
|
||||||
"SWAP16": SWAP16,
|
"SWAP15": SWAP15,
|
||||||
"LOG0": LOG0,
|
"SWAP16": SWAP16,
|
||||||
"LOG1": LOG1,
|
"LOG0": LOG0,
|
||||||
"LOG2": LOG2,
|
"LOG1": LOG1,
|
||||||
"LOG3": LOG3,
|
"LOG2": LOG2,
|
||||||
"LOG4": LOG4,
|
"LOG3": LOG3,
|
||||||
"CREATE": CREATE,
|
"LOG4": LOG4,
|
||||||
"CALL": CALL,
|
"CREATE": CREATE,
|
||||||
"RETURN": RETURN,
|
"CALL": CALL,
|
||||||
"CALLCODE": CALLCODE,
|
"RETURN": RETURN,
|
||||||
"SELFDESTRUCT": SELFDESTRUCT,
|
"REVERT": REVERT,
|
||||||
|
"CALLCODE": CALLCODE,
|
||||||
|
"SELFDESTRUCT": SELFDESTRUCT,
|
||||||
|
"RETURNDATASIZE": RETURNDATASIZE,
|
||||||
|
"RETURNDATACOPY": RETURNDATACOPY,
|
||||||
}
|
}
|
||||||
|
|
||||||
func StringToOp(str string) OpCode {
|
func StringToOp(str string) OpCode {
|
||||||
|
|
|
||||||
|
|
@ -203,8 +203,6 @@ func (ec *Client) TransactionReceipt(ctx context.Context, txHash common.Hash) (*
|
||||||
if err == nil {
|
if err == nil {
|
||||||
if r == nil {
|
if r == nil {
|
||||||
return nil, ethereum.NotFound
|
return nil, ethereum.NotFound
|
||||||
} else if len(r.PostState) == 0 {
|
|
||||||
return nil, fmt.Errorf("server returned receipt without post state")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return r, err
|
return r, err
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue