Skip to content

Commit

Permalink
feat: add a tool for submitting evidence of malicious voting
Browse files Browse the repository at this point in the history
  • Loading branch information
NathanBSC committed May 30, 2023
1 parent 1036dc7 commit 4beaa71
Show file tree
Hide file tree
Showing 7 changed files with 534 additions and 10 deletions.
21 changes: 21 additions & 0 deletions cmd/maliciousvote-submit/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
## maliciousvote-submit
A tool for submitting the evidence of malicious voting

### Options
```
GLOBAL OPTIONS:
--sender value raw private key in hex format without 0x prefix; check permission on your own
--node value rpc endpoint, http,https,ws,wss,ipc are supported
--chainId value chainId, can get by eth_chainId (default: 0)
--evidence value params for submitFinalityViolationEvidence in json format; string
--help, -h show help
--version, -v print the version
```
### Evidence
can be extracted from logs generated by MaliciousVoteMonitor

### Example
```
./build/bin/maliciousvote-summit --chainId 714 --sender 59ba8068eb256d520179e903f43dacf6d8d57d72bd306e1bd603fdb812345678 --node ws://localhost:8545 --evidence "{\"VoteA\":{\"SrcNum\":6948,\"SrcHash\":\"dc58ff5dca8deefb7b03904ef2837e5f8b0e84ec147f021d4ff08343635540d3\",\"TarNum\":6949,\"TarHash\":\"24726f05534dc55c36ecc364951025abada0defa6d1b53bcb6b637f583b59996\",\"Sig\":\"9379a0626f962b828ed21fb34a6b6de034a23651c2e0c12b907293cf8f21d4fdd559e6f9c7f450a4243d33ad7aa5783d0e51e70979631d82819c254dfb130dfe924f057f7e2b4e64195fc7562f1cb0c45486c9cc3e6cc5679b4c0b5744bf33b5\"},\"VoteB\":{\"SrcNum\":6947,\"SrcHash\":\"24726f05534dc55c36ecc364951025abada0defa6d1b53bcb6b637f583b59996\",\"TarNum\":6950,\"TarHash\":\"6257f70ea6439b84d910595064a6e44e55ba0f2abc0c887346c420a60a5ef119\",\"Sig\":\"af9b500877d64277e80eea7c42b8d6ae5744d715625344ef6ddc66fa4e1dcb3e94568c79e018239641b724bacaa93046052d13f87b655d58b7afecf4e31036d5eca911e8c7436deea68c1e64ef7ed527ed25416039e4e7352f9b089cfb86481f\"},\"VoteAddr\":\"98b94137e4e2d4e628dcbc4a05d554f44950a7498040d3276d49c265708229127cd20e48c773cdc7a898b3bb572a17bf\"}"
```

72 changes: 72 additions & 0 deletions cmd/maliciousvote-submit/json_encoding_helper.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package main

