Skip to content

Commit

Permalink
core/miner: add tests for Goat transaction processing and payload bui…
Browse files Browse the repository at this point in the history
…lding
  • Loading branch information
ericlee42 committed Dec 20, 2024
1 parent dca388d commit e34ba0b
Showing 1 changed file with 271 additions and 0 deletions.
271 changes: 271 additions & 0 deletions miner/goat_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,271 @@
package miner

import (
"bytes"
"crypto/rand"
"crypto/sha256"
"encoding/json"
"math/big"
"os"
"testing"
"time"

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/consensus/beacon"
"github.com/ethereum/go-ethereum/consensus/misc/eip1559"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/txpool"
"github.com/ethereum/go-ethereum/core/txpool/legacypool"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/types/goattypes"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/crypto/kzg4844"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/trie"
"github.com/holiman/uint256"
)

func TestGoatWorker(t *testing.T) {
var (
db = rawdb.NewMemoryDatabase()
engine = beacon.NewFaker()
)

testKey, _ := crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
testAddr := crypto.PubkeyToAddress(testKey.PublicKey)

allocJson, err := os.ReadFile("../core/testdata/goat-genesis.json")
if err != nil {
t.Fatalf("can't read goat genesis file: %v", err)
}

var alloc types.GenesisAlloc
if err := json.Unmarshal(allocJson, &alloc); err != nil {
t.Fatalf("can't unmarshal goat genesis file: %v", err)
}

config := *params.AllGoatDebugChainConfig

alloc[testAddr] = types.Account{Balance: new(big.Int).Mul(big.NewInt(1e6), big.NewInt(params.Ether))}

const gasLimit = 21000 * 5
gspec := &core.Genesis{
Config: &config,
ExtraData: make([]byte, 33),
GasLimit: gasLimit,
BaseFee: big.NewInt(params.InitialBaseFee),
Difficulty: big.NewInt(0),
Alloc: alloc,
}
signer := types.LatestSigner(gspec.Config)

chain, err := core.NewBlockChain(db, &core.CacheConfig{TrieDirtyDisabled: true}, gspec, nil, engine, vm.Config{}, nil)
if err != nil {
t.Fatalf("core.NewBlockChain failed: %v", err)
}

gensisBlock := chain.GetBlockByNumber(0)

pool := legacypool.New(testTxPoolConfig, chain)
txpool, err := txpool.New(testTxPoolConfig.PriceLimit, chain, []txpool.SubPool{pool})
if err != nil {
t.Fatalf("txpool.New failed: %v", err)
}
backend := &testWorkerBackend{db: db, chain: chain, txPool: txpool, genesis: gspec}

goatTxs := types.Transactions{
types.NewTx(types.NewGoatTx(goattypes.BirdgeModule, goattypes.BitcoinNewBlockAction, 0, &goattypes.NewBtcBlockTx{Hash: common.BigToHash(big.NewInt(1))})),
types.NewTx(types.NewGoatTx(goattypes.BirdgeModule, goattypes.BridgeDepoitAction, 1, &goattypes.DepositTx{
Txid: common.BigToHash(big.NewInt(1)),
TxOut: 0,
Target: testAddr,
Amount: big.NewInt(1e6),
Tax: big.NewInt(1e6),
})),
}

// no goat tx in txpool
{
errs := backend.txPool.Add(goatTxs, true, true)
if len(errs) != len(goatTxs) {
t.Fatalf("Add goat tx to txpool should failed: %v", errs)
}
for _, err := range errs {
if err == nil {
t.Fatalf("Add goat tx to txpool should failed: %v", err)
}
}
}

// no 4844 txs
{
var blobSidecar types.BlobTxSidecar
var blobHashes []common.Hash
for range 2 {
var blob kzg4844.Blob
_, _ = rand.Read(blob[:])

// commitment restriction
for i := range 4096 {
blob[32*i] &= 0b0011_1111
}
blobSidecar.Blobs = append(blobSidecar.Blobs, blob)

commitment, err := kzg4844.BlobToCommitment(&blob)
if err != nil {
panic(err)
}
blobSidecar.Commitments = append(blobSidecar.Commitments, commitment)

proof, err := kzg4844.ComputeBlobProof(&blob, commitment)
if err != nil {
panic(err)
}
blobSidecar.Proofs = append(blobSidecar.Proofs, proof)

blobHashes = append(blobHashes, kzg4844.CalcBlobHashV1(sha256.New(), &commitment))
}

tx := types.NewTx(&types.BlobTx{
ChainID: uint256.MustFromBig(gspec.Config.ChainID),
Nonce: 0,
GasTipCap: uint256.NewInt(3e9),
GasFeeCap: uint256.NewInt(1e9),
Gas: 21_000,
To: testAddr,
Value: uint256.NewInt(0),
Data: nil,
BlobFeeCap: uint256.NewInt(1e9),
BlobHashes: blobHashes,
Sidecar: &blobSidecar,
})
signedTx, err := types.SignTx(tx, signer, testKey)
if err != nil {
t.Fatalf("SignTx failed: %v", err)
}
errs := backend.txPool.Add([]*types.Transaction{signedTx}, true, true)
if len(errs) != 1 || errs[0] == nil {
t.Fatalf("Add blob tx should failed: %v", errs)
}
}

baseFee := eip1559.CalcBaseFee(gspec.Config, gensisBlock.Header())
var nonce uint64
var totalFee = big.NewInt(0)
for i := 0; i < 6; i++ {
legacy := i%2 == 0
var txdata types.TxData

const gas = 21_000
if legacy {
txdata = &types.LegacyTx{
Nonce: nonce,
To: &testAddr,
Gas: gas,
GasPrice: big.NewInt(2e9),
Value: big.NewInt(0),
}
} else {
txdata = &types.DynamicFeeTx{
ChainID: new(big.Int).Set(gspec.Config.ChainID),
Nonce: nonce,
GasTipCap: big.NewInt(1e9),
GasFeeCap: big.NewInt(3e9),
Gas: gas,
To: &testAddr,
Value: big.NewInt(0),
}
}

signedTx, err := types.SignTx(types.NewTx(txdata), signer, testKey)
if err != nil {
t.Fatalf("SignTx failed: %v", err)
}

if i != 5 {
fee, err := signedTx.EffectiveGasTip(baseFee)
if err != nil {
t.Fatalf("EffectiveGasTip failed: %v", err)
}
fee.Add(fee, baseFee)
fee.Mul(fee, big.NewInt(gas))
totalFee.Add(totalFee, fee)
}

errs := backend.txPool.Add([]*types.Transaction{signedTx}, true, true)
if len(errs) != 0 && errs[0] != nil {
t.Fatalf("Add failed: %v", errs)
}
nonce++
}

miner := New(backend, Config{
GasCeil: gasLimit,
ExtraData: []byte("goat"), // test extra data
GasPrice: big.NewInt(1),
Recommit: time.Second,
}, engine)

hash := common.BigToHash(common.Big256)

timestamp := uint64(time.Now().UTC().Unix())
random := common.Hash{1}
payload, err := miner.BuildPayload(&BuildPayloadArgs{
Parent: gensisBlock.Hash(),
Timestamp: timestamp,
FeeRecipient: testAddr,
Random: random,
BeaconRoot: &hash,
GoatTxs: goatTxs,
}, false)
if err != nil {
t.Fatalf("BuildPayload failed: %v", err)
}

full := payload.ResolveFull()

expectExtra := make([]byte, 33)
expectExtra[0] = uint8(len(goatTxs))
copy(expectExtra[1:], types.DeriveSha(goatTxs, trie.NewStackTrie(nil)).Bytes())
if !bytes.Equal(full.ExecutionPayload.ExtraData, expectExtra) {
t.Fatalf("extra data not match expect: %x, got: %x", expectExtra, full.ExecutionPayload.ExtraData)
}

if full.ExecutionPayload.GasUsed != gasLimit {
t.Fatalf("gas used not match expect: %d, got: %d", gasLimit, full.ExecutionPayload.GasUsed)
}

if full.ExecutionPayload.FeeRecipient != testAddr {
t.Fatalf("fee recipient not match expect: %s, got: %s", testAddr, full.ExecutionPayload.FeeRecipient)
}

if full.ExecutionPayload.Timestamp != timestamp {
t.Fatalf("timestamp not match expect: %d, got: %d", timestamp, full.ExecutionPayload.Timestamp)
}

if full.ExecutionPayload.GasLimit != gasLimit {
t.Fatalf("gas limit not match expect: %d, got: %d", gasLimit, full.ExecutionPayload.GasLimit)
}

if full.ExecutionPayload.Random != random {
t.Fatalf("random not match expect: %x, got: %x", random, full.ExecutionPayload.Random)
}

if full.BlockValue.Cmp(totalFee) != 0 {
t.Fatalf("block value not match expect: %d, got: %d", totalFee, full.BlockValue)
}

if len(full.Requests) != 1 {
t.Fatalf("should have 1 request but got %d", len(full.Requests))
}

reward := new(big.Int).Set(totalFee)
reward.Mul(reward, big.NewInt(9800))
reward.Div(reward, big.NewInt(1e4))
request := (&goattypes.LockingRequests{Gas: []*goattypes.GasRequest{goattypes.NewGasRequest(1, reward)}}).Encode()
if !bytes.Equal(full.Requests[0], request[0]) {
t.Fatalf("request not match expect: %x, got: %x", request, full.Requests[0])
}
}

0 comments on commit e34ba0b

Please sign in to comment.