-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add a tool for submitting evidence of malicious voting
- Loading branch information
Showing
7 changed files
with
514 additions
and
11 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 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 for 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) | ||
} | ||
|
||
} |
Oops, something went wrong.