forked from cerc-io/plugeth
core: implement Metropolis EIP 658, receipt status byte
This commit is contained in:
parent
2fd5ba6bd4
commit
28aea46ac0
@ -253,7 +253,8 @@ func (b *SimulatedBackend) callContract(ctx context.Context, call ethereum.CallM
|
|||||||
// about the transaction and calling mechanisms.
|
// about the transaction and calling mechanisms.
|
||||||
vmenv := vm.NewEVM(evmContext, statedb, b.config, vm.Config{})
|
vmenv := vm.NewEVM(evmContext, statedb, b.config, vm.Config{})
|
||||||
gaspool := new(core.GasPool).AddGas(math.MaxBig256)
|
gaspool := new(core.GasPool).AddGas(math.MaxBig256)
|
||||||
ret, gasUsed, _, err := core.NewStateTransition(vmenv, msg, gaspool).TransitionDb()
|
// TODO utilize returned failed flag to help gas estimation.
|
||||||
|
ret, gasUsed, _, _, err := core.NewStateTransition(vmenv, msg, gaspool).TransitionDb()
|
||||||
return ret, gasUsed, err
|
return ret, gasUsed, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -47,6 +47,9 @@ func FromHex(s string) []byte {
|
|||||||
//
|
//
|
||||||
// Returns an exact copy of the provided bytes
|
// Returns an exact copy of the provided bytes
|
||||||
func CopyBytes(b []byte) (copiedBytes []byte) {
|
func CopyBytes(b []byte) (copiedBytes []byte) {
|
||||||
|
if b == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
copiedBytes = make([]byte, len(b))
|
copiedBytes = make([]byte, len(b))
|
||||||
copy(copiedBytes, b)
|
copy(copiedBytes, b)
|
||||||
|
|
||||||
|
@ -461,12 +461,12 @@ func TestMipmapChain(t *testing.T) {
|
|||||||
var receipts types.Receipts
|
var receipts types.Receipts
|
||||||
switch i {
|
switch i {
|
||||||
case 1:
|
case 1:
|
||||||
receipt := types.NewReceipt(nil, new(big.Int))
|
receipt := types.NewReceipt(nil, false, new(big.Int))
|
||||||
receipt.Logs = []*types.Log{{Address: addr, Topics: []common.Hash{hash1}}}
|
receipt.Logs = []*types.Log{{Address: addr, Topics: []common.Hash{hash1}}}
|
||||||
gen.AddUncheckedReceipt(receipt)
|
gen.AddUncheckedReceipt(receipt)
|
||||||
receipts = types.Receipts{receipt}
|
receipts = types.Receipts{receipt}
|
||||||
case 1000:
|
case 1000:
|
||||||
receipt := types.NewReceipt(nil, new(big.Int))
|
receipt := types.NewReceipt(nil, false, new(big.Int))
|
||||||
receipt.Logs = []*types.Log{{Address: addr2}}
|
receipt.Logs = []*types.Log{{Address: addr2}}
|
||||||
gen.AddUncheckedReceipt(receipt)
|
gen.AddUncheckedReceipt(receipt)
|
||||||
receipts = types.Receipts{receipt}
|
receipts = types.Receipts{receipt}
|
||||||
|
@ -98,7 +98,7 @@ func ApplyTransaction(config *params.ChainConfig, bc *BlockChain, author *common
|
|||||||
// about the transaction and calling mechanisms.
|
// about the transaction and calling mechanisms.
|
||||||
vmenv := vm.NewEVM(context, statedb, config, cfg)
|
vmenv := vm.NewEVM(context, statedb, config, cfg)
|
||||||
// Apply the transaction to the current state (included in the env)
|
// Apply the transaction to the current state (included in the env)
|
||||||
_, gas, err := ApplyMessage(vmenv, msg, gp)
|
_, gas, failed, err := ApplyMessage(vmenv, msg, gp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
@ -114,7 +114,7 @@ func ApplyTransaction(config *params.ChainConfig, bc *BlockChain, author *common
|
|||||||
|
|
||||||
// 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.
|
||||||
receipt := types.NewReceipt(root, usedGas)
|
receipt := types.NewReceipt(root, failed, 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.
|
||||||
|
@ -59,7 +59,6 @@ type StateTransition struct {
|
|||||||
value *big.Int
|
value *big.Int
|
||||||
data []byte
|
data []byte
|
||||||
state vm.StateDB
|
state vm.StateDB
|
||||||
|
|
||||||
evm *vm.EVM
|
evm *vm.EVM
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -127,11 +126,11 @@ func NewStateTransition(evm *vm.EVM, msg Message, gp *GasPool) *StateTransition
|
|||||||
// the gas used (which includes gas refunds) and an error if it failed. An error always
|
// the gas used (which includes gas refunds) and an error if it failed. An error always
|
||||||
// indicates a core error meaning that the message would always fail for that particular
|
// indicates a core error meaning that the message would always fail for that particular
|
||||||
// state and would never be accepted within a block.
|
// state and would never be accepted within a block.
|
||||||
func ApplyMessage(evm *vm.EVM, msg Message, gp *GasPool) ([]byte, *big.Int, error) {
|
func ApplyMessage(evm *vm.EVM, msg Message, gp *GasPool) ([]byte, *big.Int, bool, error) {
|
||||||
st := NewStateTransition(evm, msg, gp)
|
st := NewStateTransition(evm, msg, gp)
|
||||||
|
|
||||||
ret, _, gasUsed, err := st.TransitionDb()
|
ret, _, gasUsed, failed, err := st.TransitionDb()
|
||||||
return ret, gasUsed, err
|
return ret, gasUsed, failed, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (st *StateTransition) from() vm.AccountRef {
|
func (st *StateTransition) from() vm.AccountRef {
|
||||||
@ -208,7 +207,7 @@ func (st *StateTransition) preCheck() error {
|
|||||||
// TransitionDb will transition the state by applying the current message and returning the result
|
// TransitionDb will transition the state by applying the current message and returning the result
|
||||||
// including the required gas for the operation as well as the used gas. It returns an error if it
|
// including the required gas for the operation as well as the used gas. It returns an error if it
|
||||||
// failed. An error indicates a consensus issue.
|
// failed. An error indicates a consensus issue.
|
||||||
func (st *StateTransition) TransitionDb() (ret []byte, requiredGas, usedGas *big.Int, err error) {
|
func (st *StateTransition) TransitionDb() (ret []byte, requiredGas, usedGas *big.Int, failed bool, err error) {
|
||||||
if err = st.preCheck(); err != nil {
|
if err = st.preCheck(); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -222,10 +221,10 @@ func (st *StateTransition) TransitionDb() (ret []byte, requiredGas, usedGas *big
|
|||||||
// TODO convert to uint64
|
// TODO convert to uint64
|
||||||
intrinsicGas := IntrinsicGas(st.data, contractCreation, homestead)
|
intrinsicGas := IntrinsicGas(st.data, contractCreation, homestead)
|
||||||
if intrinsicGas.BitLen() > 64 {
|
if intrinsicGas.BitLen() > 64 {
|
||||||
return nil, nil, nil, vm.ErrOutOfGas
|
return nil, nil, nil, false, vm.ErrOutOfGas
|
||||||
}
|
}
|
||||||
if err = st.useGas(intrinsicGas.Uint64()); err != nil {
|
if err = st.useGas(intrinsicGas.Uint64()); err != nil {
|
||||||
return nil, nil, nil, err
|
return nil, nil, nil, false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -248,7 +247,7 @@ func (st *StateTransition) TransitionDb() (ret []byte, requiredGas, usedGas *big
|
|||||||
// sufficient balance to make the transfer happen. The first
|
// sufficient balance to make the transfer happen. The first
|
||||||
// balance transfer may never fail.
|
// balance transfer may never fail.
|
||||||
if vmerr == vm.ErrInsufficientBalance {
|
if vmerr == vm.ErrInsufficientBalance {
|
||||||
return nil, nil, nil, vmerr
|
return nil, nil, nil, false, vmerr
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
requiredGas = new(big.Int).Set(st.gasUsed())
|
requiredGas = new(big.Int).Set(st.gasUsed())
|
||||||
@ -256,7 +255,7 @@ func (st *StateTransition) TransitionDb() (ret []byte, requiredGas, usedGas *big
|
|||||||
st.refundGas()
|
st.refundGas()
|
||||||
st.state.AddBalance(st.evm.Coinbase, new(big.Int).Mul(st.gasUsed(), st.gasPrice))
|
st.state.AddBalance(st.evm.Coinbase, new(big.Int).Mul(st.gasUsed(), st.gasPrice))
|
||||||
|
|
||||||
return ret, requiredGas, st.gasUsed(), err
|
return ret, requiredGas, st.gasUsed(), vmerr != nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (st *StateTransition) refundGas() {
|
func (st *StateTransition) refundGas() {
|
||||||
|
@ -14,6 +14,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"`
|
PostState hexutil.Bytes `json:"root"`
|
||||||
|
Failed bool `json:"failed"`
|
||||||
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"`
|
||||||
@ -23,6 +24,7 @@ func (r Receipt) MarshalJSON() ([]byte, error) {
|
|||||||
}
|
}
|
||||||
var enc Receipt
|
var enc Receipt
|
||||||
enc.PostState = r.PostState
|
enc.PostState = r.PostState
|
||||||
|
enc.Failed = r.Failed
|
||||||
enc.CumulativeGasUsed = (*hexutil.Big)(r.CumulativeGasUsed)
|
enc.CumulativeGasUsed = (*hexutil.Big)(r.CumulativeGasUsed)
|
||||||
enc.Bloom = r.Bloom
|
enc.Bloom = r.Bloom
|
||||||
enc.Logs = r.Logs
|
enc.Logs = r.Logs
|
||||||
@ -35,6 +37,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"`
|
PostState hexutil.Bytes `json:"root"`
|
||||||
|
Failed *bool `json:"failed"`
|
||||||
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"`
|
||||||
@ -49,6 +52,9 @@ func (r *Receipt) UnmarshalJSON(input []byte) error {
|
|||||||
if dec.PostState != nil {
|
if dec.PostState != nil {
|
||||||
r.PostState = dec.PostState
|
r.PostState = dec.PostState
|
||||||
}
|
}
|
||||||
|
if dec.Failed != nil {
|
||||||
|
r.Failed = *dec.Failed
|
||||||
|
}
|
||||||
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")
|
||||||
}
|
}
|
||||||
|
@ -28,10 +28,16 @@ import (
|
|||||||
|
|
||||||
//go:generate gencodec -type Receipt -field-override receiptMarshaling -out gen_receipt_json.go
|
//go:generate gencodec -type Receipt -field-override receiptMarshaling -out gen_receipt_json.go
|
||||||
|
|
||||||
|
const (
|
||||||
|
receiptStatusSuccessful = byte(0x01)
|
||||||
|
receiptStatusFailed = byte(0x00)
|
||||||
|
)
|
||||||
|
|
||||||
// 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"`
|
PostState []byte `json:"root"`
|
||||||
|
Failed bool `json:"failed"`
|
||||||
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"`
|
||||||
@ -60,21 +66,26 @@ type homesteadReceiptRLP struct {
|
|||||||
// metropolisReceiptRLP contains the receipt's Metropolis consensus fields, used
|
// metropolisReceiptRLP contains the receipt's Metropolis consensus fields, used
|
||||||
// during RLP serialization.
|
// during RLP serialization.
|
||||||
type metropolisReceiptRLP struct {
|
type metropolisReceiptRLP struct {
|
||||||
|
Status byte
|
||||||
CumulativeGasUsed *big.Int
|
CumulativeGasUsed *big.Int
|
||||||
Bloom Bloom
|
Bloom Bloom
|
||||||
Logs []*Log
|
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, failed bool, cumulativeGasUsed *big.Int) *Receipt {
|
||||||
return &Receipt{PostState: common.CopyBytes(root), CumulativeGasUsed: new(big.Int).Set(cumulativeGasUsed)}
|
return &Receipt{PostState: common.CopyBytes(root), Failed: failed, CumulativeGasUsed: new(big.Int).Set(cumulativeGasUsed)}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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. If no post state is present, metropolis fork is assumed.
|
// into an RLP stream. If no post state is present, metropolis fork is assumed.
|
||||||
func (r *Receipt) EncodeRLP(w io.Writer) error {
|
func (r *Receipt) EncodeRLP(w io.Writer) error {
|
||||||
if r.PostState == nil {
|
if r.PostState == nil {
|
||||||
return rlp.Encode(w, &metropolisReceiptRLP{r.CumulativeGasUsed, r.Bloom, r.Logs})
|
status := receiptStatusSuccessful
|
||||||
|
if r.Failed {
|
||||||
|
status = receiptStatusFailed
|
||||||
|
}
|
||||||
|
return rlp.Encode(w, &metropolisReceiptRLP{status, r.CumulativeGasUsed, r.Bloom, r.Logs})
|
||||||
}
|
}
|
||||||
return rlp.Encode(w, &homesteadReceiptRLP{r.PostState, r.CumulativeGasUsed, r.Bloom, r.Logs})
|
return rlp.Encode(w, &homesteadReceiptRLP{r.PostState, r.CumulativeGasUsed, r.Bloom, r.Logs})
|
||||||
}
|
}
|
||||||
@ -87,29 +98,31 @@ func (r *Receipt) DecodeRLP(s *rlp.Stream) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
list, _, err := rlp.SplitList(raw)
|
content, _, err := rlp.SplitList(raw)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
items, err := rlp.CountValues(list)
|
kind, cnt, _, err := rlp.Split(content)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
// Deserialize based on the number of content items
|
// Deserialize based on the first component type.
|
||||||
switch items {
|
switch {
|
||||||
case 3:
|
case kind == rlp.Byte || kind == rlp.String && len(cnt) == 0:
|
||||||
// Metropolis receipts have 3 components
|
// The first component of metropolis receipts is Byte
|
||||||
|
// or empty String(byte with 0x00 value).
|
||||||
var metro metropolisReceiptRLP
|
var metro metropolisReceiptRLP
|
||||||
if err := rlp.DecodeBytes(raw, &metro); err != nil {
|
if err := rlp.DecodeBytes(raw, &metro); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
r.Failed = metro.Status == receiptStatusFailed
|
||||||
r.CumulativeGasUsed = metro.CumulativeGasUsed
|
r.CumulativeGasUsed = metro.CumulativeGasUsed
|
||||||
r.Bloom = metro.Bloom
|
r.Bloom = metro.Bloom
|
||||||
r.Logs = metro.Logs
|
r.Logs = metro.Logs
|
||||||
return nil
|
return nil
|
||||||
|
|
||||||
case 4:
|
case kind == rlp.String:
|
||||||
// Homestead receipts have 4 components
|
// The first component of homestead receipts is non-empty String.
|
||||||
var home homesteadReceiptRLP
|
var home homesteadReceiptRLP
|
||||||
if err := rlp.DecodeBytes(raw, &home); err != nil {
|
if err := rlp.DecodeBytes(raw, &home); err != nil {
|
||||||
return err
|
return err
|
||||||
@ -121,14 +134,14 @@ func (r *Receipt) DecodeRLP(s *rlp.Stream) error {
|
|||||||
return nil
|
return nil
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return fmt.Errorf("invalid receipt components: %v", items)
|
return fmt.Errorf("invalid first receipt component: %v", kind)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// String implements the Stringer interface.
|
// String implements the Stringer interface.
|
||||||
func (r *Receipt) String() string {
|
func (r *Receipt) String() string {
|
||||||
if r.PostState == nil {
|
if r.PostState == nil {
|
||||||
return fmt.Sprintf("receipt{cgas=%v bloom=%x logs=%v}", r.CumulativeGasUsed, r.Bloom, r.Logs)
|
return fmt.Sprintf("receipt{failed=%t cgas=%v bloom=%x logs=%v}", r.Failed, r.CumulativeGasUsed, r.Bloom, r.Logs)
|
||||||
}
|
}
|
||||||
return fmt.Sprintf("receipt{med=%x cgas=%v bloom=%x logs=%v}", r.PostState, r.CumulativeGasUsed, r.Bloom, r.Logs)
|
return fmt.Sprintf("receipt{med=%x cgas=%v bloom=%x logs=%v}", r.PostState, r.CumulativeGasUsed, r.Bloom, r.Logs)
|
||||||
}
|
}
|
||||||
@ -144,7 +157,7 @@ func (r *ReceiptForStorage) EncodeRLP(w io.Writer) error {
|
|||||||
for i, log := range r.Logs {
|
for i, log := range r.Logs {
|
||||||
logs[i] = (*LogForStorage)(log)
|
logs[i] = (*LogForStorage)(log)
|
||||||
}
|
}
|
||||||
return rlp.Encode(w, []interface{}{r.PostState, r.CumulativeGasUsed, r.Bloom, r.TxHash, r.ContractAddress, logs, r.GasUsed})
|
return rlp.Encode(w, []interface{}{r.PostState, r.Failed, r.CumulativeGasUsed, r.Bloom, r.TxHash, r.ContractAddress, logs, r.GasUsed})
|
||||||
}
|
}
|
||||||
|
|
||||||
// DecodeRLP implements rlp.Decoder, and loads both consensus and implementation
|
// DecodeRLP implements rlp.Decoder, and loads both consensus and implementation
|
||||||
@ -152,6 +165,7 @@ func (r *ReceiptForStorage) EncodeRLP(w io.Writer) error {
|
|||||||
func (r *ReceiptForStorage) DecodeRLP(s *rlp.Stream) error {
|
func (r *ReceiptForStorage) DecodeRLP(s *rlp.Stream) error {
|
||||||
var receipt struct {
|
var receipt struct {
|
||||||
PostState []byte
|
PostState []byte
|
||||||
|
Failed bool
|
||||||
CumulativeGasUsed *big.Int
|
CumulativeGasUsed *big.Int
|
||||||
Bloom Bloom
|
Bloom Bloom
|
||||||
TxHash common.Hash
|
TxHash common.Hash
|
||||||
@ -163,7 +177,7 @@ func (r *ReceiptForStorage) DecodeRLP(s *rlp.Stream) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
// Assign the consensus fields
|
// Assign the consensus fields
|
||||||
r.PostState, r.CumulativeGasUsed, r.Bloom = receipt.PostState, receipt.CumulativeGasUsed, receipt.Bloom
|
r.PostState, r.Failed, r.CumulativeGasUsed, r.Bloom = receipt.PostState, receipt.Failed, receipt.CumulativeGasUsed, receipt.Bloom
|
||||||
r.Logs = make([]*Log, len(receipt.Logs))
|
r.Logs = make([]*Log, len(receipt.Logs))
|
||||||
for i, log := range receipt.Logs {
|
for i, log := range receipt.Logs {
|
||||||
r.Logs[i] = (*Log)(log)
|
r.Logs[i] = (*Log)(log)
|
||||||
|
@ -158,7 +158,7 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas
|
|||||||
evm.Transfer(evm.StateDB, caller.Address(), to.Address(), value)
|
evm.Transfer(evm.StateDB, caller.Address(), to.Address(), value)
|
||||||
|
|
||||||
// initialise a new contract and set the code that is to be used by the
|
// initialise a new contract and set the code that is to be used by the
|
||||||
// E The contract is a scoped evmironment for this execution context
|
// E The contract is a scoped environment for this execution context
|
||||||
// only.
|
// only.
|
||||||
contract := NewContract(caller, to, value, gas)
|
contract := NewContract(caller, to, value, gas)
|
||||||
contract.SetCallCode(&addr, evm.StateDB.GetCodeHash(addr), evm.StateDB.GetCode(addr))
|
contract.SetCallCode(&addr, evm.StateDB.GetCodeHash(addr), evm.StateDB.GetCode(addr))
|
||||||
@ -351,6 +351,10 @@ func (evm *EVM) Create(caller ContractRef, code []byte, gas uint64, value *big.I
|
|||||||
contract.UseGas(contract.Gas)
|
contract.UseGas(contract.Gas)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Assign err if contract code size exceeds the max while the err is still empty.
|
||||||
|
if maxCodeSizeExceeded && err == nil {
|
||||||
|
err = errMaxCodeSizeExceeded
|
||||||
|
}
|
||||||
return ret, contractAddr, contract.Gas, err
|
return ret, contractAddr, contract.Gas, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,6 +33,7 @@ var (
|
|||||||
errWriteProtection = errors.New("evm: write protection")
|
errWriteProtection = errors.New("evm: write protection")
|
||||||
errReturnDataOutOfBounds = errors.New("evm: return data out of bounds")
|
errReturnDataOutOfBounds = errors.New("evm: return data out of bounds")
|
||||||
errExecutionReverted = errors.New("evm: execution reverted")
|
errExecutionReverted = errors.New("evm: execution reverted")
|
||||||
|
errMaxCodeSizeExceeded = errors.New("evm: max code size exceeded")
|
||||||
)
|
)
|
||||||
|
|
||||||
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) {
|
||||||
@ -619,7 +620,6 @@ func opCall(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Sta
|
|||||||
if value.Sign() != 0 {
|
if value.Sign() != 0 {
|
||||||
gas += params.CallStipend
|
gas += params.CallStipend
|
||||||
}
|
}
|
||||||
|
|
||||||
ret, returnGas, err := evm.Call(contract, address, args, gas, value)
|
ret, returnGas, err := evm.Call(contract, address, args, gas, value)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
stack.push(new(big.Int))
|
stack.push(new(big.Int))
|
||||||
|
@ -523,7 +523,8 @@ func (api *PrivateDebugAPI) TraceTransaction(ctx context.Context, txHash common.
|
|||||||
|
|
||||||
// Run the transaction with tracing enabled.
|
// Run the transaction with tracing enabled.
|
||||||
vmenv := vm.NewEVM(context, statedb, api.config, vm.Config{Debug: true, Tracer: tracer})
|
vmenv := vm.NewEVM(context, statedb, api.config, vm.Config{Debug: true, Tracer: tracer})
|
||||||
ret, gas, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(tx.Gas()))
|
// TODO utilize failed flag
|
||||||
|
ret, gas, _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(tx.Gas()))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("tracing failed: %v", err)
|
return nil, fmt.Errorf("tracing failed: %v", err)
|
||||||
}
|
}
|
||||||
@ -570,7 +571,7 @@ func (api *PrivateDebugAPI) computeTxEnv(blockHash common.Hash, txIndex int) (co
|
|||||||
|
|
||||||
vmenv := vm.NewEVM(context, statedb, api.config, vm.Config{})
|
vmenv := vm.NewEVM(context, statedb, api.config, vm.Config{})
|
||||||
gp := new(core.GasPool).AddGas(tx.Gas())
|
gp := new(core.GasPool).AddGas(tx.Gas())
|
||||||
_, _, err := core.ApplyMessage(vmenv, msg, gp)
|
_, _, _, err := core.ApplyMessage(vmenv, msg, gp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, vm.Context{}, nil, fmt.Errorf("tx %x failed: %v", tx.Hash(), err)
|
return nil, vm.Context{}, nil, fmt.Errorf("tx %x failed: %v", tx.Hash(), err)
|
||||||
}
|
}
|
||||||
|
@ -35,11 +35,11 @@ func TestMipmapUpgrade(t *testing.T) {
|
|||||||
chain, receipts := core.GenerateChain(params.TestChainConfig, genesis, db, 10, func(i int, gen *core.BlockGen) {
|
chain, receipts := core.GenerateChain(params.TestChainConfig, genesis, db, 10, func(i int, gen *core.BlockGen) {
|
||||||
switch i {
|
switch i {
|
||||||
case 1:
|
case 1:
|
||||||
receipt := types.NewReceipt(nil, new(big.Int))
|
receipt := types.NewReceipt(nil, false, new(big.Int))
|
||||||
receipt.Logs = []*types.Log{{Address: addr}}
|
receipt.Logs = []*types.Log{{Address: addr}}
|
||||||
gen.AddUncheckedReceipt(receipt)
|
gen.AddUncheckedReceipt(receipt)
|
||||||
case 2:
|
case 2:
|
||||||
receipt := types.NewReceipt(nil, new(big.Int))
|
receipt := types.NewReceipt(nil, false, new(big.Int))
|
||||||
receipt.Logs = []*types.Log{{Address: addr}}
|
receipt.Logs = []*types.Log{{Address: addr}}
|
||||||
gen.AddUncheckedReceipt(receipt)
|
gen.AddUncheckedReceipt(receipt)
|
||||||
}
|
}
|
||||||
|
@ -33,7 +33,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func makeReceipt(addr common.Address) *types.Receipt {
|
func makeReceipt(addr common.Address) *types.Receipt {
|
||||||
receipt := types.NewReceipt(nil, new(big.Int))
|
receipt := types.NewReceipt(nil, false, new(big.Int))
|
||||||
receipt.Logs = []*types.Log{
|
receipt.Logs = []*types.Log{
|
||||||
{Address: addr},
|
{Address: addr},
|
||||||
}
|
}
|
||||||
@ -145,7 +145,7 @@ func TestFilters(t *testing.T) {
|
|||||||
var receipts types.Receipts
|
var receipts types.Receipts
|
||||||
switch i {
|
switch i {
|
||||||
case 1:
|
case 1:
|
||||||
receipt := types.NewReceipt(nil, new(big.Int))
|
receipt := types.NewReceipt(nil, false, new(big.Int))
|
||||||
receipt.Logs = []*types.Log{
|
receipt.Logs = []*types.Log{
|
||||||
{
|
{
|
||||||
Address: addr,
|
Address: addr,
|
||||||
@ -155,7 +155,7 @@ func TestFilters(t *testing.T) {
|
|||||||
gen.AddUncheckedReceipt(receipt)
|
gen.AddUncheckedReceipt(receipt)
|
||||||
receipts = types.Receipts{receipt}
|
receipts = types.Receipts{receipt}
|
||||||
case 2:
|
case 2:
|
||||||
receipt := types.NewReceipt(nil, new(big.Int))
|
receipt := types.NewReceipt(nil, false, new(big.Int))
|
||||||
receipt.Logs = []*types.Log{
|
receipt.Logs = []*types.Log{
|
||||||
{
|
{
|
||||||
Address: addr,
|
Address: addr,
|
||||||
@ -165,7 +165,7 @@ func TestFilters(t *testing.T) {
|
|||||||
gen.AddUncheckedReceipt(receipt)
|
gen.AddUncheckedReceipt(receipt)
|
||||||
receipts = types.Receipts{receipt}
|
receipts = types.Receipts{receipt}
|
||||||
case 998:
|
case 998:
|
||||||
receipt := types.NewReceipt(nil, new(big.Int))
|
receipt := types.NewReceipt(nil, false, new(big.Int))
|
||||||
receipt.Logs = []*types.Log{
|
receipt.Logs = []*types.Log{
|
||||||
{
|
{
|
||||||
Address: addr,
|
Address: addr,
|
||||||
@ -175,7 +175,7 @@ func TestFilters(t *testing.T) {
|
|||||||
gen.AddUncheckedReceipt(receipt)
|
gen.AddUncheckedReceipt(receipt)
|
||||||
receipts = types.Receipts{receipt}
|
receipts = types.Receipts{receipt}
|
||||||
case 999:
|
case 999:
|
||||||
receipt := types.NewReceipt(nil, new(big.Int))
|
receipt := types.NewReceipt(nil, false, new(big.Int))
|
||||||
receipt.Logs = []*types.Log{
|
receipt.Logs = []*types.Log{
|
||||||
{
|
{
|
||||||
Address: addr,
|
Address: addr,
|
||||||
|
@ -635,7 +635,8 @@ func (s *PublicBlockChainAPI) doCall(ctx context.Context, args CallArgs, blockNr
|
|||||||
// Setup the gas pool (also for unmetered requests)
|
// Setup the gas pool (also for unmetered requests)
|
||||||
// and apply the message.
|
// and apply the message.
|
||||||
gp := new(core.GasPool).AddGas(math.MaxBig256)
|
gp := new(core.GasPool).AddGas(math.MaxBig256)
|
||||||
res, gas, err := core.ApplyMessage(evm, msg, gp)
|
// TODO utilize failed flag to help gas estimation
|
||||||
|
res, gas, _, err := core.ApplyMessage(evm, msg, gp)
|
||||||
if err := vmError(); err != nil {
|
if err := vmError(); err != nil {
|
||||||
return nil, common.Big0, err
|
return nil, common.Big0, err
|
||||||
}
|
}
|
||||||
|
@ -127,7 +127,7 @@ func odrContractCall(ctx context.Context, db ethdb.Database, config *params.Chai
|
|||||||
|
|
||||||
//vmenv := core.NewEnv(statedb, config, bc, msg, header, vm.Config{})
|
//vmenv := core.NewEnv(statedb, config, bc, msg, header, vm.Config{})
|
||||||
gp := new(core.GasPool).AddGas(math.MaxBig256)
|
gp := new(core.GasPool).AddGas(math.MaxBig256)
|
||||||
ret, _, _ := core.ApplyMessage(vmenv, msg, gp)
|
ret, _, _, _ := core.ApplyMessage(vmenv, msg, gp)
|
||||||
res = append(res, ret...)
|
res = append(res, ret...)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -138,7 +138,7 @@ func odrContractCall(ctx context.Context, db ethdb.Database, config *params.Chai
|
|||||||
context := core.NewEVMContext(msg, header, lc, nil)
|
context := core.NewEVMContext(msg, header, lc, nil)
|
||||||
vmenv := vm.NewEVM(context, state, config, vm.Config{})
|
vmenv := vm.NewEVM(context, state, config, vm.Config{})
|
||||||
gp := new(core.GasPool).AddGas(math.MaxBig256)
|
gp := new(core.GasPool).AddGas(math.MaxBig256)
|
||||||
ret, _, _ := core.ApplyMessage(vmenv, msg, gp)
|
ret, _, _, _ := core.ApplyMessage(vmenv, msg, gp)
|
||||||
if state.Error() == nil {
|
if state.Error() == nil {
|
||||||
res = append(res, ret...)
|
res = append(res, ret...)
|
||||||
}
|
}
|
||||||
|
@ -180,7 +180,7 @@ func odrContractCall(ctx context.Context, db ethdb.Database, bc *core.BlockChain
|
|||||||
context := core.NewEVMContext(msg, header, chain, nil)
|
context := core.NewEVMContext(msg, header, chain, nil)
|
||||||
vmenv := vm.NewEVM(context, st, config, vm.Config{})
|
vmenv := vm.NewEVM(context, st, config, vm.Config{})
|
||||||
gp := new(core.GasPool).AddGas(math.MaxBig256)
|
gp := new(core.GasPool).AddGas(math.MaxBig256)
|
||||||
ret, _, _ := core.ApplyMessage(vmenv, msg, gp)
|
ret, _, _, _ := core.ApplyMessage(vmenv, msg, gp)
|
||||||
res = append(res, ret...)
|
res = append(res, ret...)
|
||||||
if st.Error() != nil {
|
if st.Error() != nil {
|
||||||
return res, st.Error()
|
return res, st.Error()
|
||||||
|
@ -156,7 +156,7 @@ func (t *StateTest) Run(subtest StateSubtest, vmconfig vm.Config) error {
|
|||||||
gaspool := new(core.GasPool)
|
gaspool := new(core.GasPool)
|
||||||
gaspool.AddGas(block.GasLimit())
|
gaspool.AddGas(block.GasLimit())
|
||||||
snapshot := statedb.Snapshot()
|
snapshot := statedb.Snapshot()
|
||||||
if _, _, err := core.ApplyMessage(evm, msg, gaspool); err != nil {
|
if _, _, _, err := core.ApplyMessage(evm, msg, gaspool); err != nil {
|
||||||
statedb.RevertToSnapshot(snapshot)
|
statedb.RevertToSnapshot(snapshot)
|
||||||
}
|
}
|
||||||
if post.Logs != nil {
|
if post.Logs != nil {
|
||||||
|
Loading…
Reference in New Issue
Block a user