feat: add a tool for submitting evidence of malicious voting (#1660)
* feat: add a tool for submitting evidence of malicious voting
This commit is contained in:
parent
3d8753cae6
commit
86446edf55
21
cmd/maliciousvote-submit/README.md
Normal file
21
cmd/maliciousvote-submit/README.md
Normal file
@ -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-submit --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
cmd/maliciousvote-submit/json_encoding_helper.go
Normal file
72
cmd/maliciousvote-submit/json_encoding_helper.go
Normal file
@ -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
cmd/maliciousvote-submit/json_encoding_helper_test.go
Normal file
23
cmd/maliciousvote-submit/json_encoding_helper_test.go
Normal file
@ -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
cmd/maliciousvote-submit/main.go
Normal file
140
cmd/maliciousvote-submit/main.go
Normal file
@ -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)
|
||||
}
|
||||
|
||||
}
|
217
cmd/maliciousvote-submit/slash_indicator.go
Normal file
217
cmd/maliciousvote-submit/slash_indicator.go
Normal file
@ -0,0 +1,217 @@
|
||||
// Code generated - DO NOT EDIT.
|
||||
// This file is a generated binding and any manual changes will be lost.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"math/big"
|
||||
"strings"
|
||||
|
||||
ethereum "github.com/ethereum/go-ethereum"
|
||||
"github.com/ethereum/go-ethereum/accounts/abi"
|
||||
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/event"
|
||||
)
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
var (
|
||||
_ = errors.New
|
||||
_ = big.NewInt
|
||||
_ = strings.NewReader
|
||||
_ = ethereum.NotFound
|
||||
_ = bind.Bind
|
||||
_ = common.Big1
|
||||
_ = types.BloomLookup
|
||||
_ = event.NewSubscription
|
||||
)
|
||||
|
||||
// SlashIndicatorFinalityEvidence is an auto generated low-level Go binding around an user-defined struct.
|
||||
type SlashIndicatorFinalityEvidence struct {
|
||||
VoteA SlashIndicatorVoteData
|
||||
VoteB SlashIndicatorVoteData
|
||||
VoteAddr []byte
|
||||
}
|
||||
|
||||
// SlashIndicatorVoteData is an auto generated low-level Go binding around an user-defined struct.
|
||||
type SlashIndicatorVoteData struct {
|
||||
SrcNum *big.Int
|
||||
SrcHash [32]byte
|
||||
TarNum *big.Int
|
||||
TarHash [32]byte
|
||||
Sig []byte
|
||||
}
|
||||
|
||||
// SlashIndicatorMetaData contains all meta data concerning the SlashIndicator contract.
|
||||
var SlashIndicatorMetaData = &bind.MetaData{
|
||||
ABI: "[{\"inputs\":[{\"components\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"srcNum\",\"type\":\"uint256\"},{\"internalType\":\"bytes32\",\"name\":\"srcHash\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"tarNum\",\"type\":\"uint256\"},{\"internalType\":\"bytes32\",\"name\":\"tarHash\",\"type\":\"bytes32\"},{\"internalType\":\"bytes\",\"name\":\"sig\",\"type\":\"bytes\"}],\"internalType\":\"structSlashIndicator.VoteData\",\"name\":\"voteA\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"uint256\",\"name\":\"srcNum\",\"type\":\"uint256\"},{\"internalType\":\"bytes32\",\"name\":\"srcHash\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"tarNum\",\"type\":\"uint256\"},{\"internalType\":\"bytes32\",\"name\":\"tarHash\",\"type\":\"bytes32\"},{\"internalType\":\"bytes\",\"name\":\"sig\",\"type\":\"bytes\"}],\"internalType\":\"structSlashIndicator.VoteData\",\"name\":\"voteB\",\"type\":\"tuple\"},{\"internalType\":\"bytes\",\"name\":\"voteAddr\",\"type\":\"bytes\"}],\"internalType\":\"structSlashIndicator.FinalityEvidence\",\"name\":\"_evidence\",\"type\":\"tuple\"}],\"name\":\"submitFinalityViolationEvidence\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]",
|
||||
}
|
||||
|
||||
// SlashIndicatorABI is the input ABI used to generate the binding from.
|
||||
// Deprecated: Use SlashIndicatorMetaData.ABI instead.
|
||||
var SlashIndicatorABI = SlashIndicatorMetaData.ABI
|
||||
|
||||
// SlashIndicator is an auto generated Go binding around an Ethereum contract.
|
||||
type SlashIndicator struct {
|
||||
SlashIndicatorCaller // Read-only binding to the contract
|
||||
SlashIndicatorTransactor // Write-only binding to the contract
|
||||
SlashIndicatorFilterer // Log filterer for contract events
|
||||
}
|
||||
|
||||
// SlashIndicatorCaller is an auto generated read-only Go binding around an Ethereum contract.
|
||||
type SlashIndicatorCaller struct {
|
||||
contract *bind.BoundContract // Generic contract wrapper for the low level calls
|
||||
}
|
||||
|
||||
// SlashIndicatorTransactor is an auto generated write-only Go binding around an Ethereum contract.
|
||||
type SlashIndicatorTransactor struct {
|
||||
contract *bind.BoundContract // Generic contract wrapper for the low level calls
|
||||
}
|
||||
|
||||
// SlashIndicatorFilterer is an auto generated log filtering Go binding around an Ethereum contract events.
|
||||
type SlashIndicatorFilterer struct {
|
||||
contract *bind.BoundContract // Generic contract wrapper for the low level calls
|
||||
}
|
||||
|
||||
// SlashIndicatorSession is an auto generated Go binding around an Ethereum contract,
|
||||
// with pre-set call and transact options.
|
||||
type SlashIndicatorSession struct {
|
||||
Contract *SlashIndicator // Generic contract binding to set the session for
|
||||
CallOpts bind.CallOpts // Call options to use throughout this session
|
||||
TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session
|
||||
}
|
||||
|
||||
// SlashIndicatorCallerSession is an auto generated read-only Go binding around an Ethereum contract,
|
||||
// with pre-set call options.
|
||||
type SlashIndicatorCallerSession struct {
|
||||
Contract *SlashIndicatorCaller // Generic contract caller binding to set the session for
|
||||
CallOpts bind.CallOpts // Call options to use throughout this session
|
||||
}
|
||||
|
||||
// SlashIndicatorTransactorSession is an auto generated write-only Go binding around an Ethereum contract,
|
||||
// with pre-set transact options.
|
||||
type SlashIndicatorTransactorSession struct {
|
||||
Contract *SlashIndicatorTransactor // Generic contract transactor binding to set the session for
|
||||
TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session
|
||||
}
|
||||
|
||||
// SlashIndicatorRaw is an auto generated low-level Go binding around an Ethereum contract.
|
||||
type SlashIndicatorRaw struct {
|
||||
Contract *SlashIndicator // Generic contract binding to access the raw methods on
|
||||
}
|
||||
|
||||
// SlashIndicatorCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract.
|
||||
type SlashIndicatorCallerRaw struct {
|
||||
Contract *SlashIndicatorCaller // Generic read-only contract binding to access the raw methods on
|
||||
}
|
||||
|
||||
// SlashIndicatorTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract.
|
||||
type SlashIndicatorTransactorRaw struct {
|
||||
Contract *SlashIndicatorTransactor // Generic write-only contract binding to access the raw methods on
|
||||
}
|
||||
|
||||
// NewSlashIndicator creates a new instance of SlashIndicator, bound to a specific deployed contract.
|
||||
func NewSlashIndicator(address common.Address, backend bind.ContractBackend) (*SlashIndicator, error) {
|
||||
contract, err := bindSlashIndicator(address, backend, backend, backend)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &SlashIndicator{SlashIndicatorCaller: SlashIndicatorCaller{contract: contract}, SlashIndicatorTransactor: SlashIndicatorTransactor{contract: contract}, SlashIndicatorFilterer: SlashIndicatorFilterer{contract: contract}}, nil
|
||||
}
|
||||
|
||||
// NewSlashIndicatorCaller creates a new read-only instance of SlashIndicator, bound to a specific deployed contract.
|
||||
func NewSlashIndicatorCaller(address common.Address, caller bind.ContractCaller) (*SlashIndicatorCaller, error) {
|
||||
contract, err := bindSlashIndicator(address, caller, nil, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &SlashIndicatorCaller{contract: contract}, nil
|
||||
}
|
||||
|
||||
// NewSlashIndicatorTransactor creates a new write-only instance of SlashIndicator, bound to a specific deployed contract.
|
||||
func NewSlashIndicatorTransactor(address common.Address, transactor bind.ContractTransactor) (*SlashIndicatorTransactor, error) {
|
||||
contract, err := bindSlashIndicator(address, nil, transactor, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &SlashIndicatorTransactor{contract: contract}, nil
|
||||
}
|
||||
|
||||
// NewSlashIndicatorFilterer creates a new log filterer instance of SlashIndicator, bound to a specific deployed contract.
|
||||
func NewSlashIndicatorFilterer(address common.Address, filterer bind.ContractFilterer) (*SlashIndicatorFilterer, error) {
|
||||
contract, err := bindSlashIndicator(address, nil, nil, filterer)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &SlashIndicatorFilterer{contract: contract}, nil
|
||||
}
|
||||
|
||||
// bindSlashIndicator binds a generic wrapper to an already deployed contract.
|
||||
func bindSlashIndicator(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) {
|
||||
parsed, err := abi.JSON(strings.NewReader(SlashIndicatorABI))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return bind.NewBoundContract(address, parsed, caller, transactor, filterer), nil
|
||||
}
|
||||
|
||||
// Call invokes the (constant) contract method with params as input values and
|
||||
// sets the output to result. The result type might be a single field for simple
|
||||
// returns, a slice of interfaces for anonymous returns and a struct for named
|
||||
// returns.
|
||||
func (_SlashIndicator *SlashIndicatorRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
|
||||
return _SlashIndicator.Contract.SlashIndicatorCaller.contract.Call(opts, result, method, params...)
|
||||
}
|
||||
|
||||
// Transfer initiates a plain transaction to move funds to the contract, calling
|
||||
// its default method if one is available.
|
||||
func (_SlashIndicator *SlashIndicatorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
|
||||
return _SlashIndicator.Contract.SlashIndicatorTransactor.contract.Transfer(opts)
|
||||
}
|
||||
|
||||
// Transact invokes the (paid) contract method with params as input values.
|
||||
func (_SlashIndicator *SlashIndicatorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
|
||||
return _SlashIndicator.Contract.SlashIndicatorTransactor.contract.Transact(opts, method, params...)
|
||||
}
|
||||
|
||||
// Call invokes the (constant) contract method with params as input values and
|
||||
// sets the output to result. The result type might be a single field for simple
|
||||
// returns, a slice of interfaces for anonymous returns and a struct for named
|
||||
// returns.
|
||||
func (_SlashIndicator *SlashIndicatorCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
|
||||
return _SlashIndicator.Contract.contract.Call(opts, result, method, params...)
|
||||
}
|
||||
|
||||
// Transfer initiates a plain transaction to move funds to the contract, calling
|
||||
// its default method if one is available.
|
||||
func (_SlashIndicator *SlashIndicatorTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
|
||||
return _SlashIndicator.Contract.contract.Transfer(opts)
|
||||
}
|
||||
|
||||
// Transact invokes the (paid) contract method with params as input values.
|
||||
func (_SlashIndicator *SlashIndicatorTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
|
||||
return _SlashIndicator.Contract.contract.Transact(opts, method, params...)
|
||||
}
|
||||
|
||||
// SubmitFinalityViolationEvidence is a paid mutator transaction binding the contract method 0xcc844b73.
|
||||
//
|
||||
// Solidity: function submitFinalityViolationEvidence(((uint256,bytes32,uint256,bytes32,bytes),(uint256,bytes32,uint256,bytes32,bytes),bytes) _evidence) returns()
|
||||
func (_SlashIndicator *SlashIndicatorTransactor) SubmitFinalityViolationEvidence(opts *bind.TransactOpts, _evidence SlashIndicatorFinalityEvidence) (*types.Transaction, error) {
|
||||
return _SlashIndicator.contract.Transact(opts, "submitFinalityViolationEvidence", _evidence)
|
||||
}
|
||||
|
||||
// SubmitFinalityViolationEvidence is a paid mutator transaction binding the contract method 0xcc844b73.
|
||||
//
|
||||
// Solidity: function submitFinalityViolationEvidence(((uint256,bytes32,uint256,bytes32,bytes),(uint256,bytes32,uint256,bytes32,bytes),bytes) _evidence) returns()
|
||||
func (_SlashIndicator *SlashIndicatorSession) SubmitFinalityViolationEvidence(_evidence SlashIndicatorFinalityEvidence) (*types.Transaction, error) {
|
||||
return _SlashIndicator.Contract.SubmitFinalityViolationEvidence(&_SlashIndicator.TransactOpts, _evidence)
|
||||
}
|
||||
|
||||
// SubmitFinalityViolationEvidence is a paid mutator transaction binding the contract method 0xcc844b73.
|
||||
//
|
||||
// Solidity: function submitFinalityViolationEvidence(((uint256,bytes32,uint256,bytes32,bytes),(uint256,bytes32,uint256,bytes32,bytes),bytes) _evidence) returns()
|
||||
func (_SlashIndicator *SlashIndicatorTransactorSession) SubmitFinalityViolationEvidence(_evidence SlashIndicatorFinalityEvidence) (*types.Transaction, error) {
|
||||
return _SlashIndicator.Contract.SubmitFinalityViolationEvidence(&_SlashIndicator.TransactOpts, _evidence)
|
||||
}
|
@ -1,7 +1,8 @@
|
||||
package monitor
|
||||
|
||||
import (
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"encoding/json"
|
||||
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/ethereum/go-ethereum/metrics"
|
||||
@ -59,27 +60,37 @@ func (m *MaliciousVoteMonitor) ConflictDetect(newVote *types.VoteEnvelope, pendi
|
||||
}
|
||||
for ; blockNumber <= pendingBlockNumber+upperLimitOfVoteBlockNumber; blockNumber++ {
|
||||
if voteDataBuffer.Contains(blockNumber) {
|
||||
voteData, ok := voteDataBuffer.Get(blockNumber)
|
||||
voteEnvelope, ok := voteDataBuffer.Get(blockNumber)
|
||||
if !ok {
|
||||
log.Error("Failed to get voteData info from LRU cache.")
|
||||
continue
|
||||
}
|
||||
maliciousVote := false
|
||||
if blockNumber == targetNumber {
|
||||
log.Warn("violate rule1", "VoteAddress", common.Bytes2Hex(newVote.VoteAddress[:]), "voteExisted", voteData.(*types.VoteData), "newVote", newVote.Data)
|
||||
violateRule1Counter.Inc(1)
|
||||
// prepare message for slashing
|
||||
return true
|
||||
} else if (blockNumber < targetNumber && voteData.(*types.VoteData).SourceNumber > sourceNumber) ||
|
||||
(blockNumber > targetNumber && voteData.(*types.VoteData).SourceNumber < sourceNumber) {
|
||||
log.Warn("violate rule2", "VoteAddress", common.Bytes2Hex(newVote.VoteAddress[:]), "voteExisted", voteData.(*types.VoteData), "newVote", newVote.Data)
|
||||
maliciousVote = true
|
||||
} else if (blockNumber < targetNumber && voteEnvelope.(*types.VoteEnvelope).Data.SourceNumber > sourceNumber) ||
|
||||
(blockNumber > targetNumber && voteEnvelope.(*types.VoteEnvelope).Data.SourceNumber < sourceNumber) {
|
||||
violateRule2Counter.Inc(1)
|
||||
// prepare message for slashing
|
||||
maliciousVote = true
|
||||
}
|
||||
if maliciousVote {
|
||||
evidence := types.NewSlashIndicatorFinalityEvidenceWrapper(voteEnvelope.(*types.VoteEnvelope), newVote)
|
||||
if evidence != nil {
|
||||
if evidenceJson, err := json.Marshal(evidence); err == nil {
|
||||
log.Warn("MaliciousVote", "evidence", string(evidenceJson))
|
||||
} else {
|
||||
log.Warn("MaliciousVote, Marshal evidence failed")
|
||||
}
|
||||
} else {
|
||||
log.Warn("MaliciousVote, construct evidence failed")
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// for simplicity, Just override even if the targetNumber has existed.
|
||||
voteDataBuffer.Add(newVote.Data.TargetNumber, newVote.Data)
|
||||
voteDataBuffer.Add(newVote.Data.TargetNumber, newVote)
|
||||
return false
|
||||
}
|
||||
|
@ -1,6 +1,8 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"math/big"
|
||||
"sync/atomic"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
@ -89,3 +91,41 @@ func (vote *VoteEnvelope) Verify() error {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type SlashIndicatorVoteDataWrapper struct {
|
||||
SrcNum *big.Int
|
||||
SrcHash string
|
||||
TarNum *big.Int
|
||||
TarHash string
|
||||
Sig string
|
||||
}
|
||||
|
||||
type SlashIndicatorFinalityEvidenceWrapper struct {
|
||||
VoteA SlashIndicatorVoteDataWrapper
|
||||
VoteB SlashIndicatorVoteDataWrapper
|
||||
VoteAddr string
|
||||
}
|
||||
|
||||
func NewSlashIndicatorFinalityEvidenceWrapper(vote1, vote2 *VoteEnvelope) *SlashIndicatorFinalityEvidenceWrapper {
|
||||
if !bytes.Equal(vote1.VoteAddress[:], vote1.VoteAddress[:]) ||
|
||||
vote1.Data == nil || vote2.Data == nil {
|
||||
return nil
|
||||
}
|
||||
return &SlashIndicatorFinalityEvidenceWrapper{
|
||||
VoteA: SlashIndicatorVoteDataWrapper{
|
||||
SrcNum: big.NewInt(int64(vote1.Data.SourceNumber)),
|
||||
SrcHash: common.Bytes2Hex(vote1.Data.SourceHash[:]),
|
||||
TarNum: big.NewInt(int64(vote1.Data.TargetNumber)),
|
||||
TarHash: common.Bytes2Hex(vote1.Data.TargetHash[:]),
|
||||
Sig: common.Bytes2Hex(vote1.Signature[:]),
|
||||
},
|
||||
VoteB: SlashIndicatorVoteDataWrapper{
|
||||
SrcNum: big.NewInt(int64(vote2.Data.SourceNumber)),
|
||||
SrcHash: common.Bytes2Hex(vote2.Data.SourceHash[:]),
|
||||
TarNum: big.NewInt(int64(vote2.Data.TargetNumber)),
|
||||
TarHash: common.Bytes2Hex(vote2.Data.TargetHash[:]),
|
||||
Sig: common.Bytes2Hex(vote2.Signature[:]),
|
||||
},
|
||||
VoteAddr: common.Bytes2Hex(vote1.VoteAddress[:]),
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user