// submit the evidence of malicious voting package main import ( "context" "fmt" "math/big" "os" "strings" "time" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/systemcontracts" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/ethclient" "github.com/ethereum/go-ethereum/internal/flags" "github.com/ethereum/go-ethereum/log" "github.com/urfave/cli/v2" ) var ( app *cli.App senderFlag = &cli.StringFlag{ Name: "sender", Usage: "raw private key in hex format without 0x prefix; check permission on your own", } nodeFlag = &cli.StringFlag{ Name: "node", Usage: "rpc endpoint, http,https,ws,wss,ipc are supported", } chainIdFlag = &cli.UintFlag{ Name: "chainId", Usage: "chainId, can get by eth_chainId", } evidenceFlag = &cli.StringFlag{ Name: "evidence", Usage: "params for submitFinalityViolationEvidence in json format; string", } ) func init() { app = flags.NewApp("a tool for submitting the evidence of malicious voting") app.Name = "maliciousvote-submit" app.Flags = []cli.Flag{ senderFlag, nodeFlag, chainIdFlag, evidenceFlag, } app.Action = submitMaliciousVotes } func submitMaliciousVotes(c *cli.Context) error { // get sender senderRawKey := c.String(senderFlag.Name) if senderRawKey == "" { log.Crit("no sender specified (--sender)") } sender, err := crypto.HexToECDSA(senderRawKey) if err != nil { log.Crit("get sender failed", "error", err) } else { log.Info("get sender success") } // connect to the given URL nodeURL := c.String(nodeFlag.Name) if nodeURL == "" { log.Crit("no node specified (--node)") } client, err := ethclient.Dial(nodeURL) if err != nil { log.Crit("Error connecting to client", "nodeURL", nodeURL, "error", err) } else { // when nodeURL is type of http or https, err==nil not mean successfully connected if !strings.HasPrefix(nodeURL, "http") { log.Info("Successfully connected to client", "nodeURL", nodeURL) } } // get chainId chainId := c.Uint(chainIdFlag.Name) if chainId == 0 { log.Crit("no chainId specified (--chainId)") } else { log.Info("get chainId success", "chainId", chainId) } // get evidence evidenceJson := c.String(evidenceFlag.Name) if evidenceJson == "" { log.Crit("no evidence specified (--evidence)") } var evidence SlashIndicatorFinalityEvidence if err = evidence.UnmarshalJSON([]byte(evidenceJson)); err != nil { log.Crit("Error parsing evidence", "error", err) } else { log.Info("get evidence success") } ops, _ := bind.NewKeyedTransactorWithChainID(sender, big.NewInt(int64(chainId))) //ops.GasLimit = 800000 slashIndicator, _ := NewSlashIndicator(common.HexToAddress(systemcontracts.SlashContract), client) tx, err := slashIndicator.SubmitFinalityViolationEvidence(ops, evidence) if err != nil { log.Crit("submitMaliciousVotes:", "error", err) } var rc *types.Receipt for i := 0; i < 180; i++ { rc, err = client.TransactionReceipt(context.Background(), tx.Hash()) if err == nil && rc.Status != 0 { log.Info("submitMaliciousVotes: submit evidence success", "receipt", rc) break } if rc != nil && rc.Status == 0 { log.Crit("submitMaliciousVotes: tx failed: ", "error", err, "receipt", rc) } time.Sleep(100 * time.Millisecond) } if rc == nil { log.Crit("submitMaliciousVotes: submit evidence failed") } return nil } func main() { log.SetDefault(log.NewLogger(log.NewTerminalHandlerWithLevel(os.Stderr, log.LevelInfo, true))) if err := app.Run(os.Args); err != nil { fmt.Fprintln(os.Stderr, err) os.Exit(1) } }