Skip to content

Commit

Permalink
Various fixes (autonity#943)
Browse files Browse the repository at this point in the history
* Fix genesis committee

With more validators configured in the genesis file
the resulting committee was inconsistent.

Signed-off-by: Youssef Azzaoui <[email protected]>

* Large scale internal testing

Signed-off-by: Youssef Azzaoui <[email protected]>

* Add concurrency when updating consensus enode

* Fix potential panic in fault detector

* Rework consensus message handling flow

* Large network e2e tests improvements

* Add verifypop command to ethkey

* Review comments

* AutInspect ethkey command

---------

Signed-off-by: Youssef Azzaoui <[email protected]>
Signed-off-by: Youssef Azzaoui <[email protected]>
  • Loading branch information
yazzaoui authored Feb 22, 2024
1 parent 8b4a17c commit 4b841aa
Show file tree
Hide file tree
Showing 19 changed files with 1,053 additions and 622 deletions.
3 changes: 1 addition & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -118,8 +118,7 @@ $(GOBINDATA_BINARY):
$(ABIGEN_BINARY):
go build -o $(ABIGEN_BINARY) ./cmd/abigen

all: contracts
make bindings
all: $(ABIGEN_BINARY) contracts
go run build/ci.go install

android:
Expand Down
4 changes: 4 additions & 0 deletions autonity/autonity.go
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,10 @@ func (c *AutonityContract) CommitteeEnodes(block *types.Block, db vm.StateDB, as
return c.callGetCommitteeEnodes(db, block.Header(), asACN)
}

func (c *AutonityContract) Committee(header *types.Header, db vm.StateDB) ([]types.CommitteeMember, error) {
return c.callGetCommittee(db, header)
}

func (c *AutonityContract) MinimumBaseFee(block *types.Header, db vm.StateDB) (*big.Int, error) {
if block.Number.Uint64() <= 1 {
return new(big.Int).SetUint64(c.chainConfig.AutonityContractConfig.MinBaseFee), nil
Expand Down
6 changes: 6 additions & 0 deletions autonity/calls.go
Original file line number Diff line number Diff line change
Expand Up @@ -388,6 +388,12 @@ func (c *AutonityContract) callGetCommitteeEnodes(state vm.StateDB, header *type
return types.NewNodes(returnedEnodes, asACN), nil
}

func (c *AutonityContract) callGetCommittee(state vm.StateDB, header *types.Header) ([]types.CommitteeMember, error) {
var committee []types.CommitteeMember
err := c.AutonityContractCall(state, header, "getCommittee", &committee)
return committee, err
}

func (c *AutonityContract) callGetMinimumBaseFee(state vm.StateDB, header *types.Header) (*big.Int, error) {
minBaseFee := new(big.Int)
err := c.AutonityContractCall(state, header, "getMinimumBaseFee", &minBaseFee)
Expand Down
5 changes: 3 additions & 2 deletions cmd/autonity/consolecmd_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ package main

import (
"crypto/rand"
"github.com/autonity/autonity/crypto"
"io/ioutil"
"math/big"
"os"
Expand All @@ -29,6 +28,8 @@ import (
"testing"
"time"

"github.com/autonity/autonity/crypto"

"github.com/autonity/autonity/params"
)

Expand Down Expand Up @@ -110,7 +111,7 @@ func tmpDataDirWithGenesisFile(t *testing.T) (dir string, genesisFile string) {
}

func getCoinBase(t *testing.T, datadir string) string {
keyfile := filepath.Join(datadir, "autonity", "nodekey")
keyfile := filepath.Join(datadir, "autonity", "autonitykeys")
key, _, err := crypto.LoadAutonityKeys(keyfile)
if err != nil {
t.Fatalf("cannot get node key with error: %v", err)
Expand Down
70 changes: 70 additions & 0 deletions cmd/ethkey/autinspect.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package main

import (
"encoding/hex"
"fmt"

"gopkg.in/urfave/cli.v1"

"github.com/autonity/autonity/cmd/utils"
"github.com/autonity/autonity/common/hexutil"
"github.com/autonity/autonity/crypto"
)

type outputAutInspect struct {
NodePublicKey string
NodeAddress string
NodePrivateKey string `json:",omitempty"`
ConsensusPublicKey string
ConsensusPrivateKey string `json:",omitempty"`
}

var commandAutInspect = cli.Command{
Name: "autinspect",
Usage: "inspect autonity keys file",
ArgsUsage: "<keyfile>",
Description: `
Print various information about the autonity keyfile.
Private key information can be printed by using the --private flag;
make sure to use this feature with great caution!`,
Flags: []cli.Flag{
jsonFlag,
cli.BoolFlag{
Name: "private",
Usage: "include the private keys in the output",
},
},
Action: func(ctx *cli.Context) error {
if ctx.NArg() != 1 {
fmt.Println("Incorrect number of arguments, 1 expected.")
cli.ShowCommandHelpAndExit(ctx, "autinspect", 1)
}
nodeKey, consensusKey, err := crypto.LoadAutonityKeys(ctx.Args().Get(0))
if err != nil {
utils.Fatalf("error opening key file %v", err)
}
out := outputAutInspect{
NodePublicKey: hexutil.Encode(crypto.FromECDSAPub(&nodeKey.PublicKey)[1:]),
NodeAddress: crypto.PubkeyToAddress(nodeKey.PublicKey).String(),
ConsensusPublicKey: consensusKey.PublicKey().Hex(),
}
showPrivate := ctx.Bool("private")
if showPrivate {
out.ConsensusPrivateKey = hex.EncodeToString(consensusKey.Marshal())
out.NodePrivateKey = hex.EncodeToString(crypto.FromECDSA(nodeKey))
}
if ctx.Bool(jsonFlag.Name) {
mustPrintJSON(out)
} else {
fmt.Println("Node Address: ", out.NodeAddress)
fmt.Println("Node Public Key: ", out.NodePublicKey)
fmt.Println("Consensus Public Key: ", out.ConsensusPublicKey)
if showPrivate {
fmt.Println("Consensus Private Key: ", out.ConsensusPrivateKey)
fmt.Println("Node Private Key: ", out.NodePrivateKey)
}
}
return nil
},
}
5 changes: 4 additions & 1 deletion cmd/ethkey/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,10 @@ package main

import (
"fmt"
"github.com/autonity/autonity/internal/flags"
"os"

"github.com/autonity/autonity/internal/flags"

"gopkg.in/urfave/cli.v1"
)

Expand All @@ -42,6 +43,8 @@ func init() {
commandChangePassphrase,
commandSignMessage,
commandVerifyMessage,
commandAutInspect,
commandVerifyPOP,
}
cli.CommandHelpTemplate = flags.OriginCommandHelpTemplate
}
Expand Down
123 changes: 123 additions & 0 deletions cmd/ethkey/verifypop.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
package main

import (
"fmt"

"gopkg.in/urfave/cli.v1"

"github.com/autonity/autonity/accounts"
"github.com/autonity/autonity/cmd/utils"
"github.com/autonity/autonity/common"
"github.com/autonity/autonity/common/hexutil"
"github.com/autonity/autonity/crypto"
"github.com/autonity/autonity/crypto/blst"
enodes "github.com/autonity/autonity/p2p/enode"
)

type outputVerifyPOP struct {
NodeKeyPOP bool
OracleKeyPOP bool
ConsensusKeyPOP bool
}

var commandVerifyPOP = cli.Command{
Name: "verifypop",
Usage: "verify proof of possessions",
ArgsUsage: "<treasury> <enode> <oracle> <consensusKey> <proof>",
Description: `
Print if the proof of possession for registering a validator is valid or not. Use --json for a json output.`,
Flags: []cli.Flag{
jsonFlag,
},
Action: func(ctx *cli.Context) error {
// Checks arguments BEGIN
if ctx.NArg() != 5 {
fmt.Println("Incorrect number of arguments, 5 expected.")
cli.ShowCommandHelpAndExit(ctx, "verifypop", 1)
}
treasuryArg := ctx.Args().Get(0)
treasuryKey, err := hexutil.Decode(treasuryArg)
if err != nil {
utils.Fatalf("can't decode treasury key with error %v", err)
}

enodeArg := ctx.Args().Get(1)
node, err := enodes.ParseV4NoResolve(enodeArg)
if err != nil {
utils.Fatalf("can't parse enode %v", err)
}
oracleArg := ctx.Args().Get(2)
oracleKey, err := hexutil.Decode(oracleArg)
if err != nil {
utils.Fatalf("can't decode oracle key with error %v", err)
}

consensusKeyArg := ctx.Args().Get(3)
consensusKey, err := hexutil.Decode(consensusKeyArg)
if err != nil {
utils.Fatalf("can't decode consensus key with error %v", err)
}

signaturesArg := ctx.Args().Get(4)
signatures, err := hexutil.Decode(signaturesArg)
if err != nil {
utils.Fatalf("can't decode proof with error %v", err)
}
if len(signatures) != crypto.AutonityPOPLen {
utils.Fatalf("invalid proof size")
}
// Checks arguments END
out := outputVerifyPOP{
NodeKeyPOP: false,
OracleKeyPOP: false,
ConsensusKeyPOP: false,
}
// compute the hash (the signed message)
hash, _ := accounts.TextAndHash(treasuryKey)
//
// Step 1: node key pop
//
recoveredNodeKey, err := crypto.SigToPub(hash, signatures[:crypto.SignatureLength])
if err != nil {
utils.Fatalf("can't recover node key %v", err)
}
out.NodeKeyPOP = recoveredNodeKey.Equal(node.Pubkey())
//
// Step 2: oracle key pop
//
recoveredOracleAddress, err := crypto.SigToAddr(hash, signatures[crypto.SignatureLength:2*crypto.SignatureLength])
if err != nil {
utils.Fatalf("can't recover oracle key %v", err)
}
out.OracleKeyPOP = recoveredOracleAddress == common.BytesToAddress(oracleKey)

//
// Step 3: consensus\ key pop
//
key, err := blst.PublicKeyFromBytes(consensusKey)
if err != nil {
utils.Fatalf("invalid consensus key %v", err)
}
sig, err := blst.SignatureFromBytes(signatures[2*crypto.SignatureLength:])
if err != nil {
utils.Fatalf("can't recover signature key %v", err)
}
if sig.IsZero() {
utils.Fatalf("can't recover signature key %v", err)
}
err = crypto.BLSPOPVerify(key, sig, treasuryKey)
if err == nil {
out.ConsensusKeyPOP = true
}

if ctx.Bool(jsonFlag.Name) {
mustPrintJSON(out)
} else {
fmt.Println("===== POP Validation Results =====")
fmt.Println("Node Key: ", out.NodeKeyPOP)
fmt.Println("Oracle Key: ", out.OracleKeyPOP)
fmt.Println("Consensus Key: ", out.ConsensusKeyPOP)
}
return nil
},
}
4 changes: 2 additions & 2 deletions cmd/gengen/gengen/new_genesis.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,10 +92,10 @@ func NewGenesis(validators []*Validator, options ...GenesisOption) (*core.Genesi
// unmarshals to an empty slice.
ExtraData: []byte{},

GasLimit: 30_000_000, // gas limit setting in piccadilly network.
GasLimit: 1_000_000_000, // gas limit setting in piccadilly network.
//GasLimit: 10000000000, // gas limit in e2e test framework.

BaseFee: big.NewInt(15000000000),
BaseFee: new(big.Int).SetUint64(params.TestAutonityContractConfig.MinBaseFee),

// Autonity relies on the difficulty always being 1 so that we can
// compare chain length by comparing total difficulty during peer
Expand Down
2 changes: 1 addition & 1 deletion consensus/tendermint/accountability/fault_detector.go
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,7 @@ tendermintMsgLoop:
switch e := ev.Data.(type) {
case events.MessageEvent:
if fd.isMsgExpired(curHeight, e.Message.H()) {
fd.logger.Debug("Fault detector: discarding old message", "sender", e.Message.Sender())
fd.logger.Debug("Fault detector: discarding old message")
continue tendermintMsgLoop
}
if err := fd.processMsg(e.Message); err != nil && !errors.Is(err, errFutureMsg) {
Expand Down
35 changes: 18 additions & 17 deletions consensus/tendermint/backend/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"github.com/autonity/autonity/consensus"
"github.com/autonity/autonity/consensus/tendermint/core/message"
"github.com/autonity/autonity/consensus/tendermint/events"
"github.com/autonity/autonity/crypto"
"github.com/autonity/autonity/p2p"
)

Expand Down Expand Up @@ -108,23 +109,18 @@ func handleConsensusMsg[T any, PT interface {
*T
message.Msg
}](sb *Backend, sender common.Address, p2pMsg p2p.Msg, errCh chan<- error) (bool, error) {
buffer := bytes.NewBuffer(make([]byte, 0, p2pMsg.Size))
// We copy the message here as it can't be saved directly due to
// a call to Discard in the eth handler which is going to empty this buffer.
if _, err := io.Copy(buffer, p2pMsg.Payload); err != nil {
return true, err
}
p2pMsg.Payload = bytes.NewReader(buffer.Bytes())
if !sb.coreStarted {
// We copy the message here as it can't be saved directly due
// to a call to Discard in the eth handler which is going to empty this buffer.
buffer := bytes.NewBuffer(make([]byte, 0, p2pMsg.Size))
if _, err := io.Copy(buffer, p2pMsg.Payload); err != nil {
return true, errDecodeFailed
}
savedMsg := p2pMsg
savedMsg.Payload = bytes.NewReader(buffer.Bytes())
sb.pendingMessages.Enqueue(UnhandledMsg{addr: sender, msg: savedMsg})
sb.pendingMessages.Enqueue(UnhandledMsg{addr: sender, msg: p2pMsg})
return true, nil // return nil to avoid shutting down connection during block sync.
}
msg := PT(new(T))
if err := p2pMsg.Decode(msg); err != nil {
sb.logger.Error("Error decoding consensus message", "err", err)
return true, err
}
hash := crypto.Hash(buffer.Bytes())
// Mark peer's message as known.
ms, ok := sb.recentMessages.Get(sender)
var m *lru.ARCCache
Expand All @@ -134,12 +130,17 @@ func handleConsensusMsg[T any, PT interface {
m, _ = lru.NewARC(inmemoryMessages)
sb.recentMessages.Add(sender, m)
}
m.Add(msg.Hash(), true)
m.Add(hash, true)
// Mark the message known for ourselves
if _, ok := sb.knownMessages.Get(msg.Hash()); ok {
if _, ok := sb.knownMessages.Get(hash); ok {
return true, nil
}
sb.knownMessages.Add(msg.Hash(), true)
sb.knownMessages.Add(hash, true)
msg := PT(new(T))
if err := p2pMsg.Decode(msg); err != nil {
sb.logger.Error("Error decoding consensus message", "err", err)
return true, err
}
go sb.Post(events.MessageEvent{
Message: msg,
ErrCh: errCh,
Expand Down
2 changes: 2 additions & 0 deletions consensus/test/auto_mining_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ func TestAutoMiningForCommitteeMembers(t *testing.T) {

// test non-committee member validators should not start the mining workers.
func TestAutoMiningForNonCommitteeValidator(t *testing.T) {
t.Skip("broken, to fix or (better) port to new e2e framework")
numOfValidators := 2
testCase := &testCase{
name: "Auto mining test, non committee member should not start mining",
Expand All @@ -55,6 +56,7 @@ func TestAutoMiningForNonCommitteeValidator(t *testing.T) {

// test on committee seats rotation, new selected validators should start mining workers.
func TestAutoMiningForNewSelectedValidator(t *testing.T) {
t.Skip("discovery is broken for this framework")
numOfValidators := 2
operator, err := makeAccount()
require.NoError(t, err)
Expand Down
Loading

0 comments on commit 4b841aa

Please sign in to comment.