Skip to content

Commit

Permalink
Merge pull request #10 from ironbeer/feat/contract-deploy
Browse files Browse the repository at this point in the history
Add feature to write contracts directly to state db
  • Loading branch information
ironbeer authored Sep 18, 2024
2 parents c43bbeb + dddaa43 commit d321857
Show file tree
Hide file tree
Showing 6 changed files with 107 additions and 0 deletions.
1 change: 1 addition & 0 deletions cmd/geth/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,7 @@ var (
utils.RollupComputePendingBlock,
utils.RollupHaltOnIncompatibleProtocolVersionFlag,
utils.RollupSuperchainUpgradesFlag,
utils.ContractUpdateFlag,
configFileFlag,
}, utils.NetworkFlags, utils.DatabaseFlags)

Expand Down
16 changes: 16 additions & 0 deletions cmd/utils/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -621,6 +621,13 @@ var (
Category: flags.MiscCategory,
}

// OASYS settings
ContractUpdateFlag = &cli.StringFlag{
Name: "dangerous.contractupdate",
Usage: "Path to the contract update configuration file",
Category: flags.OasysCategory,
}

// RPC settings
IPCDisabledFlag = &cli.BoolFlag{
Name: "ipcdisable",
Expand Down Expand Up @@ -1753,6 +1760,9 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) {
setRequiredBlocks(ctx, cfg)
setLes(ctx, cfg)

// Load contract update configuration file
loadContractUpdateConfig(ctx)

// Cap the cache allowance and tune the garbage collector
mem, err := gopsutil.VirtualMemory()
if err == nil {
Expand Down Expand Up @@ -2356,3 +2366,9 @@ func MakeTrieDatabase(ctx *cli.Context, disk ethdb.Database, preimage bool, read
}
return trie.NewDatabase(disk, config)
}

func loadContractUpdateConfig(ctx *cli.Context) {
if s := ctx.String(ContractUpdateFlag.Name); s != "" {
core.LoadContractUpdateConfig(s)
}
}
84 changes: 84 additions & 0 deletions core/contract_update.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
package core

import (
"encoding/json"
"fmt"
"os"
"strconv"

"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/log"
)

var (
contractUpdateConfig = make(map[uint64]GenesisAlloc)
)

/*
Load the contract update configuration file(json format).
Example:
{
"100": {
"0xfC76559Ffd6EF3b79C2A8Ab1A8179134d1e88953": {
"balance": "0",
"code": "0x73000000000000000000000000000000000000000030146080604052600080fdfea2646970667358221220184afaf8d58620cf6631ca9af99040ca3677ef4e6257938d587162f4e5edb88664736f6c63430008090033",
"storage": {
"0x0000000000000000000000000000000000000000000000000000000000000001": "0x000000000000000000000000464110713EAF4E7834D93E68a23B2aD8cCd7b28B",
"0x0000000000000000000000000000000000000000000000000000000000000002": "0x00000000000000000000000059BCA8bFfB73900261012c7c72515ecD2e529c97"
}
}
}
}
*/
func LoadContractUpdateConfig(filepath string) {
data, err := os.ReadFile(filepath)
if err != nil {
panic(fmt.Sprintf("Failed to read the contract update configuration file: %s", err.Error()))
}

parsed := make(map[string]GenesisAlloc)
if err = json.Unmarshal(data, &parsed); err != nil {
panic(fmt.Sprintf("Failed to unmarshal the contract update configuration file: %s", err.Error()))
}

for block, alloc := range parsed {
if u64block, err := strconv.ParseUint(block, 10, 64); err == nil {
contractUpdateConfig[u64block] = alloc
} else {
panic(fmt.Sprintf("Failed to parse block number: %s, err: %s", block, err.Error()))
}
}

log.Info("Loaded contract update config", "file", filepath)
}

// Update the contract directly to State. Affects the state root of the block.
func UpdateContract(state *state.StateDB, block uint64, on string) {
allocs, ok := contractUpdateConfig[block]
if !ok {
return
}

for address, alloc := range allocs {
if alloc.Code != nil {
oldHash := state.GetCodeHash(address)
state.SetCode(address, alloc.Code)
newHash := state.GetCodeHash(address)

log.Info("Updated contract code", "on", on,
"block", block, "address", address,
"old-hash", oldHash.Hex(), "new-hash", newHash.Hex())
}

for slot, value := range alloc.Storage {
oldValue := state.GetState(address, slot)
state.SetState(address, slot, value)

log.Info("Updated contract storage", "on", on,
"block", block, "address", address,
"slot", slot, "old-value", oldValue.Hex(), "new-value", value.Hex())
}
}
}
3 changes: 3 additions & 0 deletions core/state_processor.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,9 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg
if p.config.DAOForkSupport && p.config.DAOForkBlock != nil && p.config.DAOForkBlock.Cmp(block.Number()) == 0 {
misc.ApplyDAOHardFork(statedb)
}

UpdateContract(statedb, block.Number().Uint64(), "StateProcessor")

misc.EnsureCreate2Deployer(p.config, block.Time(), statedb)
var (
context = NewEVMBlockContext(header, p.bc, nil, p.config, statedb)
Expand Down
1 change: 1 addition & 0 deletions internal/flags/categories.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ const (
LoggingCategory = "LOGGING AND DEBUGGING"
MetricsCategory = "METRICS AND STATS"
MiscCategory = "MISC"
OasysCategory = "OASYS"
DeprecatedCategory = "ALIASED (deprecated)"
)

Expand Down
2 changes: 2 additions & 0 deletions miner/worker.go
Original file line number Diff line number Diff line change
Expand Up @@ -1072,6 +1072,8 @@ func (w *worker) generateWork(genParams *generateParams) *newPayloadResult {
work.gasPool = new(core.GasPool).AddGas(work.header.GasLimit)
}

core.UpdateContract(work.state, work.header.Number.Uint64(), "worker")

misc.EnsureCreate2Deployer(w.chainConfig, work.header.Time, work.state)

for _, tx := range genParams.txs {
Expand Down

0 comments on commit d321857

Please sign in to comment.