Skip to content

Commit

Permalink
evm: configurable gas limit & block keep amount (evmlight only) (fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
dessaya committed Nov 9, 2021
1 parent c551267 commit 30b3db2
Show file tree
Hide file tree
Showing 9 changed files with 99 additions and 34 deletions.
6 changes: 5 additions & 1 deletion contracts/native/evm/evmchain/impl.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,13 +43,17 @@ func initialize(ctx iscp.Sandbox) (dict.Dict, error) {
a := assert.NewAssert(ctx.Log())
genesisAlloc, err := evmtypes.DecodeGenesisAlloc(ctx.Params().MustGet(evm.FieldGenesisAlloc))
a.RequireNoError(err)

gasLimit, err := codec.DecodeUint64(ctx.Params().MustGet(evm.FieldGasLimit), evm.GasLimitDefault)
a.RequireNoError(err)

chainID, err := codec.DecodeUint16(ctx.Params().MustGet(evm.FieldChainID), evm.DefaultChainID)
a.RequireNoError(err)
emulator.InitGenesis(
int(chainID),
rawdb.NewDatabase(emulator.NewKVAdapter(evminternal.EVMStateSubrealm(ctx.State()))),
genesisAlloc,
evm.GasLimitDefault,
gasLimit,
timestamp(ctx),
)
evminternal.InitializeManagement(ctx)
Expand Down
55 changes: 42 additions & 13 deletions contracts/native/evm/evmlight/emulator/blockchaindb.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,12 @@ import (
const (
// config values:

keyChainID = "c"
// EVM chain ID
keyChainID = "c"
// Block gas limit
keyGasLimit = "g"
// Amount of blocks to keep in DB. Older blocks will be pruned every time a transaction is added
keyKeepAmount = "k"

// blocks:

Expand All @@ -38,9 +42,6 @@ const (
keyBlockIndexByTxHash = "th:i"
)

// Amount of blocks to keep in DB. Older blocks will be pruned every time a transaction is added
const keepAmount = 100

// BlockchainDB contains logic for storing a fake blockchain (more like a list of blocks),
// intended for satisfying EVM tools that depend on the concept of a block.
type BlockchainDB struct {
Expand All @@ -55,9 +56,10 @@ func (bc *BlockchainDB) Initialized() bool {
return bc.kv.MustGet(keyChainID) != nil
}

func (bc *BlockchainDB) Init(chainID uint16, gasLimit, timestamp uint64) {
func (bc *BlockchainDB) Init(chainID uint16, keepAmount int32, gasLimit, timestamp uint64) {
bc.SetChainID(chainID)
bc.SetGasLimit(gasLimit)
bc.SetKeepAmount(keepAmount)
bc.addBlock(bc.makeHeader(nil, nil, 0, timestamp), timestamp+1)
}

Expand Down Expand Up @@ -85,6 +87,18 @@ func (bc *BlockchainDB) GetGasLimit() uint64 {
return gas
}

func (bc *BlockchainDB) SetKeepAmount(keepAmount int32) {
bc.kv.Set(keyKeepAmount, codec.EncodeInt32(keepAmount))
}

func (bc *BlockchainDB) keepAmount() int32 {
gas, err := codec.DecodeInt32(bc.kv.MustGet(keyKeepAmount), -1)
if err != nil {
panic(err)
}
return gas
}

func (bc *BlockchainDB) setPendingTimestamp(timestamp uint64) {
bc.kv.Set(keyPendingTimestamp, codec.EncodeUint64(timestamp))
}
Expand Down Expand Up @@ -198,22 +212,37 @@ func (bc *BlockchainDB) MintBlock(timestamp uint64) {
}

func (bc *BlockchainDB) prune(currentNumber uint64) {
if currentNumber <= keepAmount {
keepAmount := bc.keepAmount()
if keepAmount < 0 {
// keep all blocks
return
}
forget := currentNumber - keepAmount
blockHash := bc.GetBlockHashByBlockNumber(forget)
txs := bc.getTxArray(forget)
if currentNumber <= uint64(keepAmount) {
return
}
toDelete := currentNumber - uint64(keepAmount)
// assume that all blocks prior to `toDelete` have been already deleted, so
// we only need to delete this one.
bc.deleteBlock(toDelete)
}

func (bc *BlockchainDB) deleteBlock(blockNumber uint64) {
header := bc.getHeaderGobByBlockNumber(blockNumber)
if header == nil {
// already deleted?
return
}
txs := bc.getTxArray(blockNumber)
n := txs.MustLen()
for i := uint32(0); i < n; i++ {
txHash := bc.GetTransactionByBlockNumberAndIndex(forget, i).Hash()
txHash := bc.GetTransactionByBlockNumberAndIndex(blockNumber, i).Hash()
bc.kv.Del(makeBlockNumberByTxHashKey(txHash))
bc.kv.Del(makeBlockIndexByTxHashKey(txHash))
}
txs.MustErase()
bc.getReceiptArray(forget).MustErase()
bc.kv.Del(makeBlockHeaderByBlockNumberKey(forget))
bc.kv.Del(makeBlockNumberByBlockHashKey(blockHash))
bc.getReceiptArray(blockNumber).MustErase()
bc.kv.Del(makeBlockHeaderByBlockNumberKey(blockNumber))
bc.kv.Del(makeBlockNumberByBlockHashKey(header.Hash))
}

type headerGob struct {
Expand Down
4 changes: 2 additions & 2 deletions contracts/native/evm/evmlight/emulator/emulator.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,12 +63,12 @@ func newBlockchainDB(store kv.KVStore) *BlockchainDB {
}

// Init initializes the EVM state with the provided genesis allocation parameters
func Init(store kv.KVStore, chainID uint16, gasLimit, timestamp uint64, alloc core.GenesisAlloc) {
func Init(store kv.KVStore, chainID uint16, blockKeepAmount int32, gasLimit, timestamp uint64, alloc core.GenesisAlloc) {
bdb := newBlockchainDB(store)
if bdb.Initialized() {
panic("evm state already initialized in kvstore")
}
bdb.Init(chainID, gasLimit, timestamp)
bdb.Init(chainID, blockKeepAmount, gasLimit, timestamp)

statedb := newStateDB(store)
for addr, account := range alloc {
Expand Down
10 changes: 5 additions & 5 deletions contracts/native/evm/evmlight/emulator/emulator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ func TestBlockchain(t *testing.T) {
}

db := dict.Dict{}
Init(db, evm.DefaultChainID, evm.GasLimitDefault, 0, genesisAlloc)
Init(db, evm.DefaultChainID, evm.BlockKeepAll, evm.GasLimitDefault, 0, genesisAlloc)
emu := NewEVMEmulator(db, 1, &iscpBackend{})

// some assertions
Expand Down Expand Up @@ -153,7 +153,7 @@ func TestBlockchainPersistence(t *testing.T) {
transferAmount := big.NewInt(1000)

db := dict.Dict{}
Init(db, evm.DefaultChainID, evm.GasLimitDefault, 0, genesisAlloc)
Init(db, evm.DefaultChainID, evm.BlockKeepAll, evm.GasLimitDefault, 0, genesisAlloc)

// do a transfer using one instance of EVMEmulator
func() {
Expand Down Expand Up @@ -255,7 +255,7 @@ func TestStorageContract(t *testing.T) {
}

db := dict.Dict{}
Init(db, evm.DefaultChainID, evm.GasLimitDefault, 0, genesisAlloc)
Init(db, evm.DefaultChainID, evm.BlockKeepAll, evm.GasLimitDefault, 0, genesisAlloc)
emu := NewEVMEmulator(db, 1, &iscpBackend{})

contractABI, err := abi.JSON(strings.NewReader(evmtest.StorageContractABI))
Expand Down Expand Up @@ -329,7 +329,7 @@ func TestERC20Contract(t *testing.T) {
}

db := dict.Dict{}
Init(db, evm.DefaultChainID, evm.GasLimitDefault, 0, genesisAlloc)
Init(db, evm.DefaultChainID, evm.BlockKeepAll, evm.GasLimitDefault, 0, genesisAlloc)
emu := NewEVMEmulator(db, 1, &iscpBackend{})

contractABI, err := abi.JSON(strings.NewReader(evmtest.ERC20ContractABI))
Expand Down Expand Up @@ -420,7 +420,7 @@ func initBenchmark(b *testing.B) (*EVMEmulator, []*types.Transaction, dict.Dict)
}

db := dict.Dict{}
Init(db, evm.DefaultChainID, evm.GasLimitDefault, 0, genesisAlloc)
Init(db, evm.DefaultChainID, evm.BlockKeepAll, evm.GasLimitDefault, 0, genesisAlloc)
emu := NewEVMEmulator(db, 1, &iscpBackend{})

contractABI, err := abi.JSON(strings.NewReader(evmtest.StorageContractABI))
Expand Down
9 changes: 8 additions & 1 deletion contracts/native/evm/evmlight/impl.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,12 @@ func initialize(ctx iscp.Sandbox) (dict.Dict, error) {
genesisAlloc, err := evmtypes.DecodeGenesisAlloc(ctx.Params().MustGet(evm.FieldGenesisAlloc))
a.RequireNoError(err)

gasLimit, err := codec.DecodeUint64(ctx.Params().MustGet(evm.FieldGasLimit), evm.GasLimitDefault)
a.RequireNoError(err)

blockKeepAmount, err := codec.DecodeInt32(ctx.Params().MustGet(evm.FieldBlockKeepAmount), evm.BlockKeepAmountDefault)
a.RequireNoError(err)

// add the standard ISCP contract at arbitrary address 0x1074
iscpcontract.DeployOnGenesis(genesisAlloc, ctx.ChainID())

Expand All @@ -55,7 +61,8 @@ func initialize(ctx iscp.Sandbox) (dict.Dict, error) {
emulator.Init(
evminternal.EVMStateSubrealm(ctx.State()),
chainID,
evm.GasLimitDefault, // TODO: make gas limit configurable
blockKeepAmount,
gasLimit,
timestamp(ctx),
genesisAlloc,
)
Expand Down
10 changes: 9 additions & 1 deletion contracts/native/evm/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,15 +60,23 @@ const (
FieldGasPerIota = "w"
FieldGasFee = "f"
FieldGasUsed = "gu"
FieldGasLimit = "gl"
FieldFilterQuery = "fq"
FieldBlockTime = "bt" // uint32, avg block time in seconds

// evmlight only:

FieldBlockTime = "bt" // uint32, avg block time in seconds
FieldBlockKeepAmount = "bk" // int32
)

const (
DefaultChainID = 1074 // IOTA -- get it?

DefaultGasPerIota uint64 = 1000
GasLimitDefault = uint64(15000000)

BlockKeepAll = -1
BlockKeepAmountDefault = BlockKeepAll
)

var GasPrice = big.NewInt(0)
29 changes: 20 additions & 9 deletions tools/evm/evmcli/deploy.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,16 @@ import (
)

type DeployParams struct {
evmFlavor string
ChainID int
name string
description string
alloc []string
allocBase64 string
GasPerIOTA uint64
blockTime uint32
evmFlavor string
ChainID int
name string
description string
alloc []string
allocBase64 string
GasPerIOTA uint64
GasLimit uint64
blockTime uint32
blockKeepAmount int32
}

func (d *DeployParams) InitFlags(cmd *cobra.Command) {
Expand All @@ -38,7 +40,9 @@ func (d *DeployParams) InitFlags(cmd *cobra.Command) {
cmd.Flags().StringSliceVarP(&d.alloc, "alloc", "", nil, "Genesis allocation (format: <address>:<wei>,<address>:<wei>,...)")
cmd.Flags().StringVarP(&d.allocBase64, "alloc-bytes", "", "", "Genesis allocation (base64-encoded)")
cmd.Flags().Uint64VarP(&d.GasPerIOTA, "gas-per-iota", "", evm.DefaultGasPerIota, "Gas per IOTA charged as fee")
cmd.Flags().Uint32VarP(&d.blockTime, "block-time", "", 0, "Average block time (0: disabled) (only supported by evmlight)")
cmd.Flags().Uint32VarP(&d.blockTime, "block-time", "", 0, "Average block time (0: disabled) [evmlight only]")
cmd.Flags().Uint64VarP(&d.GasLimit, "gas-limit", "", evm.GasLimitDefault, "Block gas limit")
cmd.Flags().Int32VarP(&d.blockKeepAmount, "block-keep-amount", "", evm.BlockKeepAmountDefault, "Amount of blocks to keep in DB (-1: keep all blocks) [evmlight only]")
}

func (d *DeployParams) Name() string {
Expand Down Expand Up @@ -70,6 +74,13 @@ func (d *DeployParams) BlockTime() uint32 {
return d.blockTime
}

func (d *DeployParams) BlockKeepAmount() int32 {
if d.blockKeepAmount > 0 && d.evmFlavor != "evmlight" {
log.Fatalf("block-keep-amount is only supported by evmlight flavor")
}
return d.blockKeepAmount
}

func (d *DeployParams) GetGenesis(def core.GenesisAlloc) core.GenesisAlloc {
if len(d.alloc) != 0 && d.allocBase64 != "" {
log.Fatalf("--alloc and --alloc-bytes are mutually exclusive")
Expand Down
3 changes: 3 additions & 0 deletions tools/evm/evmemulator/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ By default the server has no unlocked accounts. To send transactions, either:

func start(cmd *cobra.Command, args []string) {
blockTime := deployParams.BlockTime()
blockKeepAmount := deployParams.BlockKeepAmount()
evmFlavor := deployParams.EVMFlavor()

env := solo.New(solo.NewTestContext("evmemulator"), log.DebugFlag, log.DebugFlag).
Expand All @@ -82,6 +83,8 @@ func start(cmd *cobra.Command, args []string) {
evmtest.FaucetAddress: {Balance: evmtest.FaucetSupply},
})),
evm.FieldGasPerIota, deployParams.GasPerIOTA,
evm.FieldGasLimit, deployParams.GasLimit,
evm.FieldBlockKeepAmount, blockKeepAmount,
)
log.Check(err)

Expand Down
7 changes: 5 additions & 2 deletions tools/wasp-cli/chain/evm.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,12 @@ func initEVMDeploy(evmCmd *cobra.Command) {
Short: "Deploy the evmchain/evmlight contract (i.e. create a new EVM chain)",
Run: func(cmd *cobra.Command, args []string) {
blockTime := deployParams.BlockTime()
blockKeepAmount := deployParams.BlockKeepAmount()
deployContract(deployParams.Name(), deployParams.Description(), deployParams.EVMFlavor().ProgramHash, dict.Dict{
evm.FieldChainID: codec.EncodeUint16(uint16(deployParams.ChainID)),
evm.FieldGenesisAlloc: evmtypes.EncodeGenesisAlloc(deployParams.GetGenesis(nil)),
evm.FieldChainID: codec.EncodeUint16(uint16(deployParams.ChainID)),
evm.FieldGenesisAlloc: evmtypes.EncodeGenesisAlloc(deployParams.GetGenesis(nil)),
evm.FieldGasLimit: codec.EncodeUint64(deployParams.GasLimit),
evm.FieldBlockKeepAmount: codec.EncodeInt32(blockKeepAmount),
})
log.Printf("%s contract successfully deployed.\n", deployParams.Name())

Expand Down

0 comments on commit 30b3db2

Please sign in to comment.