Skip to content

Commit

Permalink
all: implement goat features
Browse files Browse the repository at this point in the history
  • Loading branch information
ericlee42 committed Dec 11, 2024
1 parent 5a1d5b0 commit 2e0f469
Show file tree
Hide file tree
Showing 58 changed files with 6,544 additions and 31 deletions.
14 changes: 14 additions & 0 deletions beacon/engine/gen_blockparams.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions beacon/engine/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,15 @@ type PayloadAttributes struct {
SuggestedFeeRecipient common.Address `json:"suggestedFeeRecipient" gencodec:"required"`
Withdrawals []*types.Withdrawal `json:"withdrawals"`
BeaconRoot *common.Hash `json:"parentBeaconBlockRoot"`

GoatTxs [][]byte `json:"goatTxs,omitempty" gencodec:"optional"`
}

// JSON type overrides for PayloadAttributes.
type payloadAttributesMarshaling struct {
Timestamp hexutil.Uint64

GoatTxs []hexutil.Bytes
}

//go:generate go run github.com/fjl/gencodec -type ExecutableData -field-override executableDataMarshaling -out gen_ed.go
Expand Down
8 changes: 8 additions & 0 deletions core/block_validator.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,10 @@ func (v *BlockValidator) ValidateBody(block *types.Block) error {
return fmt.Errorf("transaction root hash mismatch (header value %x, calculated %x)", header.TxHash, hash)
}

if err := v.validateGoatBlock(block); err != nil {
return err
}

