Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

vrfs attack Byzantine test #673

Merged
merged 16 commits into from Nov 4, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5 changes: 5 additions & 0 deletions bridge_wsl.ps1
@@ -0,0 +1,5 @@
$wsl_ip=wsl hostname -I
$port=15210 # conductor server port
netsh int ipv4 reset
netsh interface portproxy add v4tov4 listenport=$port listenaddress=0.0.0.0 connectport=$port connectaddress=$wsl_ip
echo "bridging $wsl_ip"
Expand Up @@ -170,7 +170,7 @@ func addMPTNode(r *http.Request) (*block.StateChange, error) {
sChain := GetServerChain()
bl, err := sChain.getNotarizedBlock(context.Background(), r.FormValue("round"), r.FormValue("block"))
if err != nil {
log.Panicf("Conductor: error while fetching notarized block: %v")
log.Panicf("Conductor: error while fetching notarized block: %v", err)
}

bsc, err := block.NewBlockStateChange(bl)
Expand Down
Expand Up @@ -6,14 +6,14 @@ package chain
import (
"log"

"go.uber.org/zap"

"0chain.net/chaincore/block"
"0chain.net/chaincore/node"
"0chain.net/chaincore/round"
"0chain.net/conductor/cases"
crpc "0chain.net/conductor/conductrpc"
"github.com/0chain/common/core/logging"

"go.uber.org/zap"
)

func (c *Chain) FinalizeRound(r round.RoundI) {
Expand Down Expand Up @@ -84,6 +84,7 @@ func GetNodeTypeAndTypeRank(roundNum int64) (nodeType, typeRank int) {
}
return nodeType, typeRank
}

func AddRoundInfoResult(r round.RoundI, finalisedBlockHash string) error {
res := roundInfo(r.GetRoundNumber(), finalisedBlockHash)
blob, err := res.Encode()
Expand Down
49 changes: 49 additions & 0 deletions code/go/0chain.net/chaincore/chain/utils_integration_tests.go
@@ -0,0 +1,49 @@
//go:build integration_tests
// +build integration_tests

package chain

import (
"0chain.net/chaincore/node"
crpc "0chain.net/conductor/conductrpc"
"0chain.net/conductor/config/cases"
)

// SplitGoodAndBadNodes nodes list by given IsGoodOrBad.
func SplitGoodAndBadNodes(s *crpc.State, igb crpc.IsGoodOrBad, nodes []*node.Node) (
good, bad []*node.Node) {

for _, n := range nodes {
if igb.IsBad(s, n.GetKey()) {
bad = append(bad, n)
} else if igb.IsGood(s, n.GetKey()) {
good = append(good, n)
}
}
return
}

// IsSpammer checks whether a node is a spammer.
// A list of spammers names with format "miner-x" are passed, then the x is extracted and compared with the node index.
func IsSpammer(spammers []cases.NodeTypeTypeRank, roundNum int64) (isSpammer bool) {
peterlimg marked this conversation as resolved.
Show resolved Hide resolved
isSpammer = false

nodeType, typeRank := GetNodeTypeAndTypeRank(roundNum)

for _, spammer := range spammers {
if spammer.NodeType == nodeType && spammer.TypeRank == typeRank {
return true
}
}

return
}

// IsSpamReceiver checks whether a node is the spam receiver set in the round_has_finalized configuration.
func IsSpamReceiver(state *crpc.State, roundNum int64) (isSpamReceiver bool) {
isSpamReceiver = false

nodeType, typeRank := GetNodeTypeAndTypeRank(roundNum)

return state.RoundHasFinalizedConfig.SpammingReceiver.NodeType == nodeType && state.RoundHasFinalizedConfig.SpammingReceiver.TypeRank == typeRank
}
84 changes: 84 additions & 0 deletions code/go/0chain.net/conductor/cases/round_has_finalized.go
@@ -0,0 +1,84 @@
package cases

import (
"context"
"errors"
"fmt"
"strconv"
)

type (
// RoundHasFinalized represents implementation of the TestCase interface.
RoundHasFinalized struct {
res *RoundInfo

roundID int

prepared chan struct{}
}
)

var (
// Ensure RoundHasFinalized implements TestCase interface.
_ TestCase = (*RoundHasFinalized)(nil)
)

// NewRoundHasFinalized creates initialised RoundHasFinalized.
func NewRoundHasFinalized() *RoundHasFinalized {
return &RoundHasFinalized{
prepared: make(chan struct{}),
}
}

// Check implements TestCase interface.
func (n *RoundHasFinalized) Check(ctx context.Context) (success bool, err error) {
select {
case <-ctx.Done():
return false, errors.New("cases state is not prepared, context is done")

case <-n.prepared:
return n.check()
}
}

func (n *RoundHasFinalized) check() (success bool, err error) {
if !n.res.IsFinalised {
return false, errors.New("expected the round to be finalised")
}

return true, nil
}

// Configure implements TestCase interface.
func (n *RoundHasFinalized) Configure(blob []byte) error {
roundIDStr := string(blob)

roundID, err := strconv.Atoi(roundIDStr)
if err != nil {
return err
}

n.roundID = roundID

return nil
}

// AddResult implements TestCase interface.
func (n *RoundHasFinalized) AddResult(blob []byte) error {
roundInfo := &RoundInfo{}

if err := roundInfo.Decode(blob); err != nil {
return err
}

fmt.Printf("adding result -> %+v %+v\n", roundInfo, n.roundID)

if roundInfo.Num == int64(n.roundID) && (n.res == nil || n.res.Num == 0) {
defer func() {
n.prepared <- struct{}{}
}()
n.res = roundInfo
}

return nil
}
5 changes: 5 additions & 0 deletions code/go/0chain.net/conductor/conductor/executor.go
Expand Up @@ -864,6 +864,9 @@ func (r *Runner) ConfigureTestCase(configurator cases.TestCaseConfigurator) erro
case *cases.CheckChallengeIsValid:
state.CheckChallengeIsValid = cfg

case *cases.RoundHasFinalized:
state.RoundHasFinalizedConfig = cfg

default:
log.Panicf("unknown test case name: %s", configurator.Name())
}
Expand Down Expand Up @@ -914,6 +917,8 @@ func (r *Runner) SetServerState(update interface{}) error {
state.BlobberDelete = update
case *config.AdversarialValidator:
state.AdversarialValidator = update
case *config.LockNotarizationAndSendNextRoundVRF:
state.LockNotarizationAndSendNextRoundVRF = update
}
})

