diff --git a/etherman/etherman.go b/etherman/etherman.go index 6136b19..469a17a 100644 --- a/etherman/etherman.go +++ b/etherman/etherman.go @@ -33,6 +33,7 @@ type ethereumClient interface { ethereum.ContractCaller ethereum.GasEstimator ethereum.GasPricer + ethereum.GasPricer1559 ethereum.PendingStateReader ethereum.TransactionReader ethereum.TransactionSender @@ -163,6 +164,18 @@ func (etherMan *Client) EstimateGas(ctx context.Context, from common.Address, to }) } +// EstimateGasBlobTx returns the estimated gas for the blob tx +func (etherMan *Client) EstimateGasBlobTx(ctx context.Context, from common.Address, to *common.Address, gasFeeCap *big.Int, gasTipCap *big.Int, value *big.Int, data []byte) (uint64, error) { + return etherMan.EthClient.EstimateGas(ctx, ethereum.CallMsg{ + From: from, + To: to, + GasFeeCap: gasFeeCap, + GasTipCap: gasTipCap, + Value: value, + Data: data, + }) +} + // CheckTxWasMined check if a tx was already mined func (etherMan *Client) CheckTxWasMined(ctx context.Context, txHash common.Hash) (bool, *types.Receipt, error) { receipt, err := etherMan.EthClient.TransactionReceipt(ctx, txHash) @@ -279,3 +292,15 @@ func (etherMan *Client) getBlockNumber(ctx context.Context, blockNumber rpc.Bloc } return header.Number.Uint64(), nil } + +// GetHeaderByNumber returns a block header from the current canonical chain, if number is nil the latest header is returned +func (etherMan *Client) GetHeaderByNumber(ctx context.Context, number *big.Int) (*types.Header, error) { + header, err := etherMan.EthClient.HeaderByNumber(ctx, number) + return header, err +} + +// GetSuggestGasTipCap retrieves the currently suggested gas tip cap after 1559 to allow a timely execution of a transaction +func (etherMan *Client) GetSuggestGasTipCap(ctx context.Context) (*big.Int, error) { + gasTipCap, err := etherMan.EthClient.SuggestGasTipCap(ctx) + return gasTipCap, err +} diff --git a/ethtxmanager/ethtxmanager.go b/ethtxmanager/ethtxmanager.go index 0600f63..b2abe9e 100644 --- a/ethtxmanager/ethtxmanager.go +++ b/ethtxmanager/ethtxmanager.go @@ -17,7 +17,11 @@ import ( "github.com/0xPolygonHermez/zkevm-ethtx-manager/log" "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/consensus/misc/eip4844" "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/crypto/kzg4844" + "github.com/ethereum/go-ethereum/params" + "github.com/holiman/uint256" ) const failureIntervalInSeconds = 5 @@ -126,6 +130,8 @@ func pendingL1Txs(URL string, from common.Address, httpHeaders map[string]string data := common.Hex2Bytes(tx.Data) + // TODO: handle case of blob transaction + mTx := monitoredTx{ ID: types.NewTx(&types.LegacyTx{To: &to, Nonce: nonce.Uint64(), Value: value, Data: data}).Hash(), From: common.HexToAddress(tx.From), @@ -174,7 +180,7 @@ func (c *Client) getTxNonce(ctx context.Context, from common.Address) (uint64, e } // Add a transaction to be sent and monitored -func (c *Client) Add(ctx context.Context, to *common.Address, forcedNonce *uint64, value *big.Int, data []byte) (common.Hash, error) { +func (c *Client) Add(ctx context.Context, to *common.Address, forcedNonce *uint64, value *big.Int, data []byte, sidecar *types.BlobTxSidecar) (common.Hash, error) { var nonce uint64 var err error @@ -190,19 +196,6 @@ func (c *Client) Add(ctx context.Context, to *common.Address, forcedNonce *uint6 nonce = *forcedNonce } - // get gas - gas, err := c.etherman.EstimateGas(ctx, c.from, to, value, data) - if err != nil { - err := fmt.Errorf("failed to estimate gas: %w, data: %v", err, common.Bytes2Hex(data)) - log.Error(err.Error()) - log.Debugf("failed to estimate gas for tx: from: %v, to: %v, value: %v", c.from.String(), to.String(), value.String()) - if c.cfg.ForcedGas > 0 { - gas = c.cfg.ForcedGas - } else { - return common.Hash{}, err - } - } - // get gas price gasPrice, err := c.suggestedGasPrice(ctx) if err != nil { @@ -211,13 +204,81 @@ func (c *Client) Add(ctx context.Context, to *common.Address, forcedNonce *uint6 return common.Hash{}, err } + var gas uint64 + var blobFeeCap *big.Int + var gasTipCap *big.Int + + if sidecar != nil { + // blob gas price estimation + parentHeader, err := c.etherman.GetHeaderByNumber(ctx, nil) + if err != nil { + log.Errorf("failed to get parent header: %v", err) + return common.Hash{}, err + } + + if parentHeader.ExcessBlobGas != nil && parentHeader.BlobGasUsed != nil { + parentExcessBlobGas := eip4844.CalcExcessBlobGas(*parentHeader.ExcessBlobGas, *parentHeader.BlobGasUsed) + blobFeeCap = eip4844.CalcBlobFee(parentExcessBlobGas) + } else { + log.Infof("legacy parent header no blob gas info") + blobFeeCap = eip4844.CalcBlobFee(0) + } + + gasTipCap, err = c.etherman.GetSuggestGasTipCap(ctx) + if err != nil { + log.Errorf("failed to get gas tip cap: %v", err) + return common.Hash{}, err + } + + // get gas + gas, err = c.etherman.EstimateGasBlobTx(ctx, c.from, to, gasPrice, gasTipCap, value, data) + if err != nil { + err := fmt.Errorf("failed to estimate gas blob tx: %w, data: %v", err, common.Bytes2Hex(data)) + log.Error(err.Error()) + log.Debugf("failed to estimate gas for blob tx: from: %v, to: %v, value: %v", c.from.String(), to.String(), value.String()) + return common.Hash{}, err + } + + // margin + const multiplier = 10 + gasTipCap = gasTipCap.Mul(gasTipCap, big.NewInt(multiplier)) + gasPrice = gasPrice.Mul(gasPrice, big.NewInt(multiplier)) + blobFeeCap = blobFeeCap.Mul(blobFeeCap, big.NewInt(multiplier)) + gas = gas * 12 / 10 //nolint:gomnd + } else { + // get gas + gas, err = c.etherman.EstimateGas(ctx, c.from, to, value, data) + if err != nil { + err := fmt.Errorf("failed to estimate gas: %w, data: %v", err, common.Bytes2Hex(data)) + log.Error(err.Error()) + log.Debugf("failed to estimate gas for tx: from: %v, to: %v, value: %v", c.from.String(), to.String(), value.String()) + if c.cfg.ForcedGas > 0 { + gas = c.cfg.ForcedGas + } else { + return common.Hash{}, err + } + } + } + // Calculate id - tx := types.NewTx(&types.LegacyTx{ - To: to, - Nonce: nonce, - Value: value, - Data: data, - }) + var tx *types.Transaction + if sidecar == nil { + tx = types.NewTx(&types.LegacyTx{ + To: to, + Nonce: nonce, + Value: value, + Data: data, + }) + } else { + tx = types.NewTx(&types.BlobTx{ + To: *to, + Nonce: nonce, + Value: uint256.MustFromBig(value), + Data: data, + BlobHashes: sidecar.BlobHashes(), + Sidecar: sidecar, + }) + } id := tx.Hash() @@ -226,6 +287,9 @@ func (c *Client) Add(ctx context.Context, to *common.Address, forcedNonce *uint6 ID: id, From: c.from, To: to, Nonce: nonce, Value: value, Data: data, Gas: gas, GasPrice: gasPrice, + BlobSidecar: sidecar, + BlobGas: tx.BlobGas(), + BlobGasPrice: blobFeeCap, GasTipCap: gasTipCap, Status: MonitoredTxStatusCreated, History: make(map[common.Hash]bool), } @@ -693,19 +757,9 @@ func (c *Client) shouldContinueToMonitorThisTx(ctx context.Context, receipt type // state of the blockchain func (c *Client) reviewMonitoredTx(ctx context.Context, mTx *monitoredTx, mTxLogger *log.Logger) error { mTxLogger.Debug("reviewing") - // get gas - gas, err := c.etherman.EstimateGas(ctx, mTx.From, mTx.To, mTx.Value, mTx.Data) - if err != nil { - err := fmt.Errorf("failed to estimate gas: %w", err) - mTxLogger.Errorf(err.Error()) - return err - } - - // check gas - if gas > mTx.Gas { - mTxLogger.Infof("monitored tx gas updated from %v to %v", mTx.Gas, gas) - mTx.Gas = gas - } + isBlobTx := mTx.BlobSidecar != nil + var err error + var gas uint64 // get gas price gasPrice, err := c.suggestedGasPrice(ctx) @@ -717,9 +771,63 @@ func (c *Client) reviewMonitoredTx(ctx context.Context, mTx *monitoredTx, mTxLog // check gas price if gasPrice.Cmp(mTx.GasPrice) == 1 { - mTxLogger.Infof("monitored tx gas price updated from %v to %v", mTx.GasPrice.String(), gasPrice.String()) + mTxLogger.Infof("monitored tx (blob? %t) GasPrice updated from %v to %v", isBlobTx, mTx.GasPrice.String(), gasPrice.String()) mTx.GasPrice = gasPrice } + + // get gas + if mTx.BlobSidecar != nil { + // blob gas price estimation + parentHeader, err := c.etherman.GetHeaderByNumber(ctx, nil) + if err != nil { + log.Errorf("failed to get parent header: %v", err) + return err + } + + var blobFeeCap *big.Int + if parentHeader.ExcessBlobGas != nil && parentHeader.BlobGasUsed != nil { + parentExcessBlobGas := eip4844.CalcExcessBlobGas(*parentHeader.ExcessBlobGas, *parentHeader.BlobGasUsed) + blobFeeCap = eip4844.CalcBlobFee(parentExcessBlobGas) + } else { + log.Infof("legacy parent header no blob gas info") + blobFeeCap = eip4844.CalcBlobFee(0) + } + + gasTipCap, err := c.etherman.GetSuggestGasTipCap(ctx) + if err != nil { + log.Errorf("failed to get gas tip cap: %v", err) + return err + } + + if gasTipCap.Cmp(mTx.GasTipCap) == 1 { + mTxLogger.Infof("monitored tx (blob? %t) GasTipCap updated from %v to %v", isBlobTx, mTx.GasTipCap, gasTipCap) + mTx.GasTipCap = gasTipCap + } + if blobFeeCap.Cmp(mTx.BlobGasPrice) == 1 { + mTxLogger.Infof("monitored tx (blob? %t) BlobFeeCap updated from %v to %v", isBlobTx, mTx.BlobGasPrice, blobFeeCap) + mTx.BlobGasPrice = blobFeeCap + } + + gas, err = c.etherman.EstimateGasBlobTx(ctx, mTx.From, mTx.To, mTx.GasPrice, mTx.GasTipCap, mTx.Value, mTx.Data) + if err != nil { + err := fmt.Errorf("failed to estimate gas blob tx: %w", err) + mTxLogger.Errorf(err.Error()) + return err + } + } else { + gas, err = c.etherman.EstimateGas(ctx, mTx.From, mTx.To, mTx.Value, mTx.Data) + if err != nil { + err := fmt.Errorf("failed to estimate gas: %w", err) + mTxLogger.Errorf(err.Error()) + return err + } + } + + // check gas + if gas > mTx.Gas { + mTxLogger.Infof("monitored tx (blob? %t) Gas updated from %v to %v", isBlobTx, mTx.Gas, gas) + mTx.Gas = gas + } return nil } @@ -853,6 +961,53 @@ func (c *Client) ProcessPendingMonitoredTxs(ctx context.Context, resultHandler R } } +// EncodeBlobData encodes data into blob data type +func (c *Client) EncodeBlobData(data []byte) (kzg4844.Blob, error) { + dataLen := len(data) + if dataLen > params.BlobTxFieldElementsPerBlob*(params.BlobTxBytesPerFieldElement-1) { + log.Infof("blob data longer than allowed (length: %v, limit: %v)", dataLen, params.BlobTxFieldElementsPerBlob*(params.BlobTxBytesPerFieldElement-1)) + return kzg4844.Blob{}, errors.New("blob data longer than allowed") + } + + // 1 Blob = 4096 Field elements x 32 bytes/field element = 128 KB + elemSize := params.BlobTxBytesPerFieldElement + + blob := kzg4844.Blob{} + fieldIndex := -1 + for i := 0; i < len(data); i += (elemSize - 1) { + fieldIndex++ + if fieldIndex == params.BlobTxFieldElementsPerBlob { + break + } + max := i + (elemSize - 1) + if max > len(data) { + max = len(data) + } + copy(blob[fieldIndex*elemSize+1:], data[i:max]) + } + return blob, nil +} + +// MakeBlobSidecar constructs a blob tx sidecar +func (c *Client) MakeBlobSidecar(blobs []kzg4844.Blob) *types.BlobTxSidecar { + var commitments []kzg4844.Commitment + var proofs []kzg4844.Proof + + for _, blob := range blobs { + c, _ := kzg4844.BlobToCommitment(blob) + p, _ := kzg4844.ComputeBlobProof(blob, c) + + commitments = append(commitments, c) + proofs = append(proofs, p) + } + + return &types.BlobTxSidecar{ + Blobs: blobs, + Commitments: commitments, + Proofs: proofs, + } +} + // createMonitoredTxLogger creates an instance of logger with all the important // fields already set for a monitoredTx func createMonitoredTxLogger(mTx monitoredTx) *log.Logger { diff --git a/ethtxmanager/interfaces.go b/ethtxmanager/interfaces.go index 1d88ff7..1105c3e 100644 --- a/ethtxmanager/interfaces.go +++ b/ethtxmanager/interfaces.go @@ -18,10 +18,13 @@ type ethermanInterface interface { PendingNonce(ctx context.Context, account common.Address) (uint64, error) SuggestedGasPrice(ctx context.Context) (*big.Int, error) EstimateGas(ctx context.Context, from common.Address, to *common.Address, value *big.Int, data []byte) (uint64, error) + EstimateGasBlobTx(ctx context.Context, from common.Address, to *common.Address, gasFeeCap *big.Int, gasTipCap *big.Int, value *big.Int, data []byte) (uint64, error) CheckTxWasMined(ctx context.Context, txHash common.Hash) (bool, *types.Receipt, error) SignTx(ctx context.Context, sender common.Address, tx *types.Transaction) (*types.Transaction, error) GetRevertMessage(ctx context.Context, tx *types.Transaction) (string, error) GetLatestBlockNumber(ctx context.Context) (uint64, error) + GetHeaderByNumber(ctx context.Context, number *big.Int) (*types.Header, error) + GetSuggestGasTipCap(ctx context.Context) (*big.Int, error) } type storageInterface interface { diff --git a/ethtxmanager/memstorage.go b/ethtxmanager/memstorage.go index bbf9d0f..b821fb4 100644 --- a/ethtxmanager/memstorage.go +++ b/ethtxmanager/memstorage.go @@ -25,7 +25,7 @@ func NewMemStorage(persistenceFilename string) *MemStorage { if persistenceFilename != "" { // Check if the file exists if _, err := os.Stat(persistenceFilename); os.IsNotExist(err) { - log.Warnf("Persistence file %s does not exist", persistenceFilename) + log.Infof("Persistence file %s does not exist", persistenceFilename) } else { ReadFile, err := os.ReadFile(persistenceFilename) if err != nil { diff --git a/ethtxmanager/monitoredtx.go b/ethtxmanager/monitoredtx.go index aa8d381..c7b3909 100644 --- a/ethtxmanager/monitoredtx.go +++ b/ethtxmanager/monitoredtx.go @@ -6,6 +6,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" + "github.com/holiman/uint256" ) const ( @@ -69,6 +70,18 @@ type monitoredTx struct { // tx gas price GasPrice *big.Int `mapstructure:"gasPrice"` + // blob Sidecar + BlobSidecar *types.BlobTxSidecar `mapstructure:"blobSidecar"` + + // blob Gas + BlobGas uint64 `mapstructure:"blobGas"` + + // blob gas price + BlobGasPrice *big.Int `mapstructure:"blobGasPrice"` + + // gas tip cap + GasTipCap *big.Int `mapstructure:"gasTipCap"` + // Status of this monitoring Status MonitoredTxStatus `mapstructure:"status"` @@ -91,14 +104,30 @@ type monitoredTx struct { // Tx uses the current information to build a tx func (mTx monitoredTx) Tx() *types.Transaction { - tx := types.NewTx(&types.LegacyTx{ - To: mTx.To, - Nonce: mTx.Nonce, - Value: mTx.Value, - Data: mTx.Data, - Gas: mTx.Gas + mTx.GasOffset, - GasPrice: mTx.GasPrice, - }) + var tx *types.Transaction + if mTx.BlobSidecar == nil { + tx = types.NewTx(&types.LegacyTx{ + To: mTx.To, + Nonce: mTx.Nonce, + Value: mTx.Value, + Data: mTx.Data, + Gas: mTx.Gas + mTx.GasOffset, + GasPrice: mTx.GasPrice, + }) + } else { + tx = types.NewTx(&types.BlobTx{ + To: *mTx.To, + Nonce: mTx.Nonce, + Value: uint256.MustFromBig(mTx.Value), + Data: mTx.Data, + GasFeeCap: uint256.MustFromBig(mTx.GasPrice), + GasTipCap: uint256.MustFromBig(mTx.GasTipCap), + Gas: mTx.Gas, + BlobFeeCap: uint256.MustFromBig(mTx.BlobGasPrice), + BlobHashes: mTx.BlobSidecar.BlobHashes(), + Sidecar: mTx.BlobSidecar, + }) + } return tx } diff --git a/ethtxmanager/monitoredtx_test.go b/ethtxmanager/monitoredtx_test.go index 888fcea..b0cd8ee 100644 --- a/ethtxmanager/monitoredtx_test.go +++ b/ethtxmanager/monitoredtx_test.go @@ -5,6 +5,7 @@ import ( "testing" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/crypto/kzg4844" "github.com/stretchr/testify/assert" ) @@ -36,3 +37,42 @@ func TestTx(t *testing.T) { assert.Equal(t, gas+gasOffset, tx.Gas()) assert.Equal(t, gasPrice, tx.GasPrice()) } + +func TestBlobTx(t *testing.T) { + client, _ := New(Config{}) + to := common.HexToAddress("0x2") + nonce := uint64(1) + value := big.NewInt(2) + data := []byte{} + gas := uint64(3) + gasOffset := uint64(4) + blobGas := uint64(131072) + blobGasPrice := big.NewInt(10) + + blobBytes := []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15} + blob, err := client.EncodeBlobData(blobBytes) + assert.NoError(t, err) + blobSidecar := client.MakeBlobSidecar([]kzg4844.Blob{blob}) + + mTx := monitoredTx{ + To: &to, + Nonce: nonce, + Value: value, + Data: data, + Gas: gas, + GasOffset: gasOffset, + BlobSidecar: blobSidecar, + BlobGas: blobGas, + BlobGasPrice: blobGasPrice, + } + + tx := mTx.Tx() + + assert.Equal(t, &to, tx.To()) + assert.Equal(t, nonce, tx.Nonce()) + assert.Equal(t, value, tx.Value()) + assert.Equal(t, data, tx.Data()) + assert.Equal(t, blobSidecar, tx.BlobTxSidecar()) + assert.Equal(t, blobGas, tx.BlobGas()) + assert.Equal(t, blobGasPrice, tx.BlobGasFeeCap()) +} diff --git a/go.mod b/go.mod index c7b0cfe..8b39c55 100644 --- a/go.mod +++ b/go.mod @@ -3,8 +3,9 @@ module github.com/0xPolygonHermez/zkevm-ethtx-manager go 1.21 require ( - github.com/ethereum/go-ethereum v1.13.13 + github.com/ethereum/go-ethereum v1.13.14 github.com/hermeznetwork/tracerr v0.3.2 + github.com/holiman/uint256 v1.2.4 github.com/invopop/jsonschema v0.12.0 github.com/stretchr/testify v1.9.0 go.uber.org/zap v1.27.0 @@ -33,7 +34,6 @@ require ( github.com/go-ole/go-ole v1.3.0 // indirect github.com/google/uuid v1.4.0 // indirect github.com/gorilla/websocket v1.5.1 // indirect - github.com/holiman/uint256 v1.2.4 // indirect github.com/klauspost/compress v1.17.0 // indirect github.com/logrusorgru/aurora v0.0.0-20181002194514-a7b3b318ed4e // indirect github.com/mailru/easyjson v0.7.7 // indirect diff --git a/go.sum b/go.sum index 06a95fb..d5372ac 100644 --- a/go.sum +++ b/go.sum @@ -88,8 +88,8 @@ github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7 github.com/etcd-io/bbolt v1.3.3/go.mod h1:ZF2nL25h33cCyBtcyWeZ2/I3HQOfTP+0PIEvHjkjCrw= github.com/ethereum/c-kzg-4844 v0.4.0 h1:3MS1s4JtA868KpJxroZoepdV0ZKBp3u/O5HcZ7R3nlY= github.com/ethereum/c-kzg-4844 v0.4.0/go.mod h1:VewdlzQmpT5QSrVhbBuGoCdFJkpaJlO1aQputP83wc0= -github.com/ethereum/go-ethereum v1.13.13 h1:KYn9w7pEWRI9oyZOzO94OVbctSusPByHdFDPj634jII= -github.com/ethereum/go-ethereum v1.13.13/go.mod h1:TN8ZiHrdJwSe8Cb6x+p0hs5CxhJZPbqB7hHkaUXcmIU= +github.com/ethereum/go-ethereum v1.13.14 h1:EwiY3FZP94derMCIam1iW4HFVrSgIcpsu0HwTQtm6CQ= +github.com/ethereum/go-ethereum v1.13.14/go.mod h1:TN8ZiHrdJwSe8Cb6x+p0hs5CxhJZPbqB7hHkaUXcmIU= github.com/fasthttp-contrib/websocket v0.0.0-20160511215533-1f3b11f56072/go.mod h1:duJ4Jxv5lDcvg4QuQr0oowTf7dz4/CR8NtyCooz9HL8= github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= github.com/fjl/memsize v0.0.2 h1:27txuSD9or+NZlnOWdKUxeBzTAUkWCVh+4Gf2dWFOzA= diff --git a/test/main.go b/test/main.go index f054eba..5d161f7 100644 --- a/test/main.go +++ b/test/main.go @@ -3,6 +3,7 @@ package main import ( "context" "math/big" + "math/rand" "time" "github.com/0xPolygonHermez/zkevm-ethtx-manager/config/types" @@ -10,10 +11,12 @@ import ( "github.com/0xPolygonHermez/zkevm-ethtx-manager/ethtxmanager" "github.com/0xPolygonHermez/zkevm-ethtx-manager/log" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/crypto/kzg4844" ) var ( - to1 = common.HexToAddress("0x0001") + to0 = common.HexToAddress("0x0000000000000000000000000000000000000000") + from = common.HexToAddress("0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266") ) func main() { @@ -23,18 +26,18 @@ func main() { WaitReceiptToBeGenerated: types.Duration{Duration: 10 * time.Second}, ConsolidationL1ConfirmationBlocks: 5, FinalizationL1ConfirmationBlocks: 10, - PrivateKeys: []types.KeystoreFileConfig{{Path: "test.keystore", Password: "testonly"}}, ForcedGas: 0, GasPriceMarginFactor: 1, MaxGasPriceLimit: 0, PersistenceFilename: "ethtxmanager-persistence.json", + Log: log.Config{Level: "info", Environment: "development", Outputs: []string{"stderr"}}, + PrivateKeys: []types.KeystoreFileConfig{{Path: "test.keystore", Password: "testonly"}}, Etherman: etherman.Config{ URL: "http://localhost:8545", HTTPHeaders: map[string]string{}, MultiGasProvider: false, L1ChainID: 1337, }, - Log: log.Config{Level: "info", Environment: "development", Outputs: []string{"stderr"}}, } log.Init(config.Log) log.Debug("Creating ethtxmanager") @@ -51,17 +54,18 @@ func main() { if err != nil { log.Fatalf("Error creating etherman client: %s", err) } - nonce, err := testEtherman.CurrentNonce(ctx, common.HexToAddress("0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266")) + + nonce, err := testEtherman.CurrentNonce(ctx, from) if err != nil { log.Fatalf("Error getting nonce: %s", err) } go client.Start() log.Debug("ethtxmanager started") - sendTransaction(ctx, client, nonce) + sendBlobTransaction(ctx, client, nonce) nonce++ - for i := 0; i < 10; i++ { + for i := 0; i < 0; i++ { time.Sleep(100 * time.Millisecond) sendTransaction(ctx, client, nonce) nonce++ @@ -105,7 +109,7 @@ func main() { } func sendTransaction(ctx context.Context, ethtxmanager *ethtxmanager.Client, nonce uint64) common.Hash { - id, err := ethtxmanager.Add(ctx, &to1, &nonce, big.NewInt(1), []byte{}) + id, err := ethtxmanager.Add(ctx, &to0, &nonce, big.NewInt(1), []byte{byte(rand.Intn(256)), byte(rand.Intn(256)), byte(rand.Intn(256))}, nil) if err != nil { log.Errorf("Error sending transaction: %s", err) } else { @@ -113,3 +117,23 @@ func sendTransaction(ctx context.Context, ethtxmanager *ethtxmanager.Client, non } return id } + +func sendBlobTransaction(ctx context.Context, ethtxmanager *ethtxmanager.Client, nonce uint64) common.Hash { + blobBytes := []byte{255, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, byte(rand.Intn(256)), byte(rand.Intn(256)), byte(rand.Intn(256)), byte(rand.Intn(256)), byte(rand.Intn(256))} + blob, err := ethtxmanager.EncodeBlobData(blobBytes) + if err != nil { + log.Errorf("Error encoding blob data") + return common.Hash{} + } + blobSidecar := ethtxmanager.MakeBlobSidecar([]kzg4844.Blob{blob}) + + // data := []byte{228, 103, 97, 196} // pol method + data := []byte{} + id, err := ethtxmanager.Add(ctx, &to0, &nonce, big.NewInt(0), data, blobSidecar) + if err != nil { + log.Errorf("Error sending Blob transaction: %s", err) + } else { + log.Infof("Blob Transaction sent with id %s", id) + } + return id +}