Skip to content
This repository has been archived by the owner on Apr 4, 2024. It is now read-only.

Support stateful precompiled contract #1116

Closed
yihuang opened this issue Jun 6, 2022 · 7 comments
Closed

Support stateful precompiled contract #1116

yihuang opened this issue Jun 6, 2022 · 7 comments

Comments

@yihuang
Copy link
Contributor

yihuang commented Jun 6, 2022

Proposal: Support stateful precompiled contract

Current behavior:

EVM support registering precompiled smart contract, but we can't simply modify the state in it, pitfalls of doing that, basically it doesn't play well with the statedb's snapshot and revert.

Desired behavior: Make stateful precompiled smart contract possible.

Use case:

Precompiled smart contract is a powerful tool for many use cases.

Allow precompile to extend statedb in memory logic somehow.

@yihuang
Copy link
Contributor Author

yihuang commented Jun 6, 2022

type StatefulPrecompiled interface {
  PrecompiledContract
  Commit(ctx sdk.Context) error
}

type ExtStateDB interface {
  StateDB
  AppendJournalEntry(entry journalEntry)
}

type StateDB struct {
  precompiles map[Address]StatefulPrecompiled
}

func (db *StateDB) Commit(ctx sdk.Context) error {
  for _, contract := range db.precompiles {
    if err := contract.Commit(ctx); err != nil {
      return err
    }
  }
}

db := NewStateDB()
db.precompiles := {
  addr: NewExampleContract(ctx, db),
}
evm := NewEVM(db, db.precompiles)

evm.Call(...)
type ExampleContract struct {
  db StateDB
  state ExampleState
}

func NewExampleContract(ctx sdk.Context, db StateDB) *ExampleContract {
  return &ExampleContract {
    db: db,
    state: loadState(ctx),
  }
}

func (p *ExampleContract) RequiredGas(input []byte) uint64 {
  // TODO
}

func (p *ExampleContract) Run(input []byte) ([]byte, error) {
  p.db.append(revertEntry{
    p: p,
    saved: p.state,
  })
  // modify p.state in memory
}

func (p *ExampleContract) Commit(ctx sdk.Context) error {
  // write p.state into cosmos-sdk storage.
}

// implements journalEntry interface
type revertEntry struct {
  p *ExampleContract
  saved ExampleState
}

func (r revertEntry) revert(*StateDB) {
  r.p.state = r.saved
}

func (r revertEntry) dirtied() *common.Address {
  // TODO
}

@yihuang
Copy link
Contributor Author

yihuang commented Jun 7, 2022

An example bank transfer precompiled contract:

type BankTransferContract struct {
  bankKeeper BankKeeper
  cachedCtx sdk.Context
  writeCache CacheWriter
  stateDB    ExtStateDB
}

func NewBankTransferContract(ctx sdk.Context, bankKeeper BankKeeer, stateDB StateDB) *BankTransferContract {
  cachedCtx, writeCache := ctx.CacheContext()
  return &BankTransferContract{
    bankKeeper, cachedCtx, writeCache, stateDB,
  }
}

func (bc *BankTransferContract) Run(input []byte) error {
  from, to, amount := decodeInput(input);
  if err := bc.bankKeeper.Transfer(bc.cachedCtx, from, to, amount); err != nil {
    return err
  }
  bc.stateDB.AppendJournalEntry(revertBankEntry{
    bc.bankKeeper, bc.cachedCtx, from, to, amount,
  })
}

func (bc *BankContract) Commit(ctx sdk.Context) error {
  bc.writeCache()
}

type revertBankEntry struct {
  bankKeeper BankKeeper
  ctx sdk.Context
  from, to, amount
}

func (r revertBankEntry) revert(*StateDB) {
  if err := r.bankKeeper.Transfer(r.ctx, to, from, amount); err != nil {
    // invariant, should not fail.
  }
}

func (r revertBankEntry) dirtied() *common.Address {
  return nil
}

@itsdevbear
Copy link
Contributor

should look into making special stripped out go-ethereum fork specifically for ethermint.

(Think SubnetEVM)

@itsdevbear
Copy link
Contributor

(Maybe that's even the place to start)

yihuang added a commit to yihuang/ethermint that referenced this issue Jul 6, 2022
@github-actions
Copy link

github-actions bot commented Aug 9, 2022

This issue is stale because it has been open 45 days with no activity. Remove Status: Stale label or comment or this will be closed in 7 days.

@yihuang
Copy link
Contributor Author

yihuang commented Aug 9, 2022

unstale

@github-actions
Copy link

This issue is stale because it has been open 45 days with no activity. Remove Status: Stale label or comment or this will be closed in 7 days.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

2 participants