diff --git a/cmd/puppeth/wizard_genesis.go b/cmd/puppeth/wizard_genesis.go index 5973a8cebcd833bce50bfeb5b7c33e655d8c391c..6b3d8479b77e2f5d0b626a82668edbf455c09e08 100644 --- a/cmd/puppeth/wizard_genesis.go +++ b/cmd/puppeth/wizard_genesis.go @@ -112,6 +112,7 @@ func (w *wizard) makeGenesis() { ProducerDelay: 5, Sprint: 60, ValidatorContract: "0x0000000000000000000000000000000000001000", + Heimdall: "http://localhost:1317", } // We also need the initial list of signers diff --git a/consensus/bor/api.go b/consensus/bor/api.go index da6ef1bdc0a722cd3e6c852569d5ec04a2ef0340..3e9cf87fa2385a4d2e2f90ebdc7fe555f3a1d1b5 100644 --- a/consensus/bor/api.go +++ b/consensus/bor/api.go @@ -87,33 +87,3 @@ func (api *API) GetSignersAtHash(hash common.Hash) ([]common.Address, error) { } return snap.signers(), nil } - -// Proposals returns the current proposals the node tries to uphold and vote on. -func (api *API) Proposals() map[common.Address]bool { - api.bor.lock.RLock() - defer api.bor.lock.RUnlock() - - proposals := make(map[common.Address]bool) - for address, auth := range api.bor.proposals { - proposals[address] = auth - } - return proposals -} - -// Propose injects a new authorization proposal that the signer will attempt to -// push through. -func (api *API) Propose(address common.Address, auth bool) { - api.bor.lock.Lock() - defer api.bor.lock.Unlock() - - api.bor.proposals[address] = auth -} - -// Discard drops a currently running proposal, stopping the signer from casting -// further votes (either for or against). -func (api *API) Discard(address common.Address) { - api.bor.lock.Lock() - defer api.bor.lock.Unlock() - - delete(api.bor.proposals, address) -} diff --git a/consensus/bor/bor.go b/consensus/bor/bor.go index 6daaebf8e84a2d1dd84754758df144e7053811db..a5469f7ffd04c06412738c1de825a9f86a30b5f2 100644 --- a/consensus/bor/bor.go +++ b/consensus/bor/bor.go @@ -3,12 +3,15 @@ package bor import ( "bytes" "context" + "encoding/json" "errors" "fmt" "io" "math" "math/big" + "net/http" "sort" + "strconv" "strings" "sync" "time" @@ -36,7 +39,7 @@ import ( "golang.org/x/crypto/sha3" ) -const validatorsetABI = `[{"constant":true,"inputs":[{"name":"span","type":"uint256"}],"name":"getSpan","outputs":[{"name":"number","type":"uint256"},{"name":"startBlock","type":"uint256"},{"name":"endBlock","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"number","type":"uint256"}],"name":"getBorValidators","outputs":[{"name":"","type":"address[]"},{"name":"","type":"uint256[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"proposeSpan","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"newSpan","type":"uint256"},{"name":"proposer","type":"address"},{"name":"startBlock","type":"uint256"},{"name":"endBlock","type":"uint256"},{"name":"validatorBytes","type":"bytes"},{"name":"producerBytes","type":"bytes"}],"name":"commitSpan","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"currentSpanNumber","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getNextSpan","outputs":[{"name":"number","type":"uint256"},{"name":"startBlock","type":"uint256"},{"name":"endBlock","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getInitialValidators","outputs":[{"name":"","type":"address[]"},{"name":"","type":"uint256[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getCurrentSpan","outputs":[{"name":"number","type":"uint256"},{"name":"startBlock","type":"uint256"},{"name":"endBlock","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"number","type":"uint256"}],"name":"getSpanByBlock","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getValidators","outputs":[{"name":"","type":"address[]"},{"name":"","type":"uint256[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"vote","type":"bytes"},{"name":"sigs","type":"bytes"},{"name":"txBytes","type":"bytes"},{"name":"proof","type":"bytes"}],"name":"validateValidatorSet","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"}]` +const validatorsetABI = `[{"constant":true,"inputs":[{"name":"span","type":"uint256"}],"name":"getSpan","outputs":[{"name":"number","type":"uint256"},{"name":"startBlock","type":"uint256"},{"name":"endBlock","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"number","type":"uint256"}],"name":"getBorValidators","outputs":[{"name":"","type":"address[]"},{"name":"","type":"uint256[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"newSpan","type":"uint256"},{"name":"startBlock","type":"uint256"},{"name":"endBlock","type":"uint256"},{"name":"validatorBytes","type":"bytes"},{"name":"producerBytes","type":"bytes"}],"name":"commitSpan","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"proposeSpan","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"currentSpanNumber","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getNextSpan","outputs":[{"name":"number","type":"uint256"},{"name":"startBlock","type":"uint256"},{"name":"endBlock","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getInitialValidators","outputs":[{"name":"","type":"address[]"},{"name":"","type":"uint256[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"spanProposalPending","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getCurrentSpan","outputs":[{"name":"number","type":"uint256"},{"name":"startBlock","type":"uint256"},{"name":"endBlock","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"number","type":"uint256"}],"name":"getSpanByBlock","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getValidators","outputs":[{"name":"","type":"address[]"},{"name":"","type":"uint256[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"vote","type":"bytes"},{"name":"sigs","type":"bytes"},{"name":"txBytes","type":"bytes"},{"name":"proof","type":"bytes"}],"name":"validateValidatorSet","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"}]` const ( checkpointInterval = 1024 // Number of blocks after which to save the vote snapshot to the database @@ -238,14 +241,14 @@ type Bor struct { recents *lru.ARCCache // Snapshots for recent block to speed up reorgs signatures *lru.ARCCache // Signatures of recent blocks to speed up mining - proposals map[common.Address]bool // Current list of proposals we are pushing - signer common.Address // Ethereum address of the signing key signFn SignerFn // Signer function to authorize hashes with lock sync.RWMutex // Protects the signer fields ethAPI *ethapi.PublicBlockChainAPI validatorSetABI abi.ABI + span *Span + httpClient http.Client // The fields below are for testing only fakeDiff bool // Skip difficulty verifications @@ -276,8 +279,11 @@ func New( ethAPI: ethAPI, recents: recents, signatures: signatures, - proposals: make(map[common.Address]bool), + span: nil, validatorSetABI: vABI, + httpClient: http.Client{ + Timeout: time.Duration(5 * time.Second), + }, } return c @@ -463,11 +469,8 @@ func (c *Bor) snapshot(chain consensus.ChainReader, number uint64, hash common.H // get checkpoint data hash := checkpoint.Hash() - // current validators - validators, err := c.GetCurrentValidators(number, number+1) - if err != nil { - return nil, err - } + // get validators and current span + validators, _ := c.GetCurrentValidators(number, number+1) // new snap shot snap = newSnapshot(c.config, c.signatures, number, hash, validators, c.ethAPI) @@ -659,8 +662,12 @@ func (c *Bor) Prepare(chain consensus.ChainReader, header *types.Header) error { // Finalize implements consensus.Engine, ensuring no uncles are set, nor block // rewards given. func (c *Bor) Finalize(chain consensus.ChainReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, uncles []*types.Header) { - // commit span - // c.commitSpan(state, header, chainContext{Chain: chain, Bor: c}) + // // commit span + // err := c.checkAndCommitSpan(state, header, chainContext{Chain: chain, Bor: c}) + // if err != nil { + // fmt.Println("Error while committing span", err) + // // return nil, err + // } // No block rewards in PoA, so the state remains as is and uncles are dropped header.Root = state.IntermediateRoot(chain.Config().IsEIP158(header.Number)) @@ -671,7 +678,11 @@ func (c *Bor) Finalize(chain consensus.ChainReader, header *types.Header, state // nor block rewards given, and returns the final block. func (c *Bor) FinalizeAndAssemble(chain consensus.ChainReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, uncles []*types.Header, receipts []*types.Receipt) (*types.Block, error) { // commit span - // c.commitSpan(state, header, chainContext{Chain: chain, Bor: c}) + err := c.checkAndCommitSpan(state, header, chainContext{Chain: chain, Bor: c}) + if err != nil { + fmt.Println("Error while committing span", err) + // return nil, err + } // No block rewards in PoA, so the state remains as is and uncles are dropped header.Root = state.IntermediateRoot(chain.Config().IsEIP158(header.Number)) @@ -809,6 +820,92 @@ func (c *Bor) Close() error { return nil } +// Checks if new span is pending +func (c *Bor) isSpanPending(snapshotNumber uint64) (bool, error) { + blockNr := rpc.BlockNumber(snapshotNumber) + method := "spanProposalPending" + + // get packed data + data, err := c.validatorSetABI.Pack(method) + if err != nil { + fmt.Println("Unable to pack tx for spanProposalPending", "error", err) + return false, err + } + + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() // cancel when we are finished consuming integers + + // call + msgData := (hexutil.Bytes)(data) + toAddress := common.HexToAddress(c.config.ValidatorContract) + gas := (hexutil.Uint64)(uint64(math.MaxUint64 / 2)) + result, err := c.ethAPI.Call(ctx, ethapi.CallArgs{ + Gas: &gas, + To: &toAddress, + Data: &msgData, + }, blockNr) + if err != nil { + return false, err + } + + var ret0 = new(bool) + if err := c.validatorSetABI.Unpack(ret0, method, result); err != nil { + return false, err + } + + return *ret0, nil +} + +// GetCurrentSpan get current span from contract +func (c *Bor) GetCurrentSpan(snapshotNumber uint64) (*Span, error) { + // block + blockNr := rpc.BlockNumber(snapshotNumber) + + // method + method := "getCurrentSpan" + + data, err := c.validatorSetABI.Pack(method) + if err != nil { + fmt.Println("Unable to pack tx for getCurrentSpan", "error", err) + return nil, err + } + + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() // cancel when we are finished consuming integers + + // call + msgData := (hexutil.Bytes)(data) + toAddress := common.HexToAddress(c.config.ValidatorContract) + gas := (hexutil.Uint64)(uint64(math.MaxUint64 / 2)) + result, err := c.ethAPI.Call(ctx, ethapi.CallArgs{ + Gas: &gas, + To: &toAddress, + Data: &msgData, + }, blockNr) + if err != nil { + return nil, err + } + + // span result + ret := new(struct { + Number *big.Int + StartBlock *big.Int + EndBlock *big.Int + }) + if err := c.validatorSetABI.Unpack(ret, method, result); err != nil { + return nil, err + } + + // create new span + span := Span{ + ID: ret.Number.Uint64(), + StartBlock: ret.StartBlock.Uint64(), + EndBlock: ret.EndBlock.Uint64(), + } + + return &span, nil +} + // GetCurrentValidators get current validators func (c *Bor) GetCurrentValidators(snapshotNumber uint64, blockNumber uint64) ([]*Validator, error) { // block @@ -864,16 +961,90 @@ func (c *Bor) GetCurrentValidators(snapshotNumber uint64, blockNumber uint64) ([ return valz, nil } +func (c *Bor) checkAndCommitSpan( + state *state.StateDB, + header *types.Header, + chain core.ChainContext, +) error { + var pending bool = false + var span *Span = c.span + + var wg sync.WaitGroup + wg.Add(1) + go func() { + pending, _ = c.isSpanPending(header.Number.Uint64()) + wg.Done() + }() + + // fetch if span is nil + if span == nil { + wg.Add(1) + go func() { + fmt.Println("Fetching current span") + span, _ = c.GetCurrentSpan(header.Number.Uint64() - 1) + c.span = span // store in cache + wg.Done() + }() + } + wg.Wait() + + // commit span if there is new span pending or span is ending or end block is not set + if pending || (span != nil && (span.EndBlock == 0 || span.EndBlock == header.Number.Uint64())) { + err := c.commitSpan(span, state, header, chain) + c.span = nil // reset cache + return err + } + + return nil +} + func (c *Bor) commitSpan( + span *Span, state *state.StateDB, header *types.Header, chain core.ChainContext, ) error { + response, err := FetchFromHeimdall(c.httpClient, c.chainConfig.Bor.Heimdall, "bor", "span", strconv.FormatUint(span.ID+1, 10)) + if err != nil { + return err + } + + var heimdallSpan HeimdallSpan + if err := json.Unmarshal(response.Result, &heimdallSpan); err != nil { + return err + } + + // get validators bytes + var validators []MinimalVal + for _, val := range heimdallSpan.ValidatorSet.Validators { + validators = append(validators, val.MinimalVal()) + } + validatorsBytes, err := rlp.EncodeToBytes(validators) + if err != nil { + return err + } + + // get producers bytes + var producers []MinimalVal + for _, val := range heimdallSpan.SelectedProducers { + producers = append(validators, val.MinimalVal()) + } + producersBytes, err := rlp.EncodeToBytes(producers) + if err != nil { + return err + } + // method method := "commitSpan" // get packed data - data, err := c.validatorSetABI.Pack(method) + data, err := c.validatorSetABI.Pack(method, + heimdallSpan.ID, + heimdallSpan.StartBlock, + heimdallSpan.EndBlock, + validatorsBytes, + producersBytes, + ) if err != nil { fmt.Println("Unable to pack tx for commitSpan", "error", err) return err diff --git a/consensus/bor/rest.go b/consensus/bor/rest.go new file mode 100644 index 0000000000000000000000000000000000000000..d805f2c4193d2e834c9d75cbecf43751df10321c --- /dev/null +++ b/consensus/bor/rest.go @@ -0,0 +1,58 @@ +package bor + +import ( + "encoding/json" + "fmt" + "io/ioutil" + "net/http" + "net/url" + "path" +) + +// ResponseWithHeight defines a response object type that wraps an original +// response with a height. +type ResponseWithHeight struct { + Height string `json:"height"` + Result json.RawMessage `json:"result"` +} + +// FetchFromHeimdall returns data from heimdall +func FetchFromHeimdall(client http.Client, urlString string, paths ...string) (*ResponseWithHeight, error) { + u, err := url.Parse(urlString) + if err != nil { + return nil, err + } + + for _, e := range paths { + if e != "" { + u.Path = path.Join(u.Path, e) + } + } + + res, err := client.Get(u.String()) + if err != nil { + return nil, err + } + defer res.Body.Close() + + // check status code + if res.StatusCode != 200 { + return nil, fmt.Errorf("Error while fetching data from Heimdall") + } + + // get response + body, err := ioutil.ReadAll(res.Body) + if err != nil { + return nil, err + } + + // unmarshall data from buffer + var response ResponseWithHeight + fmt.Println("body", string(body)) + if err := json.Unmarshal(body, &response); err != nil { + return nil, err + } + + fmt.Println("response", response.Result) + return &response, nil +} diff --git a/consensus/bor/snapshot.go b/consensus/bor/snapshot.go index b55fa8c9ea8c0b6d6c6454d5b2af76e51a498dda..2583bd97b89da461295fd54dc75bdbcc6e49b958 100644 --- a/consensus/bor/snapshot.go +++ b/consensus/bor/snapshot.go @@ -29,22 +29,6 @@ import ( lru "github.com/hashicorp/golang-lru" ) -// Vote represents a single vote that an authorized signer made to modify the -// list of authorizations. -type Vote struct { - Signer common.Address `json:"signer"` // Authorized signer that cast this vote - Block uint64 `json:"block"` // Block number the vote was cast in (expire old votes) - Address common.Address `json:"address"` // Account being voted on to change its authorization - Authorize bool `json:"authorize"` // Whether to authorize or deauthorize the voted account -} - -// Tally is a simple vote tally to keep the current score of votes. Votes that -// go against the proposal aren't counted since it's equivalent to not voting. -type Tally struct { - Authorize bool `json:"authorize"` // Whether the vote is about authorizing or kicking someone - Votes int `json:"votes"` // Number of votes until now wanting to pass the proposal -} - // Snapshot is the state of the authorization voting at a given point in time. type Snapshot struct { config *params.BorConfig // Consensus engine parameters to fine tune behavior @@ -55,8 +39,6 @@ type Snapshot struct { Hash common.Hash `json:"hash"` // Block hash where the snapshot was created ValidatorSet *ValidatorSet `json:"validatorSet"` // Validator set at this moment Recents map[uint64]common.Address `json:"recents"` // Set of recent signers for spam protections - // Votes []*Vote `json:"votes"` // List of votes cast in chronological order - // Tally map[common.Address]Tally `json:"tally"` // Current vote tally to avoid recalculating } // signersAscending implements the sort interface to allow sorting a list of addresses @@ -69,7 +51,14 @@ func (s signersAscending) Swap(i, j int) { s[i], s[j] = s[j], s[i] } // newSnapshot creates a new snapshot with the specified startup parameters. This // method does not initialize the set of recent signers, so only ever use if for // the genesis block. -func newSnapshot(config *params.BorConfig, sigcache *lru.ARCCache, number uint64, hash common.Hash, validators []*Validator, ethAPI *ethapi.PublicBlockChainAPI) *Snapshot { +func newSnapshot( + config *params.BorConfig, + sigcache *lru.ARCCache, + number uint64, + hash common.Hash, + validators []*Validator, + ethAPI *ethapi.PublicBlockChainAPI, +) *Snapshot { snap := &Snapshot{ config: config, ethAPI: ethAPI, @@ -78,7 +67,6 @@ func newSnapshot(config *params.BorConfig, sigcache *lru.ARCCache, number uint64 Hash: hash, ValidatorSet: NewValidatorSet(validators), Recents: make(map[uint64]common.Address), - // Tally: make(map[common.Address]Tally), } return snap } @@ -122,8 +110,6 @@ func (s *Snapshot) copy() *Snapshot { Hash: s.Hash, ValidatorSet: s.ValidatorSet.Copy(), Recents: make(map[uint64]common.Address), - // Votes: make([]*Vote, len(s.Votes)), - // Tally: make(map[common.Address]Tally), } for block, signer := range s.Recents { cpy.Recents[block] = signer @@ -208,15 +194,20 @@ func (s *Snapshot) apply(headers []*types.Header) (*Snapshot, error) { return nil, err } + fmt.Println(" validator set change ", number) + // change validator set and change proposer if number > 0 && (number+1)%s.config.Sprint == 0 { validatorBytes := header.Extra[extraVanity : len(header.Extra)-extraSeal] - // newVals, _ := GetValidators(number, number+1, s.config.Sprint, s.config.ValidatorContract, snap.ethAPI) + // get validators from headers and use that for new validator set newVals, _ := ParseValidators(validatorBytes) v := getUpdatedValidatorSet(snap.ValidatorSet.Copy(), newVals) v.IncrementProposerPriority(1) snap.ValidatorSet = v + + // log new validator set + fmt.Println("Current validator set", "number", snap.Number, "validatorSet", snap.ValidatorSet) } // check if signer is in validator set @@ -258,8 +249,6 @@ func (s *Snapshot) apply(headers []*types.Header) (*Snapshot, error) { snap.Number += uint64(len(headers)) snap.Hash = headers[len(headers)-1].Hash() - fmt.Println("Current validator set", "number", snap.Number, "validatorSet", snap.ValidatorSet) - return snap, nil } diff --git a/consensus/bor/span.go b/consensus/bor/span.go new file mode 100644 index 0000000000000000000000000000000000000000..6da0df7ea7353fe9446258735488f9e43191cd6d --- /dev/null +++ b/consensus/bor/span.go @@ -0,0 +1,16 @@ +package bor + +// Span represents a current bor span +type Span struct { + ID uint64 `json:"span_id" yaml:"span_id"` + StartBlock uint64 `json:"start_block" yaml:"start_block"` + EndBlock uint64 `json:"end_block" yaml:"end_block"` +} + +// HeimdallSpan represents +type HeimdallSpan struct { + Span + ValidatorSet ValidatorSet `json:"validator_set" yaml:"validator_set"` + SelectedProducers []Validator `json:"selected_producers" yaml:"selected_producers"` + ChainID string `json:"bor_chain_id" yaml:"bor_chain_id"` +} diff --git a/consensus/bor/validator.go b/consensus/bor/validator.go index 32934ea2d4ab96cd128f7bc3c7edf0b4e0360d01..50b4a58ae4655e131ac7df280327555ce8b27bfe 100644 --- a/consensus/bor/validator.go +++ b/consensus/bor/validator.go @@ -6,20 +6,23 @@ import ( "errors" "fmt" "math/big" + "sort" "strings" "github.com/ethereum/go-ethereum/common" ) -// Volatile state for each Validator +// Validator represets Volatile state for each Validator // NOTE: The ProposerPriority is not included in Validator.Hash(); // make sure to update that method if changes are made here type Validator struct { - Address common.Address `json:"address"` - VotingPower int64 `json:"voting_power"` - ProposerPriority int64 `json:"proposer_priority"` + ID uint64 `json:"ID"` + Address common.Address `json:"signer"` + VotingPower int64 `json:"power"` + ProposerPriority int64 `json:"accum"` } +// NewValidator creates new validator func NewValidator(address common.Address, votingPower int64) *Validator { return &Validator{ Address: address, @@ -105,6 +108,15 @@ func (v *Validator) PowerBytes() []byte { return result } +// MinimalVal returns block number of last validator update +func (v *Validator) MinimalVal() MinimalVal { + return MinimalVal{ + ID: v.ID, + VotingPower: uint64(v.VotingPower), + Signer: v.Address, + } +} + // ParseValidators returns validator set bytes func ParseValidators(validatorsBytes []byte) ([]*Validator, error) { if len(validatorsBytes)%40 != 0 { @@ -124,3 +136,29 @@ func ParseValidators(validatorsBytes []byte) ([]*Validator, error) { return result, nil } + +// --- + +// MinimalVal is the minimal validator representation +// Used to send validator information to bor validator contract +type MinimalVal struct { + ID uint64 `json:"ID"` + VotingPower uint64 `json:"power"` // TODO add 10^-18 here so that we dont overflow easily + Signer common.Address `json:"signer"` +} + +// SortMinimalValByAddress sorts validators +func SortMinimalValByAddress(a []MinimalVal) []MinimalVal { + sort.Slice(a, func(i, j int) bool { + return bytes.Compare(a[i].Signer.Bytes(), a[j].Signer.Bytes()) < 0 + }) + return a +} + +// ValidatorsToMinimalValidators converts array of validators to minimal validators +func ValidatorsToMinimalValidators(vals []Validator) (minVals []MinimalVal) { + for _, val := range vals { + minVals = append(minVals, val.MinimalVal()) + } + return +} diff --git a/contracts/validatorset/contract/ValidatorSet.abi b/contracts/validatorset/contract/ValidatorSet.abi deleted file mode 100644 index 367a36292d34c8ffd3db0d830b5d930c99593afc..0000000000000000000000000000000000000000 --- a/contracts/validatorset/contract/ValidatorSet.abi +++ /dev/null @@ -1 +0,0 @@ -[{"constant":false,"inputs":[],"name":"finalizeChange","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getValidators","outputs":[{"name":"","type":"address[]"},{"name":"","type":"uint256[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"validator","type":"address"},{"name":"blockNumber","type":"uint256"},{"name":"proof","type":"bytes"}],"name":"reportMalicious","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"validator","type":"address"},{"name":"blockNumber","type":"uint256"}],"name":"reportBenign","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_parentHash","type":"bytes32"},{"indexed":false,"name":"_newSet","type":"address[]"}],"name":"InitiateChange","type":"event"}] \ No newline at end of file diff --git a/contracts/validatorset/contract/ValidatorSet.bin b/contracts/validatorset/contract/ValidatorSet.bin deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/contracts/validatorset/contract/ValidatorSet.sol b/contracts/validatorset/contract/ValidatorSet.sol deleted file mode 100644 index df23c1d369998aed8299d4bf2469cba30c85851d..0000000000000000000000000000000000000000 --- a/contracts/validatorset/contract/ValidatorSet.sol +++ /dev/null @@ -1,15 +0,0 @@ -pragma solidity 0.5.9; - -interface ValidatorSet { - /// Get initial validator set - function getInitialValidators() - external - view - returns (address[] memory, uint256[] memory); - - /// Get current validator set (last enacted or initial if no changes ever made) with current stake. - function getValidators() - external - view - returns (address[] memory, uint256[] memory); -} \ No newline at end of file diff --git a/contracts/validatorset/validatorset.go b/contracts/validatorset/validatorset.go deleted file mode 100644 index c64bf8614c34bf9d783e58ac27177ed09d684046..0000000000000000000000000000000000000000 --- a/contracts/validatorset/validatorset.go +++ /dev/null @@ -1,399 +0,0 @@ -// Code generated - DO NOT EDIT. -// This file is a generated binding and any manual changes will be lost. - -package validatorset - -import ( - "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 ( - _ = big.NewInt - _ = strings.NewReader - _ = ethereum.NotFound - _ = abi.U256 - _ = bind.Bind - _ = common.Big1 - _ = types.BloomLookup - _ = event.NewSubscription -) - -// ValidatorsetABI is the input ABI used to generate the binding from. -const ValidatorsetABI = "[{\"constant\":false,\"inputs\":[],\"name\":\"finalizeChange\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"getValidators\",\"outputs\":[{\"name\":\"\",\"type\":\"address[]\"},{\"name\":\"\",\"type\":\"uint256[]\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"validator\",\"type\":\"address\"},{\"name\":\"blockNumber\",\"type\":\"uint256\"},{\"name\":\"proof\",\"type\":\"bytes\"}],\"name\":\"reportMalicious\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"validator\",\"type\":\"address\"},{\"name\":\"blockNumber\",\"type\":\"uint256\"}],\"name\":\"reportBenign\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"name\":\"_parentHash\",\"type\":\"bytes32\"},{\"indexed\":false,\"name\":\"_newSet\",\"type\":\"address[]\"}],\"name\":\"InitiateChange\",\"type\":\"event\"}]" - -// Validatorset is an auto generated Go binding around an Ethereum contract. -type Validatorset struct { - ValidatorsetCaller // Read-only binding to the contract - ValidatorsetTransactor // Write-only binding to the contract - ValidatorsetFilterer // Log filterer for contract events -} - -// ValidatorsetCaller is an auto generated read-only Go binding around an Ethereum contract. -type ValidatorsetCaller struct { - contract *bind.BoundContract // Generic contract wrapper for the low level calls -} - -// ValidatorsetTransactor is an auto generated write-only Go binding around an Ethereum contract. -type ValidatorsetTransactor struct { - contract *bind.BoundContract // Generic contract wrapper for the low level calls -} - -// ValidatorsetFilterer is an auto generated log filtering Go binding around an Ethereum contract events. -type ValidatorsetFilterer struct { - contract *bind.BoundContract // Generic contract wrapper for the low level calls -} - -// ValidatorsetSession is an auto generated Go binding around an Ethereum contract, -// with pre-set call and transact options. -type ValidatorsetSession struct { - Contract *Validatorset // 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 -} - -// ValidatorsetCallerSession is an auto generated read-only Go binding around an Ethereum contract, -// with pre-set call options. -type ValidatorsetCallerSession struct { - Contract *ValidatorsetCaller // Generic contract caller binding to set the session for - CallOpts bind.CallOpts // Call options to use throughout this session -} - -// ValidatorsetTransactorSession is an auto generated write-only Go binding around an Ethereum contract, -// with pre-set transact options. -type ValidatorsetTransactorSession struct { - Contract *ValidatorsetTransactor // Generic contract transactor binding to set the session for - TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session -} - -// ValidatorsetRaw is an auto generated low-level Go binding around an Ethereum contract. -type ValidatorsetRaw struct { - Contract *Validatorset // Generic contract binding to access the raw methods on -} - -// ValidatorsetCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. -type ValidatorsetCallerRaw struct { - Contract *ValidatorsetCaller // Generic read-only contract binding to access the raw methods on -} - -// ValidatorsetTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. -type ValidatorsetTransactorRaw struct { - Contract *ValidatorsetTransactor // Generic write-only contract binding to access the raw methods on -} - -// NewValidatorset creates a new instance of Validatorset, bound to a specific deployed contract. -func NewValidatorset(address common.Address, backend bind.ContractBackend) (*Validatorset, error) { - contract, err := bindValidatorset(address, backend, backend, backend) - if err != nil { - return nil, err - } - return &Validatorset{ValidatorsetCaller: ValidatorsetCaller{contract: contract}, ValidatorsetTransactor: ValidatorsetTransactor{contract: contract}, ValidatorsetFilterer: ValidatorsetFilterer{contract: contract}}, nil -} - -// NewValidatorsetCaller creates a new read-only instance of Validatorset, bound to a specific deployed contract. -func NewValidatorsetCaller(address common.Address, caller bind.ContractCaller) (*ValidatorsetCaller, error) { - contract, err := bindValidatorset(address, caller, nil, nil) - if err != nil { - return nil, err - } - return &ValidatorsetCaller{contract: contract}, nil -} - -// NewValidatorsetTransactor creates a new write-only instance of Validatorset, bound to a specific deployed contract. -func NewValidatorsetTransactor(address common.Address, transactor bind.ContractTransactor) (*ValidatorsetTransactor, error) { - contract, err := bindValidatorset(address, nil, transactor, nil) - if err != nil { - return nil, err - } - return &ValidatorsetTransactor{contract: contract}, nil -} - -// NewValidatorsetFilterer creates a new log filterer instance of Validatorset, bound to a specific deployed contract. -func NewValidatorsetFilterer(address common.Address, filterer bind.ContractFilterer) (*ValidatorsetFilterer, error) { - contract, err := bindValidatorset(address, nil, nil, filterer) - if err != nil { - return nil, err - } - return &ValidatorsetFilterer{contract: contract}, nil -} - -// bindValidatorset binds a generic wrapper to an already deployed contract. -func bindValidatorset(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { - parsed, err := abi.JSON(strings.NewReader(ValidatorsetABI)) - 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 (_Validatorset *ValidatorsetRaw) Call(opts *bind.CallOpts, result interface{}, method string, params ...interface{}) error { - return _Validatorset.Contract.ValidatorsetCaller.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 (_Validatorset *ValidatorsetRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { - return _Validatorset.Contract.ValidatorsetTransactor.contract.Transfer(opts) -} - -// Transact invokes the (paid) contract method with params as input values. -func (_Validatorset *ValidatorsetRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { - return _Validatorset.Contract.ValidatorsetTransactor.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 (_Validatorset *ValidatorsetCallerRaw) Call(opts *bind.CallOpts, result interface{}, method string, params ...interface{}) error { - return _Validatorset.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 (_Validatorset *ValidatorsetTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { - return _Validatorset.Contract.contract.Transfer(opts) -} - -// Transact invokes the (paid) contract method with params as input values. -func (_Validatorset *ValidatorsetTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { - return _Validatorset.Contract.contract.Transact(opts, method, params...) -} - -// GetValidators is a free data retrieval call binding the contract method 0xb7ab4db5. -// -// Solidity: function getValidators() constant returns(address[], uint256[]) -func (_Validatorset *ValidatorsetCaller) GetValidators(opts *bind.CallOpts) ([]common.Address, []*big.Int, error) { - var ( - ret0 = new([]common.Address) - ret1 = new([]*big.Int) - ) - out := &[]interface{}{ - ret0, - ret1, - } - err := _Validatorset.contract.Call(opts, out, "getValidators") - return *ret0, *ret1, err -} - -// GetValidators is a free data retrieval call binding the contract method 0xb7ab4db5. -// -// Solidity: function getValidators() constant returns(address[], uint256[]) -func (_Validatorset *ValidatorsetSession) GetValidators() ([]common.Address, []*big.Int, error) { - return _Validatorset.Contract.GetValidators(&_Validatorset.CallOpts) -} - -// GetValidators is a free data retrieval call binding the contract method 0xb7ab4db5. -// -// Solidity: function getValidators() constant returns(address[], uint256[]) -func (_Validatorset *ValidatorsetCallerSession) GetValidators() ([]common.Address, []*big.Int, error) { - return _Validatorset.Contract.GetValidators(&_Validatorset.CallOpts) -} - -// FinalizeChange is a paid mutator transaction binding the contract method 0x75286211. -// -// Solidity: function finalizeChange() returns() -func (_Validatorset *ValidatorsetTransactor) FinalizeChange(opts *bind.TransactOpts) (*types.Transaction, error) { - return _Validatorset.contract.Transact(opts, "finalizeChange") -} - -// FinalizeChange is a paid mutator transaction binding the contract method 0x75286211. -// -// Solidity: function finalizeChange() returns() -func (_Validatorset *ValidatorsetSession) FinalizeChange() (*types.Transaction, error) { - return _Validatorset.Contract.FinalizeChange(&_Validatorset.TransactOpts) -} - -// FinalizeChange is a paid mutator transaction binding the contract method 0x75286211. -// -// Solidity: function finalizeChange() returns() -func (_Validatorset *ValidatorsetTransactorSession) FinalizeChange() (*types.Transaction, error) { - return _Validatorset.Contract.FinalizeChange(&_Validatorset.TransactOpts) -} - -// ReportBenign is a paid mutator transaction binding the contract method 0xd69f13bb. -// -// Solidity: function reportBenign(address validator, uint256 blockNumber) returns() -func (_Validatorset *ValidatorsetTransactor) ReportBenign(opts *bind.TransactOpts, validator common.Address, blockNumber *big.Int) (*types.Transaction, error) { - return _Validatorset.contract.Transact(opts, "reportBenign", validator, blockNumber) -} - -// ReportBenign is a paid mutator transaction binding the contract method 0xd69f13bb. -// -// Solidity: function reportBenign(address validator, uint256 blockNumber) returns() -func (_Validatorset *ValidatorsetSession) ReportBenign(validator common.Address, blockNumber *big.Int) (*types.Transaction, error) { - return _Validatorset.Contract.ReportBenign(&_Validatorset.TransactOpts, validator, blockNumber) -} - -// ReportBenign is a paid mutator transaction binding the contract method 0xd69f13bb. -// -// Solidity: function reportBenign(address validator, uint256 blockNumber) returns() -func (_Validatorset *ValidatorsetTransactorSession) ReportBenign(validator common.Address, blockNumber *big.Int) (*types.Transaction, error) { - return _Validatorset.Contract.ReportBenign(&_Validatorset.TransactOpts, validator, blockNumber) -} - -// ReportMalicious is a paid mutator transaction binding the contract method 0xc476dd40. -// -// Solidity: function reportMalicious(address validator, uint256 blockNumber, bytes proof) returns() -func (_Validatorset *ValidatorsetTransactor) ReportMalicious(opts *bind.TransactOpts, validator common.Address, blockNumber *big.Int, proof []byte) (*types.Transaction, error) { - return _Validatorset.contract.Transact(opts, "reportMalicious", validator, blockNumber, proof) -} - -// ReportMalicious is a paid mutator transaction binding the contract method 0xc476dd40. -// -// Solidity: function reportMalicious(address validator, uint256 blockNumber, bytes proof) returns() -func (_Validatorset *ValidatorsetSession) ReportMalicious(validator common.Address, blockNumber *big.Int, proof []byte) (*types.Transaction, error) { - return _Validatorset.Contract.ReportMalicious(&_Validatorset.TransactOpts, validator, blockNumber, proof) -} - -// ReportMalicious is a paid mutator transaction binding the contract method 0xc476dd40. -// -// Solidity: function reportMalicious(address validator, uint256 blockNumber, bytes proof) returns() -func (_Validatorset *ValidatorsetTransactorSession) ReportMalicious(validator common.Address, blockNumber *big.Int, proof []byte) (*types.Transaction, error) { - return _Validatorset.Contract.ReportMalicious(&_Validatorset.TransactOpts, validator, blockNumber, proof) -} - -// ValidatorsetInitiateChangeIterator is returned from FilterInitiateChange and is used to iterate over the raw logs and unpacked data for InitiateChange events raised by the Validatorset contract. -type ValidatorsetInitiateChangeIterator struct { - Event *ValidatorsetInitiateChange // Event containing the contract specifics and raw log - - contract *bind.BoundContract // Generic contract to use for unpacking event data - event string // Event name to use for unpacking event data - - logs chan types.Log // Log channel receiving the found contract events - sub ethereum.Subscription // Subscription for errors, completion and termination - done bool // Whether the subscription completed delivering logs - fail error // Occurred error to stop iteration -} - -// Next advances the iterator to the subsequent event, returning whether there -// are any more events found. In case of a retrieval or parsing error, false is -// returned and Error() can be queried for the exact failure. -func (it *ValidatorsetInitiateChangeIterator) Next() bool { - // If the iterator failed, stop iterating - if it.fail != nil { - return false - } - // If the iterator completed, deliver directly whatever's available - if it.done { - select { - case log := <-it.logs: - it.Event = new(ValidatorsetInitiateChange) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - default: - return false - } - } - // Iterator still in progress, wait for either a data or an error event - select { - case log := <-it.logs: - it.Event = new(ValidatorsetInitiateChange) - if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { - it.fail = err - return false - } - it.Event.Raw = log - return true - - case err := <-it.sub.Err(): - it.done = true - it.fail = err - return it.Next() - } -} - -// Error returns any retrieval or parsing error occurred during filtering. -func (it *ValidatorsetInitiateChangeIterator) Error() error { - return it.fail -} - -// Close terminates the iteration process, releasing any pending underlying -// resources. -func (it *ValidatorsetInitiateChangeIterator) Close() error { - it.sub.Unsubscribe() - return nil -} - -// ValidatorsetInitiateChange represents a InitiateChange event raised by the Validatorset contract. -type ValidatorsetInitiateChange struct { - ParentHash [32]byte - NewSet []common.Address - Raw types.Log // Blockchain specific contextual infos -} - -// FilterInitiateChange is a free log retrieval operation binding the contract event 0x55252fa6eee4741b4e24a74a70e9c11fd2c2281df8d6ea13126ff845f7825c89. -// -// Solidity: event InitiateChange(bytes32 indexed _parentHash, address[] _newSet) -func (_Validatorset *ValidatorsetFilterer) FilterInitiateChange(opts *bind.FilterOpts, _parentHash [][32]byte) (*ValidatorsetInitiateChangeIterator, error) { - - var _parentHashRule []interface{} - for _, _parentHashItem := range _parentHash { - _parentHashRule = append(_parentHashRule, _parentHashItem) - } - - logs, sub, err := _Validatorset.contract.FilterLogs(opts, "InitiateChange", _parentHashRule) - if err != nil { - return nil, err - } - return &ValidatorsetInitiateChangeIterator{contract: _Validatorset.contract, event: "InitiateChange", logs: logs, sub: sub}, nil -} - -// WatchInitiateChange is a free log subscription operation binding the contract event 0x55252fa6eee4741b4e24a74a70e9c11fd2c2281df8d6ea13126ff845f7825c89. -// -// Solidity: event InitiateChange(bytes32 indexed _parentHash, address[] _newSet) -func (_Validatorset *ValidatorsetFilterer) WatchInitiateChange(opts *bind.WatchOpts, sink chan<- *ValidatorsetInitiateChange, _parentHash [][32]byte) (event.Subscription, error) { - - var _parentHashRule []interface{} - for _, _parentHashItem := range _parentHash { - _parentHashRule = append(_parentHashRule, _parentHashItem) - } - - logs, sub, err := _Validatorset.contract.WatchLogs(opts, "InitiateChange", _parentHashRule) - if err != nil { - return nil, err - } - return event.NewSubscription(func(quit <-chan struct{}) error { - defer sub.Unsubscribe() - for { - select { - case log := <-logs: - // New log arrived, parse the event and forward to the user - event := new(ValidatorsetInitiateChange) - if err := _Validatorset.contract.UnpackLog(event, "InitiateChange", log); err != nil { - return err - } - event.Raw = log - - select { - case sink <- event: - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - case err := <-sub.Err(): - return err - case <-quit: - return nil - } - } - }), nil -}