import (
"encoding/json"

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

func (s SlashIndicatorVoteData) ToWrapper() *types.SlashIndicatorVoteDataWrapper {
wrapper := &types.SlashIndicatorVoteDataWrapper{
SrcNum: s.SrcNum,
TarNum: s.TarNum,
}

if len(s.Sig) != types.BLSSignatureLength {
log.Crit("wrong length of sig", "wanted", types.BLSSignatureLength, "get", len(s.Sig))
}
wrapper.SrcHash = common.Bytes2Hex(s.SrcHash[:])
wrapper.TarHash = common.Bytes2Hex(s.TarHash[:])
wrapper.Sig = common.Bytes2Hex(s.Sig)
return wrapper
}

func (s *SlashIndicatorVoteData) FromWrapper(wrapper *types.SlashIndicatorVoteDataWrapper) {
if len(wrapper.SrcHash) != common.HashLength*2 {
log.Crit("wrong length of SrcHash", "wanted", common.HashLength*2, "get", len(wrapper.SrcHash))
}
if len(wrapper.TarHash) != common.HashLength*2 {
log.Crit("wrong length of TarHash", "wanted", common.HashLength*2, "get", len(wrapper.TarHash))
}
if len(wrapper.Sig) != types.BLSSignatureLength*2 {
log.Crit("wrong length of Sig", "wanted", types.BLSSignatureLength*2, "get", len(wrapper.Sig))
}

s.SrcNum = wrapper.SrcNum
s.TarNum = wrapper.TarNum
copy(s.SrcHash[:], common.Hex2Bytes(wrapper.SrcHash))
copy(s.TarHash[:], common.Hex2Bytes(wrapper.TarHash))
s.Sig = common.Hex2Bytes(wrapper.Sig)
}

func (s SlashIndicatorFinalityEvidence) MarshalJSON() ([]byte, error) {
wrapper := &types.SlashIndicatorFinalityEvidenceWrapper{
VoteA: *s.VoteA.ToWrapper(),
VoteB: *s.VoteB.ToWrapper(),
}

if len(s.VoteAddr) != types.BLSPublicKeyLength {
log.Crit("wrong length of VoteAddr", "wanted", types.BLSPublicKeyLength, "get", len(s.VoteAddr))
}
wrapper.VoteAddr = common.Bytes2Hex(s.VoteAddr)

return json.Marshal(wrapper)
}

func (s *SlashIndicatorFinalityEvidence) UnmarshalJSON(data []byte) error {
var wrapper = &types.SlashIndicatorFinalityEvidenceWrapper{}
if err := json.Unmarshal(data, wrapper); err != nil {
log.Crit("failed to Unmarshal", "error", err)
}

s.VoteA.FromWrapper(&wrapper.VoteA)
s.VoteB.FromWrapper(&wrapper.VoteB)
if len(wrapper.VoteAddr) != types.BLSPublicKeyLength*2 {
log.Crit("wrong length of VoteAddr", "wanted", types.BLSPublicKeyLength*2, "get", len(wrapper.VoteAddr))
}
s.VoteAddr = common.Hex2Bytes(wrapper.VoteAddr)

return nil
}
23 changes: 23 additions & 0 deletions cmd/maliciousvote-submit/json_encoding_helper_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package main

import (
"os"
"testing"

"github.com/ethereum/go-ethereum/log"
)

func TestSlashIndicatorFinalityEvidenceEncoding(t *testing.T) {
log.Root().SetHandler(log.LvlFilterHandler(log.LvlInfo, log.StreamHandler(os.Stderr, log.TerminalFormat(true))))
evidence := `{"VoteA":{"SrcNum":1234,"SrcHash":"36068b819f244d27b5411d975f9ffd6d18c6084b50fb5595104ffd9de561a9f8","TarNum":1234,"TarHash":"36068b819f244d27b5411d975f9ffd6d18c6084b50fb5595104ffd9de561a9f8","Sig":"893682ebf26440a06daaff5695945ee2012146268f800c217bad9906ac64dc46996cd435e3e829529aa0445b52530070893682ebf26440a06daaff5695945ee2012146268f800c217bad9906ac64dc46996cd435e3e829529aa0445b52530070"},"VoteB":{"SrcNum":1234,"SrcHash":"36068b819f244d27b5411d975f9ffd6d18c6084b50fb5595104ffd9de561a9f8","TarNum":1234,"TarHash":"36068b819f244d27b5411d975f9ffd6d18c6084b50fb5595104ffd9de561a9f8","Sig":"893682ebf26440a06daaff5695945ee2012146268f800c217bad9906ac64dc46996cd435e3e829529aa0445b52530070893682ebf26440a06daaff5695945ee2012146268f800c217bad9906ac64dc46996cd435e3e829529aa0445b52530070"},"VoteAddr":"893682ebf26440a06daaff5695945ee2012146268f800c217bad9906ac64dc46996cd435e3e829529aa0445b52530070"}`

slashIndicatorFinalityEvidence := &SlashIndicatorFinalityEvidence{}
if err := slashIndicatorFinalityEvidence.UnmarshalJSON([]byte(evidence)); err != nil {
log.Crit("SlashIndicatorFinalityEvidence UnmarshalJSON failed")
}
if output, err := slashIndicatorFinalityEvidence.MarshalJSON(); err != nil {
log.Crit("SlashIndicatorFinalityEvidence MarshalJSON failed")
} else if string(output) != evidence {
log.Crit("SlashIndicatorFinalityEvidence UnmarshalJSON MarshalJSON mismatch", "output", string(output), "evidence", evidence)
}
}
140 changes: 140 additions & 0 deletions cmd/maliciousvote-submit/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
// 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"
"gopkg.in/urfave/cli.v1"
)

var (
// Git SHA1 commit hash of the release (set via linker flags)
gitCommit = ""
gitDate = ""

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(gitCommit, gitDate, "a tool for submitting the evidence of malicious voting")
app.Flags = []cli.Flag{
senderFlag,
nodeFlag,
chainIdFlag,
evidenceFlag,
}
app.Action = submitMaliciousVotes
cli.CommandHelpTemplate = flags.AppHelpTemplate
}

func submitMaliciousVotes(c *cli.Context) {
// get sender
senderRawKey := c.GlobalString(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.GlobalString(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.GlobalUint(chainIdFlag.Name)
if chainId == 0 {
log.Crit("no chainId specified (--chainId)")
} else {
log.Info("get chainId success", "chainId", chainId)
}

// get evidence
evidenceJson := c.GlobalString(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")
}
}

func main() {
log.Root().SetHandler(log.LvlFilterHandler(log.LvlInfo, log.StreamHandler(os.Stderr, log.TerminalFormat(true))))

if err := app.Run(os.Args); err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}

}
Loading

0 comments on commit 4beaa71

Please sign in to comment.