Emint tx type for eth_call and logs setup (#118)
* Implement new tx message type for eth_call and module txs and abstracted state transition, prepared db for logs * Added transaction indexing to evm keeper * Alternative count type
This commit is contained in:
parent
6ba38d6cee
commit
8bb8b40b32
120
x/evm/handler.go
120
x/evm/handler.go
@ -3,15 +3,15 @@ package evm
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/big"
|
"math/big"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/core"
|
|
||||||
"github.com/ethereum/go-ethereum/core/vm"
|
|
||||||
|
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
|
authutils "github.com/cosmos/cosmos-sdk/x/auth/client/utils"
|
||||||
emint "github.com/cosmos/ethermint/types"
|
emint "github.com/cosmos/ethermint/types"
|
||||||
"github.com/cosmos/ethermint/x/evm/types"
|
"github.com/cosmos/ethermint/x/evm/types"
|
||||||
|
|
||||||
|
tm "github.com/tendermint/tendermint/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewHandler returns a handler for Ethermint type messages.
|
// NewHandler returns a handler for Ethermint type messages.
|
||||||
@ -20,6 +20,8 @@ func NewHandler(keeper Keeper) sdk.Handler {
|
|||||||
switch msg := msg.(type) {
|
switch msg := msg.(type) {
|
||||||
case types.EthereumTxMsg:
|
case types.EthereumTxMsg:
|
||||||
return handleETHTxMsg(ctx, keeper, msg)
|
return handleETHTxMsg(ctx, keeper, msg)
|
||||||
|
case types.EmintMsg:
|
||||||
|
return handleEmintMsg(ctx, keeper, msg)
|
||||||
default:
|
default:
|
||||||
errMsg := fmt.Sprintf("Unrecognized ethermint Msg type: %v", msg.Type())
|
errMsg := fmt.Sprintf("Unrecognized ethermint Msg type: %v", msg.Type())
|
||||||
return sdk.ErrUnknownRequest(errMsg).Result()
|
return sdk.ErrUnknownRequest(errMsg).Result()
|
||||||
@ -44,82 +46,64 @@ func handleETHTxMsg(ctx sdk.Context, keeper Keeper, msg types.EthereumTxMsg) sdk
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return emint.ErrInvalidSender(err.Error()).Result()
|
return emint.ErrInvalidSender(err.Error()).Result()
|
||||||
}
|
}
|
||||||
contractCreation := msg.To() == nil
|
|
||||||
|
|
||||||
// Pay intrinsic gas
|
st := types.StateTransition{
|
||||||
// TODO: Check config for homestead enabled
|
Sender: sender,
|
||||||
cost, err := core.IntrinsicGas(msg.Data.Payload, contractCreation, true)
|
AccountNonce: msg.Data.AccountNonce,
|
||||||
|
Price: msg.Data.Price,
|
||||||
|
GasLimit: msg.Data.GasLimit,
|
||||||
|
Recipient: msg.Data.Recipient,
|
||||||
|
Amount: msg.Data.Amount,
|
||||||
|
Payload: msg.Data.Payload,
|
||||||
|
Csdb: keeper.csdb,
|
||||||
|
ChainID: intChainID,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Encode transaction by default Tx encoder
|
||||||
|
txEncoder := authutils.GetTxEncoder(types.ModuleCdc)
|
||||||
|
txBytes, err := txEncoder(msg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return emint.ErrInvalidIntrinsicGas(err.Error()).Result()
|
return sdk.ErrInternal(err.Error()).Result()
|
||||||
|
}
|
||||||
|
txHash := tm.Tx(txBytes).Hash()
|
||||||
|
|
||||||
|
// Prepare db for logs
|
||||||
|
keeper.csdb.Prepare(common.BytesToHash(txHash), common.Hash{}, keeper.txCount.get())
|
||||||
|
keeper.txCount.increment()
|
||||||
|
|
||||||
|
return st.TransitionCSDB(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
usableGas := msg.Data.GasLimit - cost
|
func handleEmintMsg(ctx sdk.Context, keeper Keeper, msg types.EmintMsg) sdk.Result {
|
||||||
|
if err := msg.ValidateBasic(); err != nil {
|
||||||
// Create context for evm
|
return err.Result()
|
||||||
context := vm.Context{
|
|
||||||
CanTransfer: core.CanTransfer,
|
|
||||||
Transfer: core.Transfer,
|
|
||||||
Origin: sender,
|
|
||||||
Coinbase: common.Address{},
|
|
||||||
BlockNumber: big.NewInt(ctx.BlockHeight()),
|
|
||||||
Time: big.NewInt(time.Now().Unix()),
|
|
||||||
Difficulty: big.NewInt(0x30000), // unused
|
|
||||||
GasLimit: ctx.GasMeter().Limit(),
|
|
||||||
GasPrice: ctx.MinGasPrices().AmountOf(emint.DenomDefault).Int,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
vmenv := vm.NewEVM(context, keeper.csdb.WithContext(ctx), types.GenerateChainConfig(intChainID), vm.Config{})
|
// parse the chainID from a string to a base-10 integer
|
||||||
|
intChainID, ok := new(big.Int).SetString(ctx.ChainID(), 10)
|
||||||
var (
|
if !ok {
|
||||||
leftOverGas uint64
|
return emint.ErrInvalidChainID(fmt.Sprintf("invalid chainID: %s", ctx.ChainID())).Result()
|
||||||
addr common.Address
|
|
||||||
vmerr error
|
|
||||||
senderRef = vm.AccountRef(sender)
|
|
||||||
)
|
|
||||||
|
|
||||||
if contractCreation {
|
|
||||||
_, addr, leftOverGas, vmerr = vmenv.Create(senderRef, msg.Data.Payload, usableGas, msg.Data.Amount)
|
|
||||||
} else {
|
|
||||||
// Increment the nonce for the next transaction
|
|
||||||
keeper.csdb.SetNonce(sender, keeper.csdb.GetNonce(sender)+1)
|
|
||||||
_, leftOverGas, vmerr = vmenv.Call(senderRef, *msg.To(), msg.Data.Payload, usableGas, msg.Data.Amount)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// handle errors
|
st := types.StateTransition{
|
||||||
if vmerr != nil {
|
Sender: common.BytesToAddress(msg.From.Bytes()),
|
||||||
return emint.ErrVMExecution(vmerr.Error()).Result()
|
AccountNonce: msg.AccountNonce,
|
||||||
|
Price: msg.Price.BigInt(),
|
||||||
|
GasLimit: msg.GasLimit,
|
||||||
|
Amount: msg.Amount.BigInt(),
|
||||||
|
Payload: msg.Payload,
|
||||||
|
Csdb: keeper.csdb,
|
||||||
|
ChainID: intChainID,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Refund remaining gas from tx (Check these values and ensure gas is being consumed correctly)
|
if msg.Recipient != nil {
|
||||||
refundGas(keeper.csdb, &leftOverGas, msg.Data.GasLimit, context.GasPrice, sender)
|
to := common.BytesToAddress(msg.Recipient.Bytes())
|
||||||
|
st.Recipient = &to
|
||||||
// add balance for the processor of the tx (determine who rewards are being processed to)
|
|
||||||
// TODO: Double check nothing needs to be done here
|
|
||||||
|
|
||||||
keeper.csdb.Finalise(true) // Change to depend on config
|
|
||||||
|
|
||||||
// TODO: Consume gas from sender
|
|
||||||
|
|
||||||
return sdk.Result{Data: addr.Bytes(), GasUsed: msg.Data.GasLimit - leftOverGas}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func refundGas(
|
// Prepare db for logs
|
||||||
st vm.StateDB, gasRemaining *uint64, initialGas uint64, gasPrice *big.Int,
|
keeper.csdb.Prepare(common.Hash{}, common.Hash{}, keeper.txCount.get()) // Cannot provide tx hash
|
||||||
from common.Address,
|
keeper.txCount.increment()
|
||||||
) {
|
|
||||||
// Apply refund counter, capped to half of the used gas.
|
|
||||||
refund := (initialGas - *gasRemaining) / 2
|
|
||||||
if refund > st.GetRefund() {
|
|
||||||
refund = st.GetRefund()
|
|
||||||
}
|
|
||||||
*gasRemaining += refund
|
|
||||||
|
|
||||||
// Return ETH for remaining gas, exchanged at the original rate.
|
return st.TransitionCSDB(ctx)
|
||||||
remaining := new(big.Int).Mul(new(big.Int).SetUint64(*gasRemaining), gasPrice)
|
|
||||||
st.AddBalance(from, remaining)
|
|
||||||
|
|
||||||
// // Also return remaining gas to the block gas counter so it is
|
|
||||||
// // available for the next transaction.
|
|
||||||
// TODO: Return gas to block gas meter?
|
|
||||||
// st.gp.AddGas(st.gas)
|
|
||||||
}
|
}
|
||||||
|
@ -23,6 +23,21 @@ type Keeper struct {
|
|||||||
csdb *types.CommitStateDB
|
csdb *types.CommitStateDB
|
||||||
cdc *codec.Codec
|
cdc *codec.Codec
|
||||||
blockKey sdk.StoreKey
|
blockKey sdk.StoreKey
|
||||||
|
txCount *count
|
||||||
|
}
|
||||||
|
|
||||||
|
type count int
|
||||||
|
|
||||||
|
func (c *count) get() int {
|
||||||
|
return (int)(*c)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *count) increment() {
|
||||||
|
*c = *c + 1
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *count) reset() {
|
||||||
|
*c = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewKeeper generates new evm module keeper
|
// NewKeeper generates new evm module keeper
|
||||||
@ -32,6 +47,7 @@ func NewKeeper(ak auth.AccountKeeper, storageKey, codeKey sdk.StoreKey,
|
|||||||
csdb: types.NewCommitStateDB(sdk.Context{}, ak, storageKey, codeKey),
|
csdb: types.NewCommitStateDB(sdk.Context{}, ak, storageKey, codeKey),
|
||||||
cdc: cdc,
|
cdc: cdc,
|
||||||
blockKey: blockKey,
|
blockKey: blockKey,
|
||||||
|
txCount: new(count),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -53,7 +69,7 @@ func (k *Keeper) GetBlockHashMapping(ctx sdk.Context, hash []byte) (height int64
|
|||||||
store := ctx.KVStore(k.blockKey)
|
store := ctx.KVStore(k.blockKey)
|
||||||
bz := store.Get(hash)
|
bz := store.Get(hash)
|
||||||
if bytes.Equal(bz, []byte{}) {
|
if bytes.Equal(bz, []byte{}) {
|
||||||
panic(fmt.Errorf("block with hash %s not found", ethcmn.Bytes2Hex(hash)))
|
panic(fmt.Errorf("block with hash %s not found", ethcmn.BytesToHash(hash)))
|
||||||
}
|
}
|
||||||
k.cdc.MustUnmarshalBinaryLengthPrefixed(bz, &height)
|
k.cdc.MustUnmarshalBinaryLengthPrefixed(bz, &height)
|
||||||
return
|
return
|
||||||
|
@ -107,6 +107,7 @@ func (am AppModule) NewQuerierHandler() sdk.Querier {
|
|||||||
func (am AppModule) BeginBlock(ctx sdk.Context, bl abci.RequestBeginBlock) {
|
func (am AppModule) BeginBlock(ctx sdk.Context, bl abci.RequestBeginBlock) {
|
||||||
// Consider removing this when using evm as module without web3 API
|
// Consider removing this when using evm as module without web3 API
|
||||||
am.keeper.SetBlockHashMapping(ctx, bl.Header.LastBlockId.GetHash(), bl.Header.GetHeight()-1)
|
am.keeper.SetBlockHashMapping(ctx, bl.Header.LastBlockId.GetHash(), bl.Header.GetHeight()-1)
|
||||||
|
am.keeper.txCount.reset()
|
||||||
}
|
}
|
||||||
|
|
||||||
// EndBlock function for module at end of block
|
// EndBlock function for module at end of block
|
||||||
|
@ -5,6 +5,7 @@ import (
|
|||||||
"github.com/cosmos/ethermint/crypto"
|
"github.com/cosmos/ethermint/crypto"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// ModuleCdc defines the codec to be used by evm module
|
||||||
var ModuleCdc = codec.New()
|
var ModuleCdc = codec.New()
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
@ -19,5 +20,6 @@ func init() {
|
|||||||
// RegisterCodec registers concrete types and interfaces on the given codec.
|
// RegisterCodec registers concrete types and interfaces on the given codec.
|
||||||
func RegisterCodec(cdc *codec.Codec) {
|
func RegisterCodec(cdc *codec.Codec) {
|
||||||
cdc.RegisterConcrete(&EthereumTxMsg{}, "ethermint/MsgEthereumTx", nil)
|
cdc.RegisterConcrete(&EthereumTxMsg{}, "ethermint/MsgEthereumTx", nil)
|
||||||
|
cdc.RegisterConcrete(&EmintMsg{}, "ethermint/MsgEmint", nil)
|
||||||
crypto.RegisterCodec(cdc)
|
crypto.RegisterCodec(cdc)
|
||||||
}
|
}
|
||||||
|
88
x/evm/types/emint_msg.go
Normal file
88
x/evm/types/emint_msg.go
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
package types
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
|
"github.com/cosmos/ethermint/types"
|
||||||
|
ethcmn "github.com/ethereum/go-ethereum/common"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
_ sdk.Msg = EmintMsg{}
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// TypeEmintMsg defines the type string of Emint message
|
||||||
|
TypeEmintMsg = "emint_tx"
|
||||||
|
)
|
||||||
|
|
||||||
|
// EmintMsg implements a cosmos equivalent structure for Ethereum transactions
|
||||||
|
type EmintMsg struct {
|
||||||
|
AccountNonce uint64 `json:"nonce"`
|
||||||
|
Price sdk.Int `json:"gasPrice"`
|
||||||
|
GasLimit uint64 `json:"gas"`
|
||||||
|
Recipient *sdk.AccAddress `json:"to" rlp:"nil"` // nil means contract creation
|
||||||
|
Amount sdk.Int `json:"value"`
|
||||||
|
Payload []byte `json:"input"`
|
||||||
|
|
||||||
|
// From address (formerly derived from signature)
|
||||||
|
From sdk.AccAddress `json:"from"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewEmintMsg returns a reference to a new Ethermint transaction
|
||||||
|
func NewEmintMsg(
|
||||||
|
nonce uint64, to *sdk.AccAddress, amount sdk.Int,
|
||||||
|
gasLimit uint64, gasPrice sdk.Int, payload []byte, from sdk.AccAddress,
|
||||||
|
) EmintMsg {
|
||||||
|
return EmintMsg{
|
||||||
|
AccountNonce: nonce,
|
||||||
|
Price: gasPrice,
|
||||||
|
GasLimit: gasLimit,
|
||||||
|
Recipient: to,
|
||||||
|
Amount: amount,
|
||||||
|
Payload: payload,
|
||||||
|
From: from,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Route should return the name of the module
|
||||||
|
func (msg EmintMsg) Route() string { return RouterKey }
|
||||||
|
|
||||||
|
// Type returns the action of the message
|
||||||
|
func (msg EmintMsg) Type() string { return TypeEmintMsg }
|
||||||
|
|
||||||
|
// GetSignBytes encodes the message for signing
|
||||||
|
func (msg EmintMsg) GetSignBytes() []byte {
|
||||||
|
return sdk.MustSortJSON(ModuleCdc.MustMarshalJSON(msg))
|
||||||
|
}
|
||||||
|
|
||||||
|
// ValidateBasic runs stateless checks on the message
|
||||||
|
func (msg EmintMsg) ValidateBasic() sdk.Error {
|
||||||
|
if msg.Price.Sign() != 1 {
|
||||||
|
return types.ErrInvalidValue(fmt.Sprintf("Price must be positive: %x", msg.Price))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Amount can be 0
|
||||||
|
if msg.Amount.Sign() == -1 {
|
||||||
|
return types.ErrInvalidValue(fmt.Sprintf("amount cannot be negative: %x", msg.Amount))
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetSigners defines whose signature is required
|
||||||
|
func (msg EmintMsg) GetSigners() []sdk.AccAddress {
|
||||||
|
return []sdk.AccAddress{msg.From}
|
||||||
|
}
|
||||||
|
|
||||||
|
// To returns the recipient address of the transaction. It returns nil if the
|
||||||
|
// transaction is a contract creation.
|
||||||
|
func (msg EmintMsg) To() *ethcmn.Address {
|
||||||
|
if msg.Recipient == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
addr := ethcmn.BytesToAddress(msg.Recipient.Bytes())
|
||||||
|
return &addr
|
||||||
|
}
|
76
x/evm/types/emint_msg_test.go
Normal file
76
x/evm/types/emint_msg_test.go
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
package types
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
"github.com/tendermint/tendermint/crypto/secp256k1"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestEmintMsg(t *testing.T) {
|
||||||
|
addr := newSdkAddress()
|
||||||
|
fromAddr := newSdkAddress()
|
||||||
|
|
||||||
|
msg := NewEmintMsg(0, &addr, sdk.NewInt(1), 100000, sdk.NewInt(2), []byte("test"), fromAddr)
|
||||||
|
require.NotNil(t, msg)
|
||||||
|
require.Equal(t, msg.Recipient, &addr)
|
||||||
|
|
||||||
|
require.Equal(t, msg.Route(), RouterKey)
|
||||||
|
require.Equal(t, msg.Type(), TypeEmintMsg)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEmintMsgValidation(t *testing.T) {
|
||||||
|
testCases := []struct {
|
||||||
|
nonce uint64
|
||||||
|
to *sdk.AccAddress
|
||||||
|
amount sdk.Int
|
||||||
|
gasLimit uint64
|
||||||
|
gasPrice sdk.Int
|
||||||
|
payload []byte
|
||||||
|
expectPass bool
|
||||||
|
from sdk.AccAddress
|
||||||
|
}{
|
||||||
|
{amount: sdk.NewInt(100), gasPrice: sdk.NewInt(100000), expectPass: true},
|
||||||
|
{amount: sdk.NewInt(0), gasPrice: sdk.NewInt(100000), expectPass: true},
|
||||||
|
{amount: sdk.NewInt(-1), gasPrice: sdk.NewInt(100000), expectPass: false},
|
||||||
|
{amount: sdk.NewInt(100), gasPrice: sdk.NewInt(-1), expectPass: false},
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, tc := range testCases {
|
||||||
|
msg := NewEmintMsg(tc.nonce, tc.to, tc.amount, tc.gasLimit, tc.gasPrice, tc.payload, tc.from)
|
||||||
|
|
||||||
|
if tc.expectPass {
|
||||||
|
require.Nil(t, msg.ValidateBasic(), "test: %v", i)
|
||||||
|
} else {
|
||||||
|
require.NotNil(t, msg.ValidateBasic(), "test: %v", i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEmintEncodingAndDecoding(t *testing.T) {
|
||||||
|
addr := newSdkAddress()
|
||||||
|
fromAddr := newSdkAddress()
|
||||||
|
|
||||||
|
msg := NewEmintMsg(0, &addr, sdk.NewInt(1), 100000, sdk.NewInt(2), []byte("test"), fromAddr)
|
||||||
|
|
||||||
|
raw, err := cdc.MarshalBinaryBare(msg)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
var msg2 EmintMsg
|
||||||
|
err = cdc.UnmarshalBinaryBare(raw, &msg2)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
require.Equal(t, msg.AccountNonce, msg2.AccountNonce)
|
||||||
|
require.Equal(t, msg.Recipient, msg2.Recipient)
|
||||||
|
require.Equal(t, msg.Amount, msg2.Amount)
|
||||||
|
require.Equal(t, msg.GasLimit, msg2.GasLimit)
|
||||||
|
require.Equal(t, msg.Price, msg2.Price)
|
||||||
|
require.Equal(t, msg.Payload, msg2.Payload)
|
||||||
|
require.Equal(t, msg.From, msg2.From)
|
||||||
|
}
|
||||||
|
|
||||||
|
func newSdkAddress() sdk.AccAddress {
|
||||||
|
tmpKey := secp256k1.GenPrivKey().PubKey()
|
||||||
|
return sdk.AccAddress(tmpKey.Address().Bytes())
|
||||||
|
}
|
99
x/evm/types/state_transition.go
Normal file
99
x/evm/types/state_transition.go
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
package types
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math/big"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/core"
|
||||||
|
"github.com/ethereum/go-ethereum/core/vm"
|
||||||
|
|
||||||
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
|
emint "github.com/cosmos/ethermint/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
// StateTransition defines data to transitionDB in evm
|
||||||
|
type StateTransition struct {
|
||||||
|
Sender common.Address
|
||||||
|
AccountNonce uint64
|
||||||
|
Price *big.Int
|
||||||
|
GasLimit uint64
|
||||||
|
Recipient *common.Address
|
||||||
|
Amount *big.Int
|
||||||
|
Payload []byte
|
||||||
|
Csdb *CommitStateDB
|
||||||
|
ChainID *big.Int
|
||||||
|
}
|
||||||
|
|
||||||
|
// TransitionCSDB performs an evm state transition from a transaction
|
||||||
|
func (st StateTransition) TransitionCSDB(ctx sdk.Context) sdk.Result {
|
||||||
|
contractCreation := st.Recipient == nil
|
||||||
|
|
||||||
|
// Create context for evm
|
||||||
|
context := vm.Context{
|
||||||
|
CanTransfer: core.CanTransfer,
|
||||||
|
Transfer: core.Transfer,
|
||||||
|
Origin: st.Sender,
|
||||||
|
Coinbase: common.Address{},
|
||||||
|
BlockNumber: big.NewInt(ctx.BlockHeight()),
|
||||||
|
Time: big.NewInt(time.Now().Unix()),
|
||||||
|
Difficulty: big.NewInt(0x30000), // unused
|
||||||
|
GasLimit: ctx.GasMeter().Limit(),
|
||||||
|
GasPrice: ctx.MinGasPrices().AmountOf(emint.DenomDefault).Int,
|
||||||
|
}
|
||||||
|
|
||||||
|
vmenv := vm.NewEVM(context, st.Csdb.WithContext(ctx), GenerateChainConfig(st.ChainID), vm.Config{})
|
||||||
|
|
||||||
|
var (
|
||||||
|
leftOverGas uint64
|
||||||
|
addr common.Address
|
||||||
|
vmerr error
|
||||||
|
senderRef = vm.AccountRef(st.Sender)
|
||||||
|
)
|
||||||
|
|
||||||
|
if contractCreation {
|
||||||
|
_, addr, leftOverGas, vmerr = vmenv.Create(senderRef, st.Payload, st.GasLimit, st.Amount)
|
||||||
|
} else {
|
||||||
|
// Increment the nonce for the next transaction
|
||||||
|
st.Csdb.SetNonce(st.Sender, st.Csdb.GetNonce(st.Sender)+1)
|
||||||
|
_, leftOverGas, vmerr = vmenv.Call(senderRef, *st.Recipient, st.Payload, st.GasLimit, st.Amount)
|
||||||
|
}
|
||||||
|
|
||||||
|
// handle errors
|
||||||
|
if vmerr != nil {
|
||||||
|
return emint.ErrVMExecution(vmerr.Error()).Result()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Refund remaining gas from tx (Check these values and ensure gas is being consumed correctly)
|
||||||
|
refundGas(st.Csdb, &leftOverGas, st.GasLimit, context.GasPrice, st.Sender)
|
||||||
|
|
||||||
|
// add balance for the processor of the tx (determine who rewards are being processed to)
|
||||||
|
// TODO: Double check nothing needs to be done here
|
||||||
|
|
||||||
|
st.Csdb.Finalise(true) // Change to depend on config
|
||||||
|
|
||||||
|
// TODO: Consume gas from sender
|
||||||
|
|
||||||
|
return sdk.Result{Data: addr.Bytes(), GasUsed: st.GasLimit - leftOverGas}
|
||||||
|
}
|
||||||
|
|
||||||
|
func refundGas(
|
||||||
|
st vm.StateDB, gasRemaining *uint64, initialGas uint64, gasPrice *big.Int,
|
||||||
|
from common.Address,
|
||||||
|
) {
|
||||||
|
// Apply refund counter, capped to half of the used gas.
|
||||||
|
refund := (initialGas - *gasRemaining) / 2
|
||||||
|
if refund > st.GetRefund() {
|
||||||
|
refund = st.GetRefund()
|
||||||
|
}
|
||||||
|
*gasRemaining += refund
|
||||||
|
|
||||||
|
// // Return ETH for remaining gas, exchanged at the original rate.
|
||||||
|
// remaining := new(big.Int).Mul(new(big.Int).SetUint64(*gasRemaining), gasPrice)
|
||||||
|
// st.AddBalance(from, remaining)
|
||||||
|
|
||||||
|
// // Also return remaining gas to the block gas counter so it is
|
||||||
|
// // available for the next transaction.
|
||||||
|
// TODO: Return gas to block gas meter?
|
||||||
|
// st.gp.AddGas(st.gas)
|
||||||
|
}
|
@ -96,6 +96,7 @@ func NewCommitStateDB(ctx sdk.Context, ak auth.AccountKeeper, storageKey, codeKe
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WithContext returns a Database with an updated sdk context
|
||||||
func (csdb *CommitStateDB) WithContext(ctx sdk.Context) *CommitStateDB {
|
func (csdb *CommitStateDB) WithContext(ctx sdk.Context) *CommitStateDB {
|
||||||
csdb.ctx = ctx
|
csdb.ctx = ctx
|
||||||
return csdb
|
return csdb
|
||||||
@ -372,7 +373,7 @@ func (csdb *CommitStateDB) Commit(deleteEmptyObjects bool) (root ethcmn.Hash, er
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Finalize finalizes the state objects (accounts) state by setting their state,
|
// Finalise finalizes the state objects (accounts) state by setting their state,
|
||||||
// removing the csdb destructed objects and clearing the journal as well as the
|
// removing the csdb destructed objects and clearing the journal as well as the
|
||||||
// refunds.
|
// refunds.
|
||||||
func (csdb *CommitStateDB) Finalise(deleteEmptyObjects bool) {
|
func (csdb *CommitStateDB) Finalise(deleteEmptyObjects bool) {
|
||||||
|
Loading…
Reference in New Issue
Block a user