// Withdrawals are present after the Shanghai fork.
if header.WithdrawalsHash != nil {
// Withdrawals list must be present in body after Shanghai.
Expand All @@ -84,6 +88,10 @@ func (v *BlockValidator) ValidateBody(block *types.Block) error {
// Blob transactions may be present after the Cancun fork.
var blobs int
for i, tx := range block.Transactions() {
if v.config.Goat != nil {
break
}

// Count the number of blobs to validate against the header's blobGasUsed
blobs += len(tx.BlobHashes())

Expand Down
53 changes: 53 additions & 0 deletions core/block_validator_goat.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package core

import (
"errors"
"fmt"

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/trie"
)

func (v *BlockValidator) validateGoatBlock(block *types.Block) error {
if v.config.Goat == nil {
return nil
}

extra := block.Header().Extra
if len(extra) != params.GoatHeaderExtraLengthV0 {
return fmt.Errorf("no goat tx root found (block %x)", block.Number())
}

txLen, txRoot := int(extra[0]), common.BytesToHash(extra[1:])
if l := block.Transactions().Len(); l < txLen {
return fmt.Errorf("txs length(%d) is less than goat tx length %d", l, txLen)
}
if hash := types.DeriveSha(block.Transactions()[:txLen], trie.NewStackTrie(nil)); hash != txRoot {
return fmt.Errorf("goat tx root hash mismatch (header value %x, calculated %x)", txRoot, hash)
}
if len(block.Withdrawals()) > 0 {
return errors.New("withdrawals not allowed for goat-geth")
}

for i, tx := range block.Transactions() {
if i < txLen {
if !tx.IsGoatTx() {
return fmt.Errorf("transaction %d should be goat tx", i)
}
if tx.To() == nil {
return fmt.Errorf("goat tx %d should have a to address", i)
}
} else {
if tx.IsGoatTx() {
return fmt.Errorf("transaction %d should not be goat tx", i)
}
if tx.Type() == types.BlobTxType {
return fmt.Errorf("blob transaction %d is not allowed", i)
}
}
}

return nil
}
26 changes: 25 additions & 1 deletion core/chain_makers.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import (
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/trie"
"github.com/ethereum/go-ethereum/triedb"
"github.com/ethereum/go-verkle"
"github.com/holiman/uint256"
Expand Down Expand Up @@ -127,6 +128,12 @@ func (b *BlockGen) addTx(bc *BlockChain, vmConfig vm.Config, tx *types.Transacti
if b.header.BlobGasUsed != nil {
*b.header.BlobGasUsed += receipt.BlobGasUsed
}

if tx.IsGoatTx() {
b.header.Extra[0]++
hash := types.DeriveSha(types.Transactions(b.txs[:]), trie.NewStackTrie(nil))
copy(b.header.Extra[1:], hash[:])
}
}

// AddTx adds a transaction to the generated block. If no coinbase has
Expand Down Expand Up @@ -348,7 +355,19 @@ func GenerateChain(config *params.ChainConfig, parent *types.Block, engine conse
}

var requests [][]byte
if config.IsPrague(b.header.Number, b.header.Time) {
if config.Goat != nil {
var blockLogs []*types.Log
for _, r := range b.receipts {
blockLogs = append(blockLogs, r.Logs...)
}
gasRevenue := AllocateGoatGasFee(statedb, CalculateGoatGasFees(b.header, b.txs, b.receipts))
goatRequests, err := ProcessGoatRequests(b.Number().Uint64(), gasRevenue, blockLogs)
if err != nil {
panic(fmt.Sprintf("failed to parse goat logs: %v", err))
}
requests = goatRequests
}
if config.Goat == nil && config.IsPrague(b.header.Number, b.header.Time) {
requests = [][]byte{}
// EIP-6110 deposits
var blockLogs []*types.Log
Expand Down Expand Up @@ -581,6 +600,11 @@ func (cm *chainMaker) makeHeader(parent *types.Block, state *state.StateDB, engi
header.BlobGasUsed = new(uint64)
header.ParentBeaconRoot = new(common.Hash)
}

if cm.config.Goat != nil {
header.Extra = make([]byte, 1, params.GoatHeaderExtraLengthV0)
header.Extra = append(header.Extra, types.EmptyTxsHash[:]...)
}
return header
}

Expand Down
7 changes: 6 additions & 1 deletion core/genesis.go
Original file line number Diff line number Diff line change
Expand Up @@ -471,7 +471,12 @@ func (g *Genesis) toBlockWithRoot(root common.Hash) *types.Block {
head.BlobGasUsed = new(uint64)
}
}
if conf.IsPrague(num, g.Timestamp) {

if conf.Goat != nil {
head.RequestsHash = &types.EmptyRequestsHash
}

if conf.Goat == nil && conf.IsPrague(num, g.Timestamp) {
head.RequestsHash = &types.EmptyRequestsHash
}
}
Expand Down
62 changes: 62 additions & 0 deletions core/genesis_goat.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package core

import (
"embed"
"encoding/json"
"math/big"

_ "embed"

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/params"
)

//go:embed goat
var goatGenesis embed.FS

var goatEmptyExtra = common.Hex2Bytes("0056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421")

// DefaultGoatTestnet3GenesisBlock returns the Goat Testnet3 genesis block.
func DefaultGoatTestnet3GenesisBlock() *Genesis {
raw, err := goatGenesis.ReadFile("goat/testnet3.json")
if err != nil {
panic(err)
}
var alloc types.GenesisAlloc
if err := json.Unmarshal(raw, &alloc); err != nil {
panic(err)
}
return &Genesis{
Config: params.GoatTestnet3ChainConfig,
Nonce: 0,
Timestamp: 0x67345ba0,
ExtraData: goatEmptyExtra,
GasLimit: params.GoatTxGasLimit,
Difficulty: common.Big0,
Alloc: alloc,
BaseFee: big.NewInt(2028449),
}
}

// DefaultGoatMainnetGenesisBlock returns the Goat Mainnet genesis block.
func DefaultGoatMainnetGenesisBlock() *Genesis {
raw, err := goatGenesis.ReadFile("goat/mainnet.json")
if err != nil {
panic(err)
}
var alloc types.GenesisAlloc
if err := json.Unmarshal(raw, &alloc); err != nil {
panic(err)
}
return &Genesis{
Config: params.GoatMainnetChainConfig,
Nonce: 0,
Timestamp: 0x674d6b3a,
ExtraData: goatEmptyExtra,
GasLimit: params.GoatTxGasLimit,
Difficulty: common.Big0,
Alloc: alloc,
BaseFee: big.NewInt(2028449),
}
}
151 changes: 151 additions & 0 deletions core/goat/mainnet.json

Large diffs are not rendered by default.

151 changes: 151 additions & 0 deletions core/goat/testnet3.json

Large diffs are not rendered by default.

28 changes: 27 additions & 1 deletion core/state_processor.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,9 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg
blockNumber = block.Number()
allLogs []*types.Log
gp = new(GasPool).AddGas(block.GasLimit())

// gas reward to validators and goat foundation
goatGasFees = new(big.Int)
)

// Mutate the block and state according to any hard-fork specs
Expand Down Expand Up @@ -103,10 +106,29 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg
}
receipts = append(receipts, receipt)
allLogs = append(allLogs, receipt.Logs...)

if receipt.GasUsed > 0 { // non-goatTx case
tipFee := new(big.Int).SetUint64(receipt.GasUsed)
tipFee.Mul(tipFee, tx.EffectiveGasTipValue(context.BaseFee))
goatGasFees.Add(goatGasFees, tipFee)
}
}
// Read requests if Prague is enabled.
var requests [][]byte
if p.config.IsPrague(block.Number(), block.Time()) {
if p.config.Goat != nil {
burntFees := new(big.Int)
if context.BaseFee != nil && header.GasUsed > 0 {
burntFees.Mul(context.BaseFee, new(big.Int).SetUint64(header.GasUsed))
}
goatGasFees.Add(goatGasFees, burntFees)
reward := AllocateGoatGasFee(statedb, goatGasFees)
goatRequests, err := ProcessGoatRequests(block.NumberU64(), reward, allLogs)
if err != nil {
return nil, err
}
requests = goatRequests
}
if p.config.Goat == nil && p.config.IsPrague(block.Number(), block.Time()) {
requests = [][]byte{}
// EIP-6110
if err := ParseDepositLogs(&requests, allLogs, p.config); err != nil {
Expand Down Expand Up @@ -212,6 +234,10 @@ func ApplyTransaction(evm *vm.EVM, gp *GasPool, statedb *state.StateDB, header *
// ProcessBeaconBlockRoot applies the EIP-4788 system call to the beacon block root
// contract. This method is exported to be used in tests.
func ProcessBeaconBlockRoot(beaconRoot common.Hash, evm *vm.EVM) {
if evm.ChainConfig().Goat != nil { // reenable it when we have a correct beacon root
return
}

if tracer := evm.Config.Tracer; tracer != nil {
onSystemCallStart(tracer, evm.GetVMContext())
if tracer.OnSystemCallEnd != nil {
Expand Down
Loading

0 comments on commit 2e0f469

Please sign in to comment.