Expand Down
3 changes: 3 additions & 0 deletions code/go/0chain.net/conductor/conductrpc/state.go
Expand Up @@ -66,6 +66,9 @@ type State struct {
MinerNotarisedBlockRequestor *cases.MinerNotarisedBlockRequestor
FBRequestor *cases.FBRequestor
MissingLFBTicket *cases.MissingLFBTickets
RoundHasFinalizedConfig *cases.RoundHasFinalized

LockNotarizationAndSendNextRoundVRF *config.LockNotarizationAndSendNextRoundVRF

// Blobbers related states
StorageTree *config.Bad // blobber sends bad files/tree responses
Expand Down
@@ -0,0 +1,50 @@
package cases

import (
"0chain.net/conductor/cases"
"github.com/mitchellh/mapstructure"
)

type (
// NodeTypeTypeRank holds the information about the node type and the type rank of the miner
// If node type is 0 the miner is a generator/leader. Otherwise, it is a replica.
NodeTypeTypeRank struct {
NodeType int `json:"node_type" yaml:"node_type" mapstructure:"node_type"`
TypeRank int `json:"type_rank" yaml:"type_rank" mapstructure:"type_rank"`
}
// RoundHasFinalized represents TestCaseConfigurator implementation.
RoundHasFinalized struct {
Spammers []NodeTypeTypeRank `json:"spammers" yaml:"spammers" mapstructure:"spammers"`
SpammingReceiver NodeTypeTypeRank `json:"spamming_receiver" yaml:"spamming_receiver" mapstructure:"spamming_receiver"`
Round int `json:"round" yaml:"round" mapstructure:"round"`
}
)

const (
RoundHasFinalizedName = "round has finalized"
)

var (
// Ensure RoundHasFinalized implements TestCaseConfigurator.
_ TestCaseConfigurator = (*RoundHasFinalized)(nil)
)

// NewRoundHasFinalized creates initialised RoundHasFinalized.
func NewRoundHasFinalized() *RoundHasFinalized {
return &RoundHasFinalized{}
}

// TestCase implements TestCaseConfigurator interface.
func (n *RoundHasFinalized) TestCase() cases.TestCase {
return cases.NewRoundHasFinalized()
}

// Name implements TestCaseConfigurator interface.
func (n *RoundHasFinalized) Name() string {
return RoundHasFinalizedName
}

// Decode implements MapDecoder interface.
func (n *RoundHasFinalized) Decode(val interface{}) error {
return mapstructure.Decode(val, n)
}
19 changes: 19 additions & 0 deletions code/go/0chain.net/conductor/config/registry.go
Expand Up @@ -575,6 +575,25 @@ func init() {
return ex.ConfigureTestCase(cfg)
})

register("lock_notarization_and_send_next_round_vrf", func(name string,
ex Executor, val interface{}, tm time.Duration) (err error) {
cfg := NewLockNotarizationAndSendNextRoundVRF()
if err := cfg.Decode(val); err != nil {
return err
}

return ex.SetServerState(cfg)
})

register("round_has_finalized", func(name string,
ex Executor, val interface{}, tm time.Duration) (err error) {
cfg := cases.NewRoundHasFinalized()
if err := cfg.Decode(val); err != nil {
return err
}
return ex.ConfigureTestCase(cfg)
})

register("make_test_case_check", func(name string, ex Executor, val interface{}, tm time.Duration) (err error) {
cfg := &TestCaseCheck{}
if err := cfg.Decode(val); err != nil {
Expand Down
16 changes: 16 additions & 0 deletions code/go/0chain.net/conductor/config/types.go
Expand Up @@ -2,6 +2,22 @@ package config

import "github.com/mitchellh/mapstructure"

// BlobberList represents the blobber_list directive state.
type LockNotarizationAndSendNextRoundVRF struct {
Round int `json:"round" yaml:"round" mapstructure:"round"`
Adversarial string `json:"adversarial" yaml:"adversarial" mapstructure:"adversarial"`
}

// NewLockNotarizationAndSendNextRoundVRF returns an entity of LockNotarizationAndSendNextRoundVRF
func NewLockNotarizationAndSendNextRoundVRF() *LockNotarizationAndSendNextRoundVRF {
return &LockNotarizationAndSendNextRoundVRF{}
}

// Decode implements MapDecoder interface.
func (n *LockNotarizationAndSendNextRoundVRF) Decode(val interface{}) error {
return mapstructure.Decode(val, n)
}

// BlobberList represents the blobber_list directive state.
type BlobberList struct {
ReturnError bool `json:"return_error" yaml:"return_error" mapstructure:"return_error"`
Expand Down
29 changes: 0 additions & 29 deletions code/go/0chain.net/conductor/utils/utils.go
@@ -1,10 +1,7 @@
package utils

import (
"0chain.net/chaincore/node"
"0chain.net/core/encryption"

crpc "0chain.net/conductor/conductrpc"
)

var signature = encryption.NewBLS0ChainScheme()
Expand All @@ -19,29 +16,3 @@ func init() {
func Sign(hash string) (sign string, err error) {
return signature.Sign(hash)
}

// Split nodes list by given IsGoodOrBad.
func Split(s *crpc.State, igb crpc.IsGoodOrBad, nodes []*node.Node) (
good, bad []*node.Node) {

for _, n := range nodes {
if igb.IsBad(s, n.GetKey()) {
bad = append(bad, n)
} else if igb.IsGood(s, n.GetKey()) {
good = append(good, n)
}
}
return
}

// Filter return IsBy nodes only.
func Filter(s *crpc.State, ib crpc.IsBy, nodes []*node.Node) (
rest []*node.Node) {

for _, n := range nodes {
if ib.IsBy(s, n.GetKey()) {
rest = append(rest, n)
}
}
return
}
4 changes: 2 additions & 2 deletions code/go/0chain.net/miner/m_handler.go
Expand Up @@ -136,8 +136,8 @@ func SetupM2MRequestors() {
DKGShareSender = node.RequestEntityHandler("/v1/_m2m/dkg/share", options, dkgShareEntityMetadata)
}

// VRFShareHandler - handle the vrf share.
func VRFShareHandler(ctx context.Context, entity datastore.Entity) (
// vrfShareHandler - handle the vrf share.
func vrfShareHandler(ctx context.Context, entity datastore.Entity) (
interface{}, error) {
vrfs, ok := entity.(*round.VRFShare)
if !ok {
Expand Down
7 changes: 6 additions & 1 deletion code/go/0chain.net/miner/m_handler_integration_tests.go
Expand Up @@ -86,7 +86,6 @@ func NotarizationReceiptHandler(ctx context.Context, entity datastore.Entity) (i
<-delayedBlock
}()
}

return notarizationReceiptHandler(ctx, entity)
}

Expand Down Expand Up @@ -199,3 +198,9 @@ func blockWithoutVerTickets(r *http.Request) (*block.Block, error) {

return bl, nil
}

// VRFShareHandler - handle the vrf share.
func VRFShareHandler(ctx context.Context, entity datastore.Entity) (
interface{}, error) {
return vrfShareHandler(ctx, entity)
}
6 changes: 6 additions & 0 deletions code/go/0chain.net/miner/m_handler_main.go
Expand Up @@ -31,3 +31,9 @@ func NotarizationReceiptHandler(ctx context.Context, entity datastore.Entity) (i
func NotarizedBlockSendHandler(ctx context.Context, r *http.Request) (interface{}, error) {
return notarizedBlockSendHandler(ctx, r)
}

// VRFShareHandler - handle the vrf share.
func VRFShareHandler(ctx context.Context, entity datastore.Entity) (
interface{}, error) {
return vrfShareHandler(ctx, entity)
}