plugeth-statediff/blockchain.go

153 lines
3.9 KiB
Go
Raw Normal View History

package statediff
import (
"context"
"encoding/json"
"errors"
"math/big"
"sync"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/params"
plugeth "github.com/openrelayxyz/plugeth-utils/core"
"github.com/openrelayxyz/plugeth-utils/restricted"
"github.com/cerc-io/plugeth-statediff/adapt"
"github.com/cerc-io/plugeth-statediff/utils"
)
type BlockChain interface {
SubscribeChainEvent(ch chan<- core.ChainEvent) event.Subscription
CurrentBlock() *types.Header
GetBlockByHash(hash common.Hash) *types.Block
GetBlockByNumber(number uint64) *types.Block
GetReceiptsByHash(hash common.Hash) types.Receipts
GetTd(hash common.Hash, number uint64) *big.Int
// TODO LockTrie is never used
// UnlockTrie(root core.Hash)
StateCache() adapt.StateView
}
2023-06-20 17:19:58 +00:00
// CodeStore stores contract code hashes to data in a synchronized map
type CodeStore struct {
code map[plugeth.Hash][]byte
codeMtx sync.RWMutex
}
2023-06-20 17:19:58 +00:00
// pluginBlockChain adapts the plugeth Backend to the blockChain interface
type pluginBlockChain struct {
restricted.Backend
ctx context.Context
code *CodeStore
}
var _ BlockChain = (*pluginBlockChain)(nil)
2023-06-20 17:19:58 +00:00
func NewPluginBlockChain(backend restricted.Backend, code *CodeStore) BlockChain {
return &pluginBlockChain{
Backend: backend,
ctx: context.Background(),
2023-06-20 17:19:58 +00:00
code: code,
}
}
2023-06-20 17:19:58 +00:00
func (b *pluginBlockChain) SubscribeChainEvent(ch chan<- core.ChainEvent) event.Subscription {
bufferChan := make(chan plugeth.ChainEvent, chainEventChanSize)
sub := b.Backend.SubscribeChainEvent(bufferChan)
go func() {
for event := range bufferChan {
block := utils.MustDecode[types.Block](event.Block)
// TODO: apparently we ignore the logs
// logs := utils.MustDecode[types.Log](chainEvent.Logs)
ch <- core.ChainEvent{
Block: block,
Hash: common.Hash(event.Hash),
}
}
}()
return sub
}
2023-06-20 17:19:58 +00:00
func (b *pluginBlockChain) CurrentBlock() *types.Header {
buf := b.Backend.CurrentBlock()
return utils.MustDecode[types.Header](buf)
}
2023-06-20 17:19:58 +00:00
func (b *pluginBlockChain) GetBlockByHash(hash common.Hash) *types.Block {
buf, err := b.Backend.BlockByHash(b.ctx, plugeth.Hash(hash))
if err != nil {
panic(err)
}
return utils.MustDecode[types.Block](buf)
}
2023-06-20 17:19:58 +00:00
func (b *pluginBlockChain) GetBlockByNumber(number uint64) *types.Block {
buf, err := b.Backend.BlockByNumber(b.ctx, int64(number))
if err != nil {
panic(err)
}
return utils.MustDecode[types.Block](buf)
}
2023-06-20 17:19:58 +00:00
func (b *pluginBlockChain) GetReceiptsByHash(hash common.Hash) types.Receipts {
buf, err := b.Backend.GetReceipts(b.ctx, plugeth.Hash(hash))
if err != nil {
panic(err)
}
var receipts types.Receipts
err = json.Unmarshal(buf, &receipts)
if err != nil {
panic(err)
}
return receipts
}
2023-06-20 17:19:58 +00:00
func (b *pluginBlockChain) GetTd(hash common.Hash, number uint64) *big.Int {
return b.Backend.GetTd(b.ctx, plugeth.Hash(hash))
}
2023-06-20 17:19:58 +00:00
func (b *pluginBlockChain) StateCache() adapt.StateView {
return &pluginStateView{backend: b}
}
2023-06-20 17:19:58 +00:00
func (b *pluginBlockChain) ChainConfig() *params.ChainConfig {
return adapt.ChainConfig(b.Backend.ChainConfig())
}
// exposes a StateView from a combination of plugeth's core Backend and cached contract code
type pluginStateView struct {
2023-06-20 17:19:58 +00:00
backend *pluginBlockChain
}
func (p *pluginStateView) OpenTrie(root common.Hash) (adapt.StateTrie, error) {
t, err := p.backend.GetTrie(plugeth.Hash(root))
if err != nil {
return nil, err
}
return adapt.NewStateTrie(t), nil
}
func (p *pluginStateView) ContractCode(hash common.Hash) ([]byte, error) {
2023-06-20 17:19:58 +00:00
return p.backend.code.Get(plugeth.Hash(hash))
}
2023-06-20 17:19:58 +00:00
func (b *CodeStore) Get(hash plugeth.Hash) ([]byte, error) {
b.codeMtx.RLock()
defer b.codeMtx.RUnlock()
code, has := b.code[hash]
if !has {
return nil, errors.New("code not found")
}
return []byte(string(code)), nil
}
func (b *CodeStore) Set(hash plugeth.Hash, code []byte) {
b.codeMtx.Lock()
defer b.codeMtx.Unlock()
b.code[hash] = code
}