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

feat: blob mode for loadtest #292

Merged
merged 6 commits into from
Jun 4, 2024
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
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
107 changes: 107 additions & 0 deletions cmd/loadtest/blob.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
package loadtest

import (
cryptorand "crypto/rand"
"crypto/sha256"
_ "embed"
"fmt"
"math/rand"

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto/kzg4844"
"github.com/ethereum/go-ethereum/params"

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

type BlobCommitment struct {
Blob kzg4844.Blob
Commitment kzg4844.Commitment
Proof kzg4844.Proof
VersionedHash common.Hash
}

// generateRandomBlobData will generate random data to be used for blob encoding
func generateRandomBlobData(size int) ([]byte, error) {
data := make([]byte, size)
n, err := cryptorand.Read(data)
if err != nil {
return nil, err
}
if n != size {
return nil, fmt.Errorf("Could not create random blob data with size %d: %v", size, err)
}
return data, nil
}

// createBlob takes in randomly generated byte slice and commits it with KZG
func createBlob(data []byte) kzg4844.Blob {
blob := kzg4844.Blob{}
fieldIndex := -1
for i := 0; i < len(data); i += 31 {
fieldIndex++
if fieldIndex == params.BlobTxFieldElementsPerBlob {
break
}
max := i + 31
if max > len(data) {
max = len(data)
}
copy(blob[fieldIndex*32+1:], data[i:max])
}
return blob
}

// generateBlobCommitment will generate the values for BlobCommitment variables
func generateBlobCommitment(data []byte) (*BlobCommitment, error) {
dataLen := len(data)
if dataLen > params.BlobTxFieldElementsPerBlob*(params.BlobTxBytesPerFieldElement-1) {
return nil, fmt.Errorf("Blob data longer than allowed (length: %v, limit: %v)", dataLen, params.BlobTxFieldElementsPerBlob*(params.BlobTxBytesPerFieldElement-1))
}
blobCommitment := BlobCommitment{
Blob: createBlob(data),
}
var err error

// Generate blob commitment
blobCommitment.Commitment, err = kzg4844.BlobToCommitment(blobCommitment.Blob)
if err != nil {
return nil, fmt.Errorf("Failed generating blob commitment: %w", err)
}

// Generate blob proof
blobCommitment.Proof, err = kzg4844.ComputeBlobProof(blobCommitment.Blob, blobCommitment.Commitment)
if err != nil {
return nil, fmt.Errorf("Failed generating blob proof: %w", err)
}

// Build versioned hash
blobCommitment.VersionedHash = sha256.Sum256(blobCommitment.Commitment[:])
blobCommitment.VersionedHash[0] = 0x01
return &blobCommitment, nil
}

// appendBlobCommitment will append the generated BlobCommitment values to blob transaction specific variables
func appendBlobCommitment(tx *types.BlobTx) error {
var err error
var blobBytes []byte
var blobRefBytes []byte
blobLen := rand.Intn((params.BlobTxFieldElementsPerBlob * (params.BlobTxBytesPerFieldElement - 1)) - len(blobBytes))
blobRefBytes, _ = generateRandomBlobData(blobLen)

if blobRefBytes == nil {
return fmt.Errorf("Unknown blob ref")
}
blobBytes = append(blobBytes, blobRefBytes...)

blobCommitment, err := generateBlobCommitment(blobBytes)
if err != nil {
return fmt.Errorf("Invalid blob: %w", err)
}

tx.BlobHashes = append(tx.BlobHashes, blobCommitment.VersionedHash)
tx.Sidecar.Blobs = append(tx.Sidecar.Blobs, blobCommitment.Blob)
tx.Sidecar.Commitments = append(tx.Sidecar.Commitments, blobCommitment.Commitment)
tx.Sidecar.Proofs = append(tx.Sidecar.Proofs, blobCommitment.Proof)
return nil
}
75 changes: 75 additions & 0 deletions cmd/loadtest/loadtest.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,17 @@ import (
"io"
"math/big"
"math/rand"

"os"
"os/signal"
"strings"
"sync"
"time"

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto/kzg4844"
"github.com/ethereum/go-ethereum/signer/core/apitypes"
"github.com/holiman/uint256"

"github.com/maticnetwork/polygon-cli/bindings/tester"
"github.com/maticnetwork/polygon-cli/bindings/tokens"
Expand All @@ -29,6 +33,7 @@ import (
ethereum "github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
ethcommon "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
ethtypes "github.com/ethereum/go-ethereum/core/types"
ethcrypto "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethclient"
Expand Down Expand Up @@ -64,6 +69,7 @@ const (
loadTestModeContractCall
loadTestModeInscription
loadTestModeUniswapV3
loadTestModeBlob

codeQualitySeed = "code code code code code code code code code code code quality"
codeQualityPrivateKey = "42b6e34dc21598a807dc19d7784c71b2a7a01f6480dc6f58258f78e539f1a1fa"
Expand Down Expand Up @@ -103,6 +109,8 @@ func characterToLoadTestMode(mode string) (loadTestMode, error) {
return loadTestModeContractCall, nil
case "inscription":
return loadTestModeInscription, nil
case "blob":
return loadTestModeBlob, nil
default:
return 0, fmt.Errorf("unrecognized load test mode: %s", mode)
}
Expand Down Expand Up @@ -637,6 +645,8 @@ func mainLoop(ctx context.Context, c *ethclient.Client, rpc *ethrpc.Client) erro
startReq, endReq, tErr = loadTestContractCall(ctx, c, myNonceValue)
case loadTestModeInscription:
startReq, endReq, tErr = loadTestInscription(ctx, c, myNonceValue)
case loadTestModeBlob:
startReq, endReq, tErr = loadTestBlob(ctx, c, myNonceValue)
default:
log.Error().Str("mode", mode.String()).Msg("We've arrived at a load test mode that we don't recognize")
}
Expand Down Expand Up @@ -1477,6 +1487,71 @@ func loadTestInscription(ctx context.Context, c *ethclient.Client, nonce uint64)
return
}

func loadTestBlob(ctx context.Context, c *ethclient.Client, nonce uint64) (t1 time.Time, t2 time.Time, err error) {
ltp := inputLoadTestParams

to := ltp.ToETHAddress
if *ltp.ToRandom {
to = getRandomAddress()
}

amount := ltp.SendAmount
chainID := new(big.Int).SetUint64(*ltp.ChainID)
privateKey := ltp.ECDSAPrivateKey

gasLimit := uint64(21000)
gasPrice, gasTipCap := getSuggestedGasPrices(ctx, c)
blobFeeCap := uint64(1000000000) // 1eth

// Initialize blobTx with blob transaction type
blobTx := ethtypes.BlobTx{
ChainID: uint256.NewInt(chainID.Uint64()),
Nonce: nonce,
GasTipCap: uint256.NewInt(gasTipCap.Uint64()),
GasFeeCap: uint256.NewInt(gasPrice.Uint64()),
BlobFeeCap: uint256.NewInt(blobFeeCap),
Gas: gasLimit,
To: *to,
Value: uint256.NewInt(amount.Uint64()),
Data: nil,
AccessList: nil,
BlobHashes: make([]common.Hash, 0),
Sidecar: &types.BlobTxSidecar{
Blobs: make([]kzg4844.Blob, 0),
Commitments: make([]kzg4844.Commitment, 0),
Proofs: make([]kzg4844.Proof, 0),
},
}
// appendBlobCommitment() will take in the blobTx struct and append values to blob transaction specific keys in the following steps:
// The function will take in blobTx with empty BlobHashses, and Blob Sidecar variables initially.
// Then generateRandomBlobData() is called to generate a byte slice with random values.
// createBlob() is called to commit the randomly generated byte slice with KZG.
// generateBlobCommitment() will do the same for the Commitment and Proof.
// Append all the blob related computed values to the blobTx struct.
err = appendBlobCommitment(&blobTx)
if err != nil {
log.Error().Err(err).Msg("Unable to parse blob")
return
}
tx := types.NewTx(&blobTx)

stx, err := types.SignTx(tx, types.LatestSignerForChainID(chainID), privateKey)
if err != nil {
log.Error().Err(err).Msg("Unable to sign transaction")
return
}

t1 = time.Now()
defer func() { t2 = time.Now() }()
if *ltp.CallOnly {
log.Error().Err(err).Msg("CallOnly not supported to blob transactions")
return
} else {
err = c.SendTransaction(ctx, stx)
}
return
}

func recordSample(goRoutineID, requestID int64, err error, start, end time.Time, nonce uint64) {
s := loadTestSample{}
s.GoRoutineID = goRoutineID
Expand Down
5 changes: 3 additions & 2 deletions cmd/loadtest/loadtestmode_string.go

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

6 changes: 3 additions & 3 deletions cmd/loadtest/uniswapv3.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import (
var (
//go:embed uniswapv3Usage.md
uniswapv3Usage string
uniswapv3LoadTestParams params
uniswapv3LoadTestParams uniswap3params
)

var uniswapV3LoadTestCmd = &cobra.Command{
Expand Down Expand Up @@ -62,15 +62,15 @@ func checkUniswapV3LoadtestFlags() error {
return nil
}

type params struct {
type uniswap3params struct {
UniswapFactoryV3, UniswapMulticall, UniswapProxyAdmin, UniswapTickLens, UniswapNFTLibDescriptor, UniswapNonfungibleTokenPositionDescriptor, UniswapUpgradeableProxy, UniswapNonfungiblePositionManager, UniswapMigrator, UniswapStaker, UniswapQuoterV2, UniswapSwapRouter, WETH9, UniswapPoolToken0, UniswapPoolToken1 *string
PoolFees *float64
SwapAmountInput *uint64
}

func init() {
// Specify subcommand flags.
params := new(params)
params := new(uniswap3params)

// Pre-deployed addresses.
params.UniswapFactoryV3 = uniswapV3LoadTestCmd.Flags().String("uniswap-factory-v3-address", "", "The address of a pre-deployed UniswapFactoryV3 contract")
Expand Down
4 changes: 2 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -130,13 +130,13 @@ require (
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
go.opencensus.io v0.24.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
golang.org/x/mod v0.14.0 // indirect
golang.org/x/mod v0.17.0 // indirect
golang.org/x/net v0.25.0 // indirect
golang.org/x/oauth2 v0.20.0 // indirect
golang.org/x/sync v0.7.0 // indirect
golang.org/x/sys v0.20.0 // indirect
golang.org/x/term v0.20.0 // indirect
golang.org/x/tools v0.16.0 // indirect
golang.org/x/tools v0.21.0 // indirect
google.golang.org/genproto v0.0.0-20240401170217-c3f982113cda // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20240513163218-0867130af1f8 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240513163218-0867130af1f8 // indirect
Expand Down
4 changes: 4 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -447,6 +447,8 @@ golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0=
golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA=
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
Expand Down Expand Up @@ -525,6 +527,8 @@ golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4f
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.16.0 h1:GO788SKMRunPIBCXiQyo2AaexLstOrVhuAL5YwsckQM=
golang.org/x/tools v0.16.0/go.mod h1:kYVVN6I1mBNoB1OX+noeBjbRk4IUEPa7JJ+TJMEooJ0=
golang.org/x/tools v0.21.0 h1:qc0xYgIbsSDt9EyWz05J5wfa7LOVW0YTLOXrqdLAWIw=
golang.org/x/tools v0.21.0/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
Expand Down