Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Datablob transactions #1

Draft
wants to merge 61 commits into
base: base
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
61 commits
Select commit Hold shift + click to select a range
92d7fa9
core/types: data blob transaction type and signer
protolambda Feb 19, 2022
562723e
accounts,signer: blob tx signer support
protolambda Feb 19, 2022
6bc5155
params/conf: add sharding fork defn
lightclient Feb 18, 2022
1d43675
all: add data hashes to evm msg
lightclient Feb 18, 2022
7c62e93
core/vm: impl DATAHASH opcode
lightclient Feb 19, 2022
e552a93
params: update gas per blob parameter to 120k
lightclient Feb 19, 2022
46a4b31
core/vm: use correct gas price for DATAHASH
lightclient Feb 19, 2022
59dc43f
core/types/data_blob_tx: grab correct r,s values from signature
lightclient Feb 19, 2022
5e37223
core/types/transaction_signing: use dank signer when needed
lightclient Feb 19, 2022
e61cf36
core/types/transaction: grab data hashes from blob txs for message
lightclient Feb 19, 2022
78187b8
core: add test for data blob txs
lightclient Feb 19, 2022
89c1e27
all: fix intrinsic gas calls in various tests
lightclient Feb 19, 2022
7a3a455
Merge pull request #2 from lightclient/simple-blob
protolambda Feb 20, 2022
204c556
work in progress, tx wrapper for blob tx pool / journal / block build…
protolambda Feb 20, 2022
cbcdcdd
core/types: implement data blob / kzg and lists ssz encoding
protolambda Feb 20, 2022
5b878b7
Import go-kzg to geth
asn-d6 Feb 19, 2022
dbfa618
Introduce dummy KZG trusted setup generator
asn-d6 Feb 19, 2022
72eced9
Introduce KZG crypto module (that implements the funcs from the mini-…
asn-d6 Feb 19, 2022
f83107f
Introduce unittests for KZG and the trusted setup
asn-d6 Feb 19, 2022
f4f1230
Add the trusted setup json data as a go file
asn-d6 Feb 19, 2022
9da9ab7
Introduce blobVerification precompile
asn-d6 Feb 19, 2022
b5c5515
Introduce blobVerification precompile test vector
asn-d6 Feb 20, 2022
b7db064
Introduce pointEvaluation precompile
asn-d6 Feb 20, 2022
5e18fbd
Introduce pointEvaluation precompile test vector (happy case)
asn-d6 Feb 20, 2022
cfb0440
eth/catalyst: GetBlobV1
protolambda Feb 20, 2022
b2d3882
go.mod,go.sum: update bls/kzg libs
protolambda Feb 20, 2022
b1dc9bc
go.mod,go.sum: update KZG lib
protolambda Feb 20, 2022
ff1a74f
core/vm,crypto/kzg,tests: update data blob kzg to use From/To Compres…
protolambda Feb 20, 2022
21836f0
core/types,crypto/kzg,signer: compute KZG commitment from raw blob data
protolambda Feb 20, 2022
e0b5cde
Update test vectors for blobVerification/pointEvaluation
asn-d6 Feb 21, 2022
f500191
Remove go-kzg dependency from kzg crypto module
asn-d6 Feb 21, 2022
96bf205
core/types: blob kzgs list ssz vector->list fix, fix blob tx encoding…
protolambda Feb 21, 2022
a38a121
core/types: test dynamic fee and blob tx binary+json encoding
protolambda Feb 21, 2022
803f31e
core: don't reinject incomplete transactions on reorg
protolambda Feb 21, 2022
c971490
core/types: encode/decode the block with transactions the minimal way
protolambda Feb 22, 2022
d19e6ee
core: consider blobs count for intrinsic gas check
protolambda Feb 25, 2022
a922276
Merge pull request #3 from asn-d6/prune-gokzg
protolambda Feb 25, 2022
587a212
eth/catalyst: implement GetBlobsBundleV1 - EIP-4844 engine api extension
protolambda Mar 12, 2022
4b0c1cb
core/types: compute kzgs for blobs list
protolambda Mar 13, 2022
e9279d9
accounts,internal/ethapi: blob transaction api arguments
protolambda Mar 13, 2022
5fa43da
signer/core/apitypes: fix wrap-data NewTx option
protolambda Mar 13, 2022
e539920
core/types: fix marshal/unmarshal text Blob type, BLSFieldElement, KZ…
protolambda Mar 13, 2022
184ba49
Add functions to extract the crypto out of Blobs/KZGCommitment/BlobKzgs
asn-d6 Mar 1, 2022
6cd16f1
Use optimized VerifyBlobs() function
asn-d6 Mar 1, 2022
dafbb4d
Add unittest for VerifyBlobs() function
asn-d6 Mar 1, 2022
0c236b0
kzg: Rename CRS variables to match the EIP naming
asn-d6 Mar 1, 2022
9f6e026
kzg: Document kzg code further
asn-d6 Mar 1, 2022
5009206
core/types: clean up blob and commitment parse methods, use ptr recei…
protolambda Mar 15, 2022
f80048e
tests: blob test update, Parse blobs/commitments, fix mutation on copy
protolambda Mar 15, 2022
d48a83e
params,core/types: remove duplicate kzg version param
protolambda Mar 15, 2022
52abcb8
core/vm,crypto/kzg,tests: remove versioned-hash func from crypto, app…
protolambda Mar 15, 2022
6e4051e
tests: benchmark kzg funcs
protolambda Mar 15, 2022
db23602
crypto/kzg: batch verification for multiple txs
protolambda Mar 17, 2022
d3ab1dd
core/types: support blobs batch-verify of multiple txs
protolambda Mar 17, 2022
6f21779
core: refactor TxPool.add and .addTxsLocked to batch-verify txs
protolambda Mar 17, 2022
bfe1f35
Update LatestSignerForChainID() to return a danksigner by default
asn-d6 Mar 21, 2022
7512b91
Transaction inner size should be computed on-demand
asn-d6 Mar 21, 2022
f87c6d6
Include versioned hashes when creating a transaction using the JSON-R…
asn-d6 Mar 22, 2022
d6fb210
Merge pull request #5 from asn-d6/eip4844-tooling
protolambda Mar 22, 2022
b58bd6e
remove blob verification precompile in favor of point evaluation prec…
protolambda Jun 7, 2022
ff35a44
fix lint
protolambda Jun 7, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions accounts/abi/bind/backends/simulated.go
Original file line number Diff line number Diff line change
Expand Up @@ -812,6 +812,7 @@ func (m callMsg) Gas() uint64 { return m.CallMsg.Gas }
func (m callMsg) Value() *big.Int { return m.CallMsg.Value }
func (m callMsg) Data() []byte { return m.CallMsg.Data }
func (m callMsg) AccessList() types.AccessList { return m.CallMsg.AccessList }
func (m callMsg) DataHashes() []common.Hash { return m.CallMsg.DataHashes }

// filterBackend implements filters.Backend to support filtering for logs without
// taking bloom-bits acceleration structures into account.
Expand Down
8 changes: 8 additions & 0 deletions accounts/external/backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,14 @@ func (api *ExternalSigner) SignTx(account accounts.Account, tx *types.Transactio
case types.DynamicFeeTxType:
args.MaxFeePerGas = (*hexutil.Big)(tx.GasFeeCap())
args.MaxPriorityFeePerGas = (*hexutil.Big)(tx.GasTipCap())
case types.BlobTxType:
hashes, _, blobs := tx.BlobWrapData()
if len(hashes) != len(blobs) {
return nil, fmt.Errorf("missing blobs data, expected %d blobs", len(hashes))
}
args.MaxFeePerGas = (*hexutil.Big)(tx.GasFeeCap())
args.MaxPriorityFeePerGas = (*hexutil.Big)(tx.GasTipCap())
args.Blobs = blobs
default:
return nil, fmt.Errorf("unsupported tx type %d", tx.Type())
}
Expand Down
2 changes: 1 addition & 1 deletion cmd/evm/internal/t8ntool/transaction.go
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ func Transaction(ctx *cli.Context) error {
r.Address = sender
}
// Check intrinsic gas
if gas, err := core.IntrinsicGas(tx.Data(), tx.AccessList(), tx.To() == nil,
if gas, err := core.IntrinsicGas(tx.Data(), tx.AccessList(), len(tx.BlobVersionedHashes()), tx.To() == nil,
chainConfig.IsHomestead(new(big.Int)), chainConfig.IsIstanbul(new(big.Int))); err != nil {
r.Error = err
results = append(results, r)
Expand Down
52 changes: 52 additions & 0 deletions cmd/kzg_dummy_setup/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// **NEVER EVER** use the output of this script in production
//
// Do a dummy KZG trusted setup ceremony for testing purposes
// Dump a json file with the results
//
// **NEVER EVER** use the output of this script in production

package main

import (
"encoding/json"
"io/ioutil"
"math"

gokzg "github.com/protolambda/go-kzg"
"github.com/protolambda/go-kzg/bls"
)

const CHUNKS_PER_BLOB = 4096

type JSONTrustedSetup struct {
SetupG1 []bls.G1Point
SetupG2 []bls.G2Point
SetupLagrange []bls.G1Point
}

func main() {
// Generate roots of unity
fs := gokzg.NewFFTSettings(uint8(math.Log2(CHUNKS_PER_BLOB)))

// Create a CRS for `s` with CHUNKS_PER_BLOB elements
s := "1927409816240961209460912649124"
kzg_setup_g1, kzg_setup_g2 := gokzg.GenerateTestingSetup(s, CHUNKS_PER_BLOB)

// Also create the lagrange CRS
kzg_setup_lagrange, err := fs.FFTG1(kzg_setup_g1[:CHUNKS_PER_BLOB], true)
if err != nil {
panic(err)
}

var trusted_setup = JSONTrustedSetup{}
trusted_setup.SetupG1 = kzg_setup_g1
trusted_setup.SetupG2 = kzg_setup_g2
trusted_setup.SetupLagrange = kzg_setup_lagrange

json_trusted_setup, _ := json.Marshal(trusted_setup)

err = ioutil.WriteFile("kzg_trusted_setup.json", json_trusted_setup, 0644)
if err != nil {
panic(err)
}
}
32 changes: 27 additions & 5 deletions core/beacon/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,13 @@ type payloadAttributesMarshaling struct {
Timestamp hexutil.Uint64
}

// BlobsBundleV1 holds the blobs of an execution payload, to be retrieved separately
type BlobsBundleV1 struct {
BlockHash common.Hash `json:"blockHash" gencodec:"required"`
KZGs []types.KZGCommitment `json:"kzgs" gencodec:"required"`
Blobs []types.Blob `json:"blobs" gencodec:"required"`
}

//go:generate go run github.com/fjl/gencodec -type ExecutableDataV1 -field-override executableDataMarshaling -out gen_ed.go

// ExecutableDataV1 structure described at https://github.com/ethereum/execution-apis/src/engine/specification.md
Expand Down Expand Up @@ -127,7 +134,7 @@ type ForkchoiceStateV1 struct {
func encodeTransactions(txs []*types.Transaction) [][]byte {
var enc = make([][]byte, len(txs))
for i, tx := range txs {
enc[i], _ = tx.MarshalBinary()
enc[i], _ = tx.MarshalMinimal()
}
return enc
}
Expand Down Expand Up @@ -182,10 +189,12 @@ func ExecutableDataToBlock(params ExecutableDataV1) (*types.Block, error) {
return block, nil
}

// BlockToExecutableData constructs the executableDataV1 structure by filling the
// BlockToWrappedExecutableData constructs the executableDataV1 structure by filling the
// fields from the given block. It assumes the given block is post-merge block.
func BlockToExecutableData(block *types.Block) *ExecutableDataV1 {
return &ExecutableDataV1{
// Additional blob contents are provided as well.
func BlockToWrappedExecutableData(block *types.Block) (*ExecutableDataV1, *BlobsBundleV1, error) {
txs := encodeTransactions(block.Transactions())
execData := &ExecutableDataV1{
BlockHash: block.Hash(),
ParentHash: block.ParentHash(),
FeeRecipient: block.Coinbase(),
Expand All @@ -197,8 +206,21 @@ func BlockToExecutableData(block *types.Block) *ExecutableDataV1 {
Timestamp: block.Time(),
ReceiptsRoot: block.ReceiptHash(),
LogsBloom: block.Bloom().Bytes(),
Transactions: encodeTransactions(block.Transactions()),
Transactions: txs,
Random: block.MixDigest(),
ExtraData: block.Extra(),
}
blobsBundle := &BlobsBundleV1{BlockHash: execData.BlockHash}
for i, tx := range block.Transactions() {
if tx.Type() == types.BlobTxType {
versionedHashes, kzgs, blobs := tx.BlobWrapData()
if len(versionedHashes) != len(kzgs) || len(versionedHashes) != len(blobs) {
return nil, nil, fmt.Errorf("tx %d in block %s has inconsistent blobs (%d) / kzgs (%d)"+
" / versioned hashes (%d)", i, execData.BlockHash, len(blobs), len(kzgs), len(versionedHashes))
}
blobsBundle.Blobs = append(blobsBundle.Blobs, blobs...)
blobsBundle.KZGs = append(blobsBundle.KZGs, kzgs...)
}
}
return execData, blobsBundle, nil
}
2 changes: 1 addition & 1 deletion core/bench_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ func genValueTx(nbytes int) func(int, *BlockGen) {
return func(i int, gen *BlockGen) {
toaddr := common.Address{}
data := make([]byte, nbytes)
gas, _ := IntrinsicGas(data, nil, false, false, false)
gas, _ := IntrinsicGas(data, nil, 0, false, false, false)
signer := types.MakeSigner(gen.config, big.NewInt(int64(i)))
gasPrice := big.NewInt(0)
if gen.header.BaseFee != nil {
Expand Down
85 changes: 85 additions & 0 deletions core/blockchain_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ import (
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/trie"
"github.com/protolambda/ztyp/view"
)

// So we can deterministically seed different blockchains
Expand Down Expand Up @@ -3704,3 +3705,87 @@ func TestEIP1559Transition(t *testing.T) {
t.Fatalf("sender balance incorrect: expected %d, got %d", expected, actual)
}
}

// TestDataBlobTxs tests the following:
//
// 1. Writes data hash from transaction to storage.
func TestDataBlobTxs(t *testing.T) {
var (
one = common.Hash{1}
two = common.Hash{2}
aa = common.HexToAddress("0x000000000000000000000000000000000000aaaa")

// Generate a canonical chain to act as the main dataset
engine = ethash.NewFaker()
db = rawdb.NewMemoryDatabase()

// A sender who makes transactions, has some funds
key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
addr1 = crypto.PubkeyToAddress(key1.PublicKey)
funds = new(big.Int).Mul(common.Big1, big.NewInt(params.Ether))
gspec = &Genesis{
Config: params.AllEthashProtocolChanges,
Alloc: GenesisAlloc{
addr1: {Balance: funds},
// The address 0xAAAA writes dataHashes[1] to storage slot 0x0.
aa: {
Code: []byte{
byte(vm.PUSH1),
byte(0x1),
byte(vm.DATAHASH),
byte(vm.PUSH1),
byte(0x0),
byte(vm.SSTORE),
},
Nonce: 0,
Balance: big.NewInt(0),
},
},
}
)

gspec.Config.BerlinBlock = common.Big0
gspec.Config.LondonBlock = common.Big0
gspec.Config.ShardingForkBlock = common.Big0
genesis := gspec.MustCommit(db)
signer := types.LatestSigner(gspec.Config)

blocks, _ := GenerateChain(gspec.Config, genesis, engine, db, 1, func(i int, b *BlockGen) {
b.SetCoinbase(common.Address{1})
msg := types.BlobTxMessage{
Nonce: 0,
Gas: 500000,
}
msg.To.Address = (*types.AddressSSZ)(&aa)
msg.ChainID.SetFromBig((*big.Int)(gspec.Config.ChainID))
msg.Nonce = view.Uint64View(0)
msg.GasFeeCap.SetFromBig(newGwei(5))
msg.GasTipCap.SetFromBig(big.NewInt(2))
msg.BlobVersionedHashes = []common.Hash{one, two}
txdata := &types.SignedBlobTx{Message: msg}

tx := types.NewTx(txdata)
tx, _ = types.SignTx(tx, signer, key1)

b.AddTx(tx)
})

diskdb := rawdb.NewMemoryDatabase()
gspec.MustCommit(diskdb)

chain, err := NewBlockChain(diskdb, nil, gspec.Config, engine, vm.Config{}, nil, nil)
if err != nil {
t.Fatalf("failed to create tester chain: %v", err)
}
if n, err := chain.InsertChain(blocks); err != nil {
t.Fatalf("block %d: failed to insert into chain: %v", n, err)
}

state, _ := chain.State()

// 1. Check that the storage slot is set to dataHashes[1].
actual := state.GetState(aa, common.Hash{0})
if actual != two {
t.Fatalf("incorrect data hash written to state (want: %s, got: %s)", two, actual)
}
}
5 changes: 3 additions & 2 deletions core/evm.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,9 @@ func NewEVMBlockContext(header *types.Header, chain ChainContext, author *common
// NewEVMTxContext creates a new transaction context for a single transaction.
func NewEVMTxContext(msg Message) vm.TxContext {
return vm.TxContext{
Origin: msg.From(),
GasPrice: new(big.Int).Set(msg.GasPrice()),
Origin: msg.From(),
GasPrice: new(big.Int).Set(msg.GasPrice()),
DataHashes: msg.DataHashes(),
}
}

Expand Down
6 changes: 4 additions & 2 deletions core/state_transition.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ type Message interface {
IsFake() bool
Data() []byte
AccessList() types.AccessList
DataHashes() []common.Hash
}

// ExecutionResult includes all output after executing given evm
Expand Down Expand Up @@ -115,7 +116,7 @@ func (result *ExecutionResult) Revert() []byte {
}

// IntrinsicGas computes the 'intrinsic gas' for a message with the given data.
func IntrinsicGas(data []byte, accessList types.AccessList, isContractCreation bool, isHomestead, isEIP2028 bool) (uint64, error) {
func IntrinsicGas(data []byte, accessList types.AccessList, blobCount int, isContractCreation bool, isHomestead, isEIP2028 bool) (uint64, error) {
// Set the starting gas for the raw transaction
var gas uint64
if isContractCreation && isHomestead {
Expand Down Expand Up @@ -152,6 +153,7 @@ func IntrinsicGas(data []byte, accessList types.AccessList, isContractCreation b
gas += uint64(len(accessList)) * params.TxAccessListAddressGas
gas += uint64(accessList.StorageKeys()) * params.TxAccessListStorageKeyGas
}
gas += uint64(blobCount) * params.BlobGas
return gas, nil
}

Expand Down Expand Up @@ -295,7 +297,7 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) {
contractCreation := msg.To() == nil

// Check clauses 4-5, subtract intrinsic gas if everything is correct
gas, err := IntrinsicGas(st.data, st.msg.AccessList(), contractCreation, homestead, istanbul)
gas, err := IntrinsicGas(st.data, st.msg.AccessList(), len(st.msg.DataHashes()), contractCreation, homestead, istanbul)
if err != nil {
return nil, err
}
Expand Down
Loading