From 59e08d3b66b13c8ebbd1fb608c53183f3c95e3b2 Mon Sep 17 00:00:00 2001 From: Vitaly Drogan Date: Mon, 11 Nov 2024 21:25:17 +0100 Subject: [PATCH] test-tx-sender --- Makefile | 1 + cmd/test-tx-sender/main.go | 204 +++++++++++++++++++++++++++++++++++++ go.sum | 2 - 3 files changed, 205 insertions(+), 2 deletions(-) create mode 100644 cmd/test-tx-sender/main.go diff --git a/Makefile b/Makefile index 82502db..07c0e9b 100644 --- a/Makefile +++ b/Makefile @@ -25,6 +25,7 @@ build: ## Build the HTTP server @mkdir -p ./build go build -trimpath -ldflags "-X github.com/flashbots/tdx-orderflow-proxy/common.Version=${VERSION}" -v -o ./build/sender-proxy cmd/sender-proxy/main.go go build -trimpath -ldflags "-X github.com/flashbots/tdx-orderflow-proxy/common.Version=${VERSION}" -v -o ./build/receiver-proxy cmd/receiver-proxy/main.go + go build -trimpath -ldflags "-X github.com/flashbots/tdx-orderflow-proxy/common.Version=${VERSION}" -v -o ./build/test-orderflow-sender cmd/test-tx-sender/main.go ##@ Test & Development diff --git a/cmd/test-tx-sender/main.go b/cmd/test-tx-sender/main.go new file mode 100644 index 0000000..82149cd --- /dev/null +++ b/cmd/test-tx-sender/main.go @@ -0,0 +1,204 @@ +package main + +import ( + "context" + "errors" + "io" + "log" + "log/slog" + "net/http" + "os" + + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/rpc" + "github.com/flashbots/go-utils/rpctypes" + "github.com/flashbots/go-utils/signature" + "github.com/flashbots/tdx-orderflow-proxy/proxy" + "github.com/google/uuid" + "github.com/urfave/cli/v2" // imports as package "cli" +) + +var flags []cli.Flag = []cli.Flag{ + // input and output + &cli.StringFlag{ + Name: "local-orderflow-endpoint", + Value: "https://127.0.0.1:443", + Usage: "address to send orderflow to", + EnvVars: []string{"LOCAL_ORDERPLOW_ENDPOINT"}, + }, + &cli.StringFlag{ + Name: "cert-endpoint", + Value: "http://127.0.0.1:14727", + Usage: "address that serves certifiate on /cert endpoint", + EnvVars: []string{"CERT_ENDPOINT"}, + }, + &cli.StringFlag{ + Name: "signer-private-key", + Value: "0x52da2727dd1180b547258c9ca7deb7f9576b2768f3f293b67f36505c85b2ddd0", + Usage: "signer of the requests", + EnvVars: []string{"SIGNER_PRIVATE_KEY"}, + }, + &cli.StringFlag{ + Name: "rpc-endpoint", + Value: "http://127.0.0.1:8545", + Usage: "address of the node RPC that supports eth_blockNumber", + EnvVars: []string{"RPC_ENDPOINT"}, + }, +} + +// test tx + +// tx with hash 0x40614141bf0c512efcaa2e742f79ce5e654c6658d5de77ca4f1154b5b52ae13a +var testTx = hexutil.MustDecode("0x1234") + +func main() { + app := &cli.App{ + Name: "test-tx-sender", + Usage: "send test transactions", + Flags: flags, + Action: func(cCtx *cli.Context) error { + localOrderflowEndpoint := cCtx.String("local-orderflow-endpoint") + certEndpoint := cCtx.String("cert-endpoint") + signerPrivateKey := cCtx.String("signer-private-key") + + orderflowSigner, err := signature.NewSignerFromHexPrivateKey(signerPrivateKey) + if err != nil { + return err + } + slog.Info("Ordeflow signing address", "address", orderflowSigner.Address()) + + cert, err := fetchCertificate(certEndpoint + "/cert") + if err != nil { + return err + } + slog.Info("Fetched certificate") + + client, err := proxy.RPCClientWithCertAndSigner(localOrderflowEndpoint, cert, orderflowSigner, 1) + if err != nil { + return err + } + slog.Info("Created client") + + rpcEndpoint := cCtx.String("rpc-endpoint") + blockNumberSource := proxy.NewBlockNumberSource(rpcEndpoint) + block, err := blockNumberSource.BlockNumber() + if err != nil { + return err + } + slog.Info("Current block number", "block", block) + + // send eth_sendRawTransactions + resp, err := client.Call(context.Background(), "eth_sendRawTransaction", hexutil.Bytes(testTx)) + if err != nil { + return err + } + if resp.Error != nil { + slog.Error("RPC returned error", "error", resp.Error) + return errors.New("eth_sendRawTransaction failed") + } + slog.Info("Sent eth_sendRawTransaction") + + // send eth_sendBundle + replacementUUIDTyped := uuid.New() + repacementUUID := replacementUUIDTyped.String() + slog.Info("Using the following replacement UUID", "value", repacementUUID) + bundleArgs := rpctypes.EthSendBundleArgs{ + Txs: []hexutil.Bytes{testTx}, + ReplacementUUID: &repacementUUID, + BlockNumber: rpc.BlockNumber(block), //nolint:gosec + } + + bundleHash, bundleUUID, err := bundleArgs.Validate() + if err != nil { + return err + } + resp, err = client.Call(context.Background(), "eth_sendBundle", bundleArgs) + if err != nil { + return err + } + if resp.Error != nil { + slog.Error("RPC returned error", "error", resp.Error) + return errors.New("eth_sendBundle failed") + } + slog.Info("Sent eth_sendBundle", "bundleHash", bundleHash, "bundleUUID", bundleUUID) + + // send eth_cancelBundle + + resp, err = client.Call(context.Background(), "eth_cancelBundle", rpctypes.EthCancelBundleArgs{ + ReplacementUUID: repacementUUID, + }) + if err != nil { + return err + } + if resp.Error != nil { + slog.Error("RPC returned error", "error", resp.Error) + return errors.New("eth_cancelBundle failed") + } + slog.Info("Sent eth_cancelBundle") + + // send mev_sendBundle (normal bundle) + sbundleArgs := rpctypes.MevSendBundleArgs{ + Version: "v0.1", + ReplacementUUID: repacementUUID, + Inclusion: rpctypes.MevBundleInclusion{ + BlockNumber: hexutil.Uint64(block), + }, + Body: []rpctypes.MevBundleBody{ + { + Tx: (*hexutil.Bytes)(&testTx), + CanRevert: true, + }, + }, + } + sbundleHash, err := sbundleArgs.Validate() + if err != nil { + return err + } + + resp, err = client.Call(context.Background(), "mev_sendBundle", sbundleArgs) + if err != nil { + return err + } + if resp.Error != nil { + slog.Error("RPC returned error", "error", resp.Error) + return errors.New("mev_sendBundle (normal bundle) failed") + } + slog.Info("Sent mev_sendBundle (normal bundle)", "hash", sbundleHash) + + // send mev_sendBundle (cancellation bundle) + sbundleCancelArgs := rpctypes.MevSendBundleArgs{ + Version: "v0.1", + ReplacementUUID: repacementUUID, + } + resp, err = client.Call(context.Background(), "mev_sendBundle", sbundleCancelArgs) + if err != nil { + return err + } + if resp.Error != nil { + slog.Error("RPC returned error", "error", resp.Error) + return errors.New("mev_sendBundle (cancellation) failed") + } + slog.Info("Sent mev_sendBundle (cancellation)") + + return nil + }, + } + + if err := app.Run(os.Args); err != nil { + log.Fatal(err) + } +} + +func fetchCertificate(endpoint string) ([]byte, error) { + resp, err := http.Get(endpoint) //nolint:gosec + if err != nil { + return nil, err + } + defer resp.Body.Close() + + body, err := io.ReadAll(resp.Body) + if err != nil { + return nil, err + } + return body, nil +} diff --git a/go.sum b/go.sum index cc34663..563fa1b 100644 --- a/go.sum +++ b/go.sum @@ -56,8 +56,6 @@ github.com/ethereum/go-ethereum v1.14.10 h1:kC24WjYeRjDy86LVo6MfF5Xs7nnUu+XG4Aja github.com/ethereum/go-ethereum v1.14.10/go.mod h1:+l/fr42Mma+xBnhefL/+z11/hcmJ2egl+ScIVPjhc7E= github.com/ethereum/go-verkle v0.1.1-0.20240829091221-dffa7562dbe9 h1:8NfxH2iXvJ60YRB8ChToFTUzl8awsc3cJ8CbLjGIl/A= github.com/ethereum/go-verkle v0.1.1-0.20240829091221-dffa7562dbe9/go.mod h1:M3b90YRnzqKyyzBEWJGqj8Qff4IDeXnzFw0P9bFw3uk= -github.com/flashbots/go-utils v0.8.1-0.20241104120502-7337c4b9d7b6 h1:CYI4xzd3ho4p9tjm4j9vOKHOqes2zz0mSsgUXZVwUJ8= -github.com/flashbots/go-utils v0.8.1-0.20241104120502-7337c4b9d7b6/go.mod h1:Lo/nrlC+q8ANgT3e6MKALIJCU+V9qTSgNtoLk/q1uIw= github.com/flashbots/go-utils v0.8.1-0.20241111163610-99c6bcefd7df h1:hUEq6QNP8kUMQcOJc/iur3XFMUptqgAn+Qz1XYccj1k= github.com/flashbots/go-utils v0.8.1-0.20241111163610-99c6bcefd7df/go.mod h1:Lo/nrlC+q8ANgT3e6MKALIJCU+V9qTSgNtoLk/q1uIw= github.com/getsentry/sentry-go v0.27.0 h1:Pv98CIbtB3LkMWmXi4Joa5OOcwbmnX88sF5qbK3r3Ps=