diff --git a/Makefile b/Makefile index 246e4b3467a83adb317f11ffa6312f109b3788a7..c150585948dbfc38d534d0666f1d19f7d0886341 100644 --- a/Makefile +++ b/Makefile @@ -110,6 +110,11 @@ tracker: @echo "Done building." @echo "Run \"$(GOBIN)/tracker\" to run snapshots tracker." +devnettest: + $(GOBUILD) -o $(GOBIN)/devnettest ./cmd/devnettest + @echo "Done building." + @echo "Run \"$(GOBIN)/devnettest\" to launch devnettest." + db-tools: @echo "Building db-tools" rm -rf libmdbx # hub.docker.com setup incorrect gitpath for git modules. Just remove it and re-init submodule. diff --git a/cmd/devnettest/main.go b/cmd/devnettest/main.go new file mode 100644 index 0000000000000000000000000000000000000000..6cad3a97b535039b7753bd6e3daa37a5b0442122 --- /dev/null +++ b/cmd/devnettest/main.go @@ -0,0 +1,43 @@ +package main + +import ( + "flag" + "fmt" + "github.com/ledgerwatch/erigon/cmd/devnettest/services" +) + +func main() { + var ( + to string + value uint64 + blockNum string + getBalance bool + sendTx bool + txPoolContent bool + clearDev bool + ) + + flag.StringVar(&to, "to", "", "String Address to send to") + flag.Uint64Var(&value, "value", uint64(0), "Uint64 Value to send") + flag.StringVar(&blockNum, "block-num", "latest", "String denoting block number") + flag.BoolVar(&getBalance, "get-balance", false, "Boolean Flag to determine if API should get balance") + flag.BoolVar(&sendTx, "send-tx", false, "Boolean Flag to determine if API should send transaction") + flag.BoolVar(&txPoolContent, "txpool-content", false, "Boolean Flag to determine if API should get content of txpool") + flag.BoolVar(&clearDev, "clear-dev", false, "Boolean Flag to determine if service should clear /dev after this call") + flag.Parse() + + //fmt.Printf("to: %v\n", to) + //fmt.Printf("value: %v\n", value) + //fmt.Printf("blockNum: %v\n", blockNum) + //fmt.Printf("getBalance: %v\n", getBalance) + //fmt.Printf("sendTx: %v\n", sendTx) + //fmt.Printf("txPoolContent: %v\n", txPoolContent) + //fmt.Printf("clearDev: %v\n", clearDev) + + services.ValidateInputs(&getBalance, &sendTx, &txPoolContent, &blockNum, &value, &to) + + services.ParseRequests(&getBalance, &sendTx, &txPoolContent, &clearDev, &blockNum, &value, &to) + + fmt.Print("\n") + fmt.Print("Finished processing\n") +} diff --git a/cmd/devnettest/requests/request_generator.go b/cmd/devnettest/requests/request_generator.go new file mode 100644 index 0000000000000000000000000000000000000000..c31fcc551397ce4da7e54ca0b3c36f93dc36342b --- /dev/null +++ b/cmd/devnettest/requests/request_generator.go @@ -0,0 +1,53 @@ +package requests + +import ( + "fmt" + "github.com/ledgerwatch/erigon/cmd/rpctest/rpctest" + "github.com/ledgerwatch/erigon/common" + "net/http" + "time" +) + +var ( + erigonUrl = "http://localhost:8545" +) + +type RequestGenerator struct { + reqID int + client *http.Client +} + +func initialiseRequestGenerator() *RequestGenerator { + var client = &http.Client{ + Timeout: time.Second * 600, + } + + reqGen := RequestGenerator{ + client: client, + } + reqGen.reqID++ + + return &reqGen +} + +func (req *RequestGenerator) Erigon(method, body string, response interface{}) rpctest.CallResult { + return req.call(erigonUrl, method, body, response) +} + +func (req *RequestGenerator) call(target string, method, body string, response interface{}) rpctest.CallResult { + start := time.Now() + err := post(req.client, erigonUrl, body, response) + return rpctest.CallResult{ + RequestBody: body, + Target: target, + Took: time.Since(start), + RequestID: req.reqID, + Method: method, + Err: err, + } +} + +func (req *RequestGenerator) getBalance(address common.Address, blockNum string) string { + const template = `{"jsonrpc":"2.0","method":"eth_getBalance","params":["0x%x","%v"],"id":%d}` + return fmt.Sprintf(template, address, blockNum, req.reqID) +} diff --git a/cmd/devnettest/requests/requests.go b/cmd/devnettest/requests/requests.go new file mode 100644 index 0000000000000000000000000000000000000000..59d2ab8b8e0c2859742d427add984b46e7b55e04 --- /dev/null +++ b/cmd/devnettest/requests/requests.go @@ -0,0 +1,31 @@ +package requests + +import ( + "crypto/ecdsa" + "fmt" + "github.com/ledgerwatch/erigon/cmd/rpctest/rpctest" + "github.com/ledgerwatch/erigon/common" +) + +func GetBalance(address common.Address, blockNum string) { + reqGen := initialiseRequestGenerator() + var b rpctest.EthBalance + + res := reqGen.Erigon("eth_getBalance", reqGen.getBalance(address, blockNum), &b) + if res.Err != nil { + fmt.Printf("Error getting balance: %v\n", res.Err) + return + } + + fmt.Printf("Balance is: %v\n", b.Balance.ToInt()) +} + +func SendTx(from *ecdsa.PrivateKey, to common.Address, value uint64) { + fmt.Printf("from is: %v", from) + fmt.Printf("to is: %v", to) + fmt.Printf("value is: %v", value) +} + +func TxpoolContent() string { + return "" +} diff --git a/cmd/devnettest/requests/utils.go b/cmd/devnettest/requests/utils.go new file mode 100644 index 0000000000000000000000000000000000000000..46c5054578946817e3b7ee7f2c1dcfce8372cc53 --- /dev/null +++ b/cmd/devnettest/requests/utils.go @@ -0,0 +1,29 @@ +package requests + +import ( + "encoding/json" + "fmt" + "net/http" + "strings" + "time" + + "github.com/ledgerwatch/log/v3" +) + +func post(client *http.Client, url, request string, response interface{}) error { + fmt.Printf("Request=%s\n", request) + log.Info("Getting", "url", url, "request", request) + start := time.Now() + r, err := client.Post(url, "application/json", strings.NewReader(request)) + if err != nil { + return err + } + defer r.Body.Close() + if r.StatusCode != 200 { + return fmt.Errorf("status %s", r.Status) + } + decoder := json.NewDecoder(r.Body) + err = decoder.Decode(response) + log.Info("Got in", "time", time.Since(start).Seconds()) + return err +} diff --git a/cmd/devnettest/services/utility.go b/cmd/devnettest/services/utility.go new file mode 100644 index 0000000000000000000000000000000000000000..0e0a821756c92d515185298fb2cb1dbf91ef5180 --- /dev/null +++ b/cmd/devnettest/services/utility.go @@ -0,0 +1,68 @@ +package services + +import ( + "fmt" + "github.com/ledgerwatch/erigon/cmd/devnettest/requests" + "github.com/ledgerwatch/erigon/common" + "github.com/ledgerwatch/erigon/crypto" +) + +var devnetSignPrivateKey, _ = crypto.HexToECDSA("26e86e45f6fc45ec6e2ecd128cec80fa1d1505e5507dcd2ae58c3130a7a97b48") + +func ValidateInputs(getBalance *bool, sendTx *bool, txpoolContent *bool, blockNum *string, value *uint64, to *string) { + if !(*getBalance) && !(*sendTx) && !(*txpoolContent) { + panic("At least one function flag (get-balance, send-tx, txpool-content) should be true") + } + + seen := false + for _, val := range []bool{*getBalance, *sendTx, *txpoolContent} { + if val { + if seen { + panic("Only function flag (get-balance, send-tx, txpool-content) can be true at a time") + } + seen = true + } + } + + if *value <= 0 { + panic("Value must be greater than zero") + } + + if *getBalance { + if *to == "" { + panic("Cannot check balance of empty address") + } + if *blockNum != "pending" && *blockNum != "latest" && *blockNum != "earliest" { + panic("Block number must be 'pending', 'latest' or 'earliest'") + } + } + + if *sendTx && *to == "" { + panic("Cannot send to empty address") + } + +} + +func ParseRequests(getBalance *bool, sendTx *bool, txpoolContent *bool, clearDev *bool, blockNum *string, value *uint64, to *string) { + if *getBalance { + toAddress := common.HexToAddress(*to) + requests.GetBalance(toAddress, *blockNum) + } + + if *sendTx { + toAddress := common.HexToAddress(*to) + requests.SendTx(devnetSignPrivateKey, toAddress, *value) + } + + if *txpoolContent { + requests.TxpoolContent() + } + + if *clearDev { + clearDevDB() + } +} + +func clearDevDB() { + fmt.Printf("Clearing ~/dev\n") +}