mirror of https://github.com/poanetwork/gecko.git
2366 lines
48 KiB
Go
2366 lines
48 KiB
Go
// (c) 2019-2020, Ava Labs, Inc. All rights reserved.
|
|
// See the file LICENSE for licensing terms.
|
|
|
|
package avalanche
|
|
|
|
import (
|
|
"bytes"
|
|
"errors"
|
|
"testing"
|
|
|
|
"github.com/prometheus/client_golang/prometheus"
|
|
|
|
"github.com/ava-labs/gecko/ids"
|
|
"github.com/ava-labs/gecko/snow/choices"
|
|
"github.com/ava-labs/gecko/snow/consensus/avalanche"
|
|
"github.com/ava-labs/gecko/snow/consensus/snowball"
|
|
"github.com/ava-labs/gecko/snow/consensus/snowstorm"
|
|
"github.com/ava-labs/gecko/snow/engine/common"
|
|
"github.com/ava-labs/gecko/snow/validators"
|
|
)
|
|
|
|
var (
|
|
errFailedParsing = errors.New("failed parsing")
|
|
errMissing = errors.New("missing")
|
|
)
|
|
|
|
func TestEngineAdd(t *testing.T) {
|
|
config := DefaultConfig()
|
|
|
|
vdr := validators.GenerateRandomValidator(1)
|
|
|
|
vals := validators.NewSet()
|
|
config.Validators = vals
|
|
|
|
vals.Add(vdr)
|
|
|
|
sender := &common.SenderTest{}
|
|
sender.T = t
|
|
config.Sender = sender
|
|
|
|
sender.Default(true)
|
|
sender.CantGetAcceptedFrontier = false
|
|
|
|
st := &stateTest{t: t}
|
|
config.State = st
|
|
|
|
st.Default(true)
|
|
|
|
st.cantEdge = false
|
|
|
|
te := &Transitive{}
|
|
te.Initialize(config)
|
|
te.finishBootstrapping()
|
|
|
|
if !te.Context().ChainID.Equals(ids.Empty) {
|
|
t.Fatalf("Wrong chain ID")
|
|
}
|
|
|
|
vtx := &Vtx{
|
|
parents: []avalanche.Vertex{
|
|
&Vtx{
|
|
id: GenerateID(),
|
|
status: choices.Unknown,
|
|
},
|
|
},
|
|
id: GenerateID(),
|
|
status: choices.Processing,
|
|
bytes: []byte{1},
|
|
}
|
|
|
|
asked := new(bool)
|
|
sender.GetF = func(inVdr ids.ShortID, _ uint32, vtxID ids.ID) {
|
|
if *asked {
|
|
t.Fatalf("Asked multiple times")
|
|
}
|
|
*asked = true
|
|
if !vdr.ID().Equals(inVdr) {
|
|
t.Fatalf("Asking wrong validator for vertex")
|
|
}
|
|
if !vtx.parents[0].ID().Equals(vtxID) {
|
|
t.Fatalf("Asking for wrong vertex")
|
|
}
|
|
}
|
|
|
|
st.parseVertex = func(b []byte) (avalanche.Vertex, error) {
|
|
if !bytes.Equal(b, vtx.Bytes()) {
|
|
t.Fatalf("Wrong bytes")
|
|
}
|
|
return vtx, nil
|
|
}
|
|
|
|
te.Put(vdr.ID(), 0, vtx.ID(), vtx.Bytes())
|
|
|
|
st.parseVertex = nil
|
|
|
|
if !*asked {
|
|
t.Fatalf("Didn't ask for a missing vertex")
|
|
}
|
|
|
|
if len(te.vtxBlocked) != 1 {
|
|
t.Fatalf("Should have been blocking on request")
|
|
}
|
|
|
|
st.parseVertex = func(b []byte) (avalanche.Vertex, error) { return nil, errFailedParsing }
|
|
|
|
te.Put(vdr.ID(), 0, vtx.parents[0].ID(), nil)
|
|
|
|
st.parseVertex = nil
|
|
|
|
if len(te.vtxBlocked) != 0 {
|
|
t.Fatalf("Should have finished blocking issue")
|
|
}
|
|
}
|
|
|
|
func TestEngineQuery(t *testing.T) {
|
|
config := DefaultConfig()
|
|
|
|
vdr := validators.GenerateRandomValidator(1)
|
|
|
|
vals := validators.NewSet()
|
|
config.Validators = vals
|
|
|
|
vals.Add(vdr)
|
|
|
|
sender := &common.SenderTest{}
|
|
sender.T = t
|
|
config.Sender = sender
|
|
|
|
sender.Default(true)
|
|
sender.CantGetAcceptedFrontier = false
|
|
|
|
st := &stateTest{t: t}
|
|
config.State = st
|
|
|
|
st.Default(true)
|
|
|
|
gVtx := &Vtx{
|
|
id: GenerateID(),
|
|
status: choices.Accepted,
|
|
}
|
|
mVtx := &Vtx{
|
|
id: GenerateID(),
|
|
status: choices.Accepted,
|
|
}
|
|
|
|
vts := []avalanche.Vertex{gVtx, mVtx}
|
|
utxos := []ids.ID{GenerateID()}
|
|
|
|
tx0 := &TestTx{
|
|
TestTx: snowstorm.TestTx{Identifier: GenerateID()},
|
|
}
|
|
tx0.Ins.Add(utxos[0])
|
|
|
|
vtx0 := &Vtx{
|
|
parents: vts,
|
|
id: GenerateID(),
|
|
txs: []snowstorm.Tx{tx0},
|
|
height: 1,
|
|
status: choices.Processing,
|
|
bytes: []byte{0, 1, 2, 3},
|
|
}
|
|
|
|
st.edge = func() []ids.ID { return []ids.ID{vts[0].ID(), vts[1].ID()} }
|
|
st.getVertex = func(id ids.ID) (avalanche.Vertex, error) {
|
|
switch {
|
|
case id.Equals(gVtx.ID()):
|
|
return gVtx, nil
|
|
case id.Equals(mVtx.ID()):
|
|
return mVtx, nil
|
|
}
|
|
|
|
t.Fatalf("Unknown vertex")
|
|
panic("Should have errored")
|
|
}
|
|
|
|
te := &Transitive{}
|
|
te.Initialize(config)
|
|
te.finishBootstrapping()
|
|
|
|
vertexed := new(bool)
|
|
st.getVertex = func(vtxID ids.ID) (avalanche.Vertex, error) {
|
|
if *vertexed {
|
|
t.Fatalf("Sent multiple requests")
|
|
}
|
|
*vertexed = true
|
|
if !vtxID.Equals(vtx0.ID()) {
|
|
t.Fatalf("Wrong vertex requested")
|
|
}
|
|
return nil, errUnknownVertex
|
|
}
|
|
|
|
asked := new(bool)
|
|
sender.GetF = func(inVdr ids.ShortID, _ uint32, vtxID ids.ID) {
|
|
if *asked {
|
|
t.Fatalf("Asked multiple times")
|
|
}
|
|
*asked = true
|
|
if !vdr.ID().Equals(inVdr) {
|
|
t.Fatalf("Asking wrong validator for vertex")
|
|
}
|
|
if !vtx0.ID().Equals(vtxID) {
|
|
t.Fatalf("Asking for wrong vertex")
|
|
}
|
|
}
|
|
|
|
te.PullQuery(vdr.ID(), 0, vtx0.ID())
|
|
if !*vertexed {
|
|
t.Fatalf("Didn't request vertex")
|
|
}
|
|
if !*asked {
|
|
t.Fatalf("Didn't request vertex from validator")
|
|
}
|
|
|
|
queried := new(bool)
|
|
queryRequestID := new(uint32)
|
|
sender.PushQueryF = func(inVdrs ids.ShortSet, requestID uint32, vtxID ids.ID, vtx []byte) {
|
|
if *queried {
|
|
t.Fatalf("Asked multiple times")
|
|
}
|
|
*queried = true
|
|
*queryRequestID = requestID
|
|
vdrSet := ids.ShortSet{}
|
|
vdrSet.Add(vdr.ID())
|
|
if !inVdrs.Equals(vdrSet) {
|
|
t.Fatalf("Asking wrong validator for preference")
|
|
}
|
|
if !vtx0.ID().Equals(vtxID) {
|
|
t.Fatalf("Asking for wrong vertex")
|
|
}
|
|
}
|
|
|
|
chitted := new(bool)
|
|
sender.ChitsF = func(inVdr ids.ShortID, _ uint32, prefs ids.Set) {
|
|
if *chitted {
|
|
t.Fatalf("Sent multiple chits")
|
|
}
|
|
*chitted = true
|
|
if !Matches(prefs.List(), []ids.ID{vtx0.ID()}) {
|
|
t.Fatalf("Wrong chits preferences")
|
|
}
|
|
}
|
|
|
|
st.parseVertex = func(b []byte) (avalanche.Vertex, error) {
|
|
if !bytes.Equal(b, vtx0.Bytes()) {
|
|
t.Fatalf("Wrong bytes")
|
|
}
|
|
return vtx0, nil
|
|
}
|
|
te.Put(vdr.ID(), 0, vtx0.ID(), vtx0.Bytes())
|
|
st.parseVertex = nil
|
|
|
|
if !*queried {
|
|
t.Fatalf("Didn't ask for preferences")
|
|
}
|
|
if !*chitted {
|
|
t.Fatalf("Didn't provide preferences")
|
|
}
|
|
|
|
vtx1 := &Vtx{
|
|
parents: vts,
|
|
id: GenerateID(),
|
|
txs: []snowstorm.Tx{tx0},
|
|
height: 1,
|
|
status: choices.Processing,
|
|
bytes: []byte{5, 4, 3, 2, 1, 9},
|
|
}
|
|
|
|
st.getVertex = func(vtxID ids.ID) (avalanche.Vertex, error) {
|
|
if vtxID.Equals(vtx0.ID()) {
|
|
return &Vtx{status: choices.Processing}, nil
|
|
}
|
|
if vtxID.Equals(vtx1.ID()) {
|
|
return nil, errUnknownVertex
|
|
}
|
|
t.Fatalf("Wrong vertex requested")
|
|
panic("Should have failed")
|
|
}
|
|
|
|
*asked = false
|
|
sender.GetF = func(inVdr ids.ShortID, _ uint32, vtxID ids.ID) {
|
|
if *asked {
|
|
t.Fatalf("Asked multiple times")
|
|
}
|
|
*asked = true
|
|
if !vdr.ID().Equals(inVdr) {
|
|
t.Fatalf("Asking wrong validator for vertex")
|
|
}
|
|
if !vtx1.ID().Equals(vtxID) {
|
|
t.Fatalf("Asking for wrong vertex")
|
|
}
|
|
}
|
|
|
|
s := ids.Set{}
|
|
s.Add(vtx1.ID())
|
|
te.Chits(vdr.ID(), *queryRequestID, s)
|
|
|
|
*queried = false
|
|
sender.PushQueryF = func(inVdrs ids.ShortSet, requestID uint32, vtxID ids.ID, vtx []byte) {
|
|
if *queried {
|
|
t.Fatalf("Asked multiple times")
|
|
}
|
|
*queried = true
|
|
*queryRequestID = requestID
|
|
vdrSet := ids.ShortSet{}
|
|
vdrSet.Add(vdr.ID())
|
|
if !inVdrs.Equals(vdrSet) {
|
|
t.Fatalf("Asking wrong validator for preference")
|
|
}
|
|
if !vtx1.ID().Equals(vtxID) {
|
|
t.Fatalf("Asking for wrong vertex")
|
|
}
|
|
}
|
|
|
|
st.parseVertex = func(b []byte) (avalanche.Vertex, error) {
|
|
if !bytes.Equal(b, vtx1.Bytes()) {
|
|
t.Fatalf("Wrong bytes")
|
|
}
|
|
return vtx1, nil
|
|
}
|
|
te.Put(vdr.ID(), 0, vtx1.ID(), vtx1.Bytes())
|
|
st.parseVertex = nil
|
|
|
|
if vtx0.Status() != choices.Accepted {
|
|
t.Fatalf("Should have executed vertex")
|
|
}
|
|
if len(te.vtxBlocked) != 0 {
|
|
t.Fatalf("Should have finished blocking")
|
|
}
|
|
|
|
_ = te.polls.String() // Shouldn't panic
|
|
|
|
te.QueryFailed(vdr.ID(), *queryRequestID)
|
|
if len(te.vtxBlocked) != 0 {
|
|
t.Fatalf("Should have finished blocking")
|
|
}
|
|
}
|
|
|
|
func TestEngineMultipleQuery(t *testing.T) {
|
|
config := DefaultConfig()
|
|
|
|
config.Params = avalanche.Parameters{
|
|
Parameters: snowball.Parameters{
|
|
Metrics: prometheus.NewRegistry(),
|
|
K: 3,
|
|
Alpha: 2,
|
|
BetaVirtuous: 1,
|
|
BetaRogue: 2,
|
|
},
|
|
Parents: 2,
|
|
BatchSize: 1,
|
|
}
|
|
|
|
vdr0 := validators.GenerateRandomValidator(1)
|
|
vdr1 := validators.GenerateRandomValidator(1)
|
|
vdr2 := validators.GenerateRandomValidator(1)
|
|
|
|
vals := validators.NewSet()
|
|
config.Validators = vals
|
|
|
|
vals.Add(vdr0)
|
|
vals.Add(vdr1)
|
|
vals.Add(vdr2)
|
|
|
|
sender := &common.SenderTest{}
|
|
sender.T = t
|
|
config.Sender = sender
|
|
|
|
sender.Default(true)
|
|
sender.CantGetAcceptedFrontier = false
|
|
|
|
st := &stateTest{t: t}
|
|
config.State = st
|
|
|
|
gVtx := &Vtx{
|
|
id: GenerateID(),
|
|
status: choices.Accepted,
|
|
}
|
|
mVtx := &Vtx{
|
|
id: GenerateID(),
|
|
status: choices.Accepted,
|
|
}
|
|
|
|
vts := []avalanche.Vertex{gVtx, mVtx}
|
|
utxos := []ids.ID{GenerateID()}
|
|
|
|
st.edge = func() []ids.ID { return []ids.ID{vts[0].ID(), vts[1].ID()} }
|
|
st.getVertex = func(id ids.ID) (avalanche.Vertex, error) {
|
|
switch {
|
|
case id.Equals(gVtx.ID()):
|
|
return gVtx, nil
|
|
case id.Equals(mVtx.ID()):
|
|
return mVtx, nil
|
|
}
|
|
t.Fatalf("Unknown vertex")
|
|
panic("Should have errored")
|
|
}
|
|
|
|
tx0 := &TestTx{
|
|
TestTx: snowstorm.TestTx{Identifier: GenerateID()},
|
|
}
|
|
tx0.Ins.Add(utxos[0])
|
|
|
|
vtx0 := &Vtx{
|
|
parents: vts,
|
|
id: GenerateID(),
|
|
txs: []snowstorm.Tx{tx0},
|
|
height: 1,
|
|
status: choices.Processing,
|
|
}
|
|
|
|
te := &Transitive{}
|
|
te.Initialize(config)
|
|
te.finishBootstrapping()
|
|
|
|
queried := new(bool)
|
|
queryRequestID := new(uint32)
|
|
sender.PushQueryF = func(inVdrs ids.ShortSet, requestID uint32, vtxID ids.ID, vtx []byte) {
|
|
if *queried {
|
|
t.Fatalf("Asked multiple times")
|
|
}
|
|
*queried = true
|
|
*queryRequestID = requestID
|
|
vdrSet := ids.ShortSet{}
|
|
vdrSet.Add(vdr0.ID(), vdr1.ID(), vdr2.ID())
|
|
if !inVdrs.Equals(vdrSet) {
|
|
t.Fatalf("Asking wrong validator for preference")
|
|
}
|
|
if !vtx0.ID().Equals(vtxID) {
|
|
t.Fatalf("Asking for wrong vertex")
|
|
}
|
|
}
|
|
|
|
te.insert(vtx0)
|
|
|
|
vtx1 := &Vtx{
|
|
parents: vts,
|
|
id: GenerateID(),
|
|
txs: []snowstorm.Tx{tx0},
|
|
height: 1,
|
|
status: choices.Processing,
|
|
}
|
|
|
|
st.getVertex = func(id ids.ID) (avalanche.Vertex, error) {
|
|
switch {
|
|
case id.Equals(gVtx.ID()):
|
|
return gVtx, nil
|
|
case id.Equals(mVtx.ID()):
|
|
return mVtx, nil
|
|
case id.Equals(vtx0.ID()):
|
|
return vtx0, nil
|
|
case id.Equals(vtx1.ID()):
|
|
return nil, errUnknownVertex
|
|
}
|
|
t.Fatalf("Unknown vertex")
|
|
panic("Should have errored")
|
|
}
|
|
|
|
asked := new(bool)
|
|
sender.GetF = func(inVdr ids.ShortID, _ uint32, vtxID ids.ID) {
|
|
if *asked {
|
|
t.Fatalf("Asked multiple times")
|
|
}
|
|
*asked = true
|
|
if !vdr0.ID().Equals(inVdr) {
|
|
t.Fatalf("Asking wrong validator for vertex")
|
|
}
|
|
if !vtx1.ID().Equals(vtxID) {
|
|
t.Fatalf("Asking for wrong vertex")
|
|
}
|
|
}
|
|
|
|
s0 := ids.Set{}
|
|
s0.Add(vtx0.ID())
|
|
s0.Add(vtx1.ID())
|
|
|
|
s2 := ids.Set{}
|
|
s2.Add(vtx0.ID())
|
|
|
|
te.Chits(vdr0.ID(), *queryRequestID, s0)
|
|
te.QueryFailed(vdr1.ID(), *queryRequestID)
|
|
te.Chits(vdr2.ID(), *queryRequestID, s2)
|
|
|
|
// Should be dropped because the query was marked as failed
|
|
te.Chits(vdr1.ID(), *queryRequestID, s0)
|
|
|
|
te.GetFailed(vdr0.ID(), 0, vtx1.ID())
|
|
|
|
if vtx0.Status() != choices.Accepted {
|
|
t.Fatalf("Should have executed vertex")
|
|
}
|
|
if len(te.vtxBlocked) != 0 {
|
|
t.Fatalf("Should have finished blocking")
|
|
}
|
|
}
|
|
|
|
func TestEngineBlockedIssue(t *testing.T) {
|
|
config := DefaultConfig()
|
|
|
|
vdr := validators.GenerateRandomValidator(1)
|
|
|
|
vals := validators.NewSet()
|
|
config.Validators = vals
|
|
|
|
vals.Add(vdr)
|
|
|
|
st := &stateTest{t: t}
|
|
config.State = st
|
|
|
|
gVtx := &Vtx{
|
|
id: GenerateID(),
|
|
status: choices.Accepted,
|
|
}
|
|
mVtx := &Vtx{
|
|
id: GenerateID(),
|
|
status: choices.Accepted,
|
|
}
|
|
|
|
vts := []avalanche.Vertex{gVtx, mVtx}
|
|
utxos := []ids.ID{GenerateID()}
|
|
|
|
tx0 := &TestTx{
|
|
TestTx: snowstorm.TestTx{Identifier: GenerateID()},
|
|
}
|
|
tx0.Ins.Add(utxos[0])
|
|
|
|
vtx0 := &Vtx{
|
|
parents: vts,
|
|
id: GenerateID(),
|
|
txs: []snowstorm.Tx{tx0},
|
|
height: 1,
|
|
status: choices.Processing,
|
|
}
|
|
|
|
vtx1 := &Vtx{
|
|
parents: []avalanche.Vertex{&Vtx{
|
|
id: vtx0.ID(),
|
|
status: choices.Unknown,
|
|
}},
|
|
id: GenerateID(),
|
|
txs: []snowstorm.Tx{tx0},
|
|
height: 1,
|
|
status: choices.Processing,
|
|
}
|
|
|
|
te := &Transitive{}
|
|
te.Initialize(config)
|
|
te.finishBootstrapping()
|
|
|
|
te.insert(vtx1)
|
|
|
|
vtx1.parents[0] = vtx0
|
|
te.insert(vtx0)
|
|
|
|
if !Matches(te.Consensus.Preferences().List(), []ids.ID{vtx1.ID()}) {
|
|
t.Fatalf("Should have issued vtx1")
|
|
}
|
|
}
|
|
|
|
func TestEngineAbandonResponse(t *testing.T) {
|
|
config := DefaultConfig()
|
|
|
|
vdr := validators.GenerateRandomValidator(1)
|
|
|
|
vals := validators.NewSet()
|
|
config.Validators = vals
|
|
|
|
vals.Add(vdr)
|
|
|
|
st := &stateTest{t: t}
|
|
config.State = st
|
|
|
|
gVtx := &Vtx{
|
|
id: GenerateID(),
|
|
status: choices.Accepted,
|
|
}
|
|
mVtx := &Vtx{
|
|
id: GenerateID(),
|
|
status: choices.Accepted,
|
|
}
|
|
|
|
vts := []avalanche.Vertex{gVtx, mVtx}
|
|
utxos := []ids.ID{GenerateID()}
|
|
|
|
tx0 := &TestTx{
|
|
TestTx: snowstorm.TestTx{Identifier: GenerateID()},
|
|
}
|
|
tx0.Ins.Add(utxos[0])
|
|
|
|
vtx := &Vtx{
|
|
parents: vts,
|
|
id: GenerateID(),
|
|
txs: []snowstorm.Tx{tx0},
|
|
height: 1,
|
|
status: choices.Processing,
|
|
}
|
|
|
|
st.getVertex = func(id ids.ID) (avalanche.Vertex, error) { return nil, errUnknownVertex }
|
|
|
|
te := &Transitive{}
|
|
te.Initialize(config)
|
|
te.finishBootstrapping()
|
|
|
|
te.PullQuery(vdr.ID(), 0, vtx.ID())
|
|
te.GetFailed(vdr.ID(), 0, vtx.ID())
|
|
|
|
if len(te.vtxBlocked) != 0 {
|
|
t.Fatalf("Should have removed blocking event")
|
|
}
|
|
}
|
|
|
|
func TestEngineScheduleRepoll(t *testing.T) {
|
|
config := DefaultConfig()
|
|
|
|
vdr := validators.GenerateRandomValidator(1)
|
|
|
|
vals := validators.NewSet()
|
|
config.Validators = vals
|
|
|
|
vals.Add(vdr)
|
|
|
|
gVtx := &Vtx{
|
|
id: GenerateID(),
|
|
status: choices.Accepted,
|
|
}
|
|
mVtx := &Vtx{
|
|
id: GenerateID(),
|
|
status: choices.Accepted,
|
|
}
|
|
|
|
vts := []avalanche.Vertex{gVtx, mVtx}
|
|
utxos := []ids.ID{GenerateID()}
|
|
|
|
tx0 := &TestTx{
|
|
TestTx: snowstorm.TestTx{Identifier: GenerateID()},
|
|
}
|
|
tx0.Ins.Add(utxos[0])
|
|
|
|
vtx := &Vtx{
|
|
parents: vts,
|
|
id: GenerateID(),
|
|
txs: []snowstorm.Tx{tx0},
|
|
height: 1,
|
|
status: choices.Processing,
|
|
}
|
|
|
|
st := &stateTest{t: t}
|
|
config.State = st
|
|
|
|
st.Default(true)
|
|
st.cantEdge = false
|
|
|
|
sender := &common.SenderTest{}
|
|
sender.T = t
|
|
config.Sender = sender
|
|
|
|
sender.Default(true)
|
|
sender.CantGetAcceptedFrontier = false
|
|
|
|
te := &Transitive{}
|
|
te.Initialize(config)
|
|
te.finishBootstrapping()
|
|
|
|
requestID := new(uint32)
|
|
sender.PushQueryF = func(_ ids.ShortSet, reqID uint32, _ ids.ID, _ []byte) {
|
|
*requestID = reqID
|
|
}
|
|
|
|
te.insert(vtx)
|
|
|
|
sender.PushQueryF = nil
|
|
|
|
st.buildVertex = func(_ ids.Set, txs []snowstorm.Tx) (avalanche.Vertex, error) {
|
|
consumers := []snowstorm.Tx{}
|
|
for _, tx := range txs {
|
|
consumers = append(consumers, tx)
|
|
}
|
|
return &Vtx{
|
|
parents: []avalanche.Vertex{gVtx, mVtx},
|
|
id: GenerateID(),
|
|
txs: consumers,
|
|
status: choices.Processing,
|
|
bytes: []byte{1},
|
|
}, nil
|
|
}
|
|
|
|
repolled := new(bool)
|
|
sender.PushQueryF = func(_ ids.ShortSet, _ uint32, _ ids.ID, _ []byte) {
|
|
*repolled = true
|
|
}
|
|
|
|
te.QueryFailed(vdr.ID(), *requestID)
|
|
|
|
if !*repolled {
|
|
t.Fatalf("Should have issued a noop")
|
|
}
|
|
}
|
|
|
|
func TestEngineRejectDoubleSpendTx(t *testing.T) {
|
|
config := DefaultConfig()
|
|
|
|
config.Params.BatchSize = 2
|
|
|
|
sender := &common.SenderTest{}
|
|
sender.T = t
|
|
config.Sender = sender
|
|
|
|
sender.Default(true)
|
|
sender.CantGetAcceptedFrontier = false
|
|
|
|
vdr := validators.GenerateRandomValidator(1)
|
|
|
|
vals := validators.NewSet()
|
|
config.Validators = vals
|
|
|
|
vals.Add(vdr)
|
|
|
|
st := &stateTest{t: t}
|
|
config.State = st
|
|
|
|
st.Default(true)
|
|
|
|
vm := &VMTest{}
|
|
vm.T = t
|
|
config.VM = vm
|
|
|
|
vm.Default(true)
|
|
|
|
gVtx := &Vtx{
|
|
id: GenerateID(),
|
|
status: choices.Accepted,
|
|
}
|
|
mVtx := &Vtx{
|
|
id: GenerateID(),
|
|
status: choices.Accepted,
|
|
}
|
|
|
|
gTx := &TestTx{
|
|
TestTx: snowstorm.TestTx{
|
|
Identifier: GenerateID(),
|
|
Stat: choices.Accepted,
|
|
},
|
|
}
|
|
|
|
utxos := []ids.ID{GenerateID()}
|
|
|
|
tx0 := &TestTx{
|
|
TestTx: snowstorm.TestTx{
|
|
Identifier: GenerateID(),
|
|
Deps: []snowstorm.Tx{gTx},
|
|
Stat: choices.Processing,
|
|
},
|
|
}
|
|
tx0.Ins.Add(utxos[0])
|
|
|
|
tx1 := &TestTx{
|
|
TestTx: snowstorm.TestTx{
|
|
Identifier: GenerateID(),
|
|
Deps: []snowstorm.Tx{gTx},
|
|
Stat: choices.Processing,
|
|
},
|
|
}
|
|
tx1.Ins.Add(utxos[0])
|
|
|
|
st.edge = func() []ids.ID { return []ids.ID{gVtx.ID(), mVtx.ID()} }
|
|
st.getVertex = func(id ids.ID) (avalanche.Vertex, error) {
|
|
switch {
|
|
case id.Equals(gVtx.ID()):
|
|
return gVtx, nil
|
|
case id.Equals(mVtx.ID()):
|
|
return mVtx, nil
|
|
}
|
|
t.Fatalf("Unknown vertex")
|
|
panic("Should have errored")
|
|
}
|
|
st.buildVertex = func(_ ids.Set, txs []snowstorm.Tx) (avalanche.Vertex, error) {
|
|
consumers := []snowstorm.Tx{}
|
|
for _, tx := range txs {
|
|
consumers = append(consumers, tx)
|
|
}
|
|
return &Vtx{
|
|
parents: []avalanche.Vertex{gVtx, mVtx},
|
|
id: GenerateID(),
|
|
txs: consumers,
|
|
status: choices.Processing,
|
|
bytes: []byte{1},
|
|
}, nil
|
|
}
|
|
|
|
te := &Transitive{}
|
|
te.Initialize(config)
|
|
te.finishBootstrapping()
|
|
|
|
sender.CantPushQuery = false
|
|
|
|
vm.PendingTxsF = func() []snowstorm.Tx { return []snowstorm.Tx{tx0, tx1} }
|
|
te.Notify(common.PendingTxs)
|
|
}
|
|
|
|
func TestEngineRejectDoubleSpendIssuedTx(t *testing.T) {
|
|
config := DefaultConfig()
|
|
|
|
config.Params.BatchSize = 2
|
|
|
|
sender := &common.SenderTest{}
|
|
sender.T = t
|
|
config.Sender = sender
|
|
|
|
sender.Default(true)
|
|
sender.CantGetAcceptedFrontier = false
|
|
|
|
vdr := validators.GenerateRandomValidator(1)
|
|
|
|
vals := validators.NewSet()
|
|
config.Validators = vals
|
|
|
|
vals.Add(vdr)
|
|
|
|
st := &stateTest{t: t}
|
|
config.State = st
|
|
|
|
st.Default(true)
|
|
|
|
vm := &VMTest{}
|
|
vm.T = t
|
|
config.VM = vm
|
|
|
|
vm.Default(true)
|
|
|
|
gVtx := &Vtx{
|
|
id: GenerateID(),
|
|
status: choices.Accepted,
|
|
}
|
|
mVtx := &Vtx{
|
|
id: GenerateID(),
|
|
status: choices.Accepted,
|
|
}
|
|
|
|
gTx := &TestTx{
|
|
TestTx: snowstorm.TestTx{
|
|
Identifier: GenerateID(),
|
|
Stat: choices.Accepted,
|
|
},
|
|
}
|
|
|
|
utxos := []ids.ID{GenerateID()}
|
|
|
|
tx0 := &TestTx{
|
|
TestTx: snowstorm.TestTx{
|
|
Identifier: GenerateID(),
|
|
Deps: []snowstorm.Tx{gTx},
|
|
Stat: choices.Processing,
|
|
},
|
|
}
|
|
tx0.Ins.Add(utxos[0])
|
|
|
|
tx1 := &TestTx{
|
|
TestTx: snowstorm.TestTx{
|
|
Identifier: GenerateID(),
|
|
Deps: []snowstorm.Tx{gTx},
|
|
Stat: choices.Processing,
|
|
},
|
|
}
|
|
tx1.Ins.Add(utxos[0])
|
|
|
|
st.edge = func() []ids.ID { return []ids.ID{gVtx.ID(), mVtx.ID()} }
|
|
st.getVertex = func(id ids.ID) (avalanche.Vertex, error) {
|
|
switch {
|
|
case id.Equals(gVtx.ID()):
|
|
return gVtx, nil
|
|
case id.Equals(mVtx.ID()):
|
|
return mVtx, nil
|
|
}
|
|
t.Fatalf("Unknown vertex")
|
|
panic("Should have errored")
|
|
}
|
|
|
|
te := &Transitive{}
|
|
te.Initialize(config)
|
|
te.finishBootstrapping()
|
|
|
|
st.buildVertex = func(_ ids.Set, txs []snowstorm.Tx) (avalanche.Vertex, error) {
|
|
consumers := []snowstorm.Tx{}
|
|
for _, tx := range txs {
|
|
consumers = append(consumers, tx)
|
|
}
|
|
return &Vtx{
|
|
parents: []avalanche.Vertex{gVtx, mVtx},
|
|
id: GenerateID(),
|
|
txs: consumers,
|
|
status: choices.Processing,
|
|
bytes: []byte{1},
|
|
}, nil
|
|
}
|
|
|
|
sender.CantPushQuery = false
|
|
|
|
vm.PendingTxsF = func() []snowstorm.Tx { return []snowstorm.Tx{tx0} }
|
|
te.Notify(common.PendingTxs)
|
|
|
|
vm.PendingTxsF = func() []snowstorm.Tx { return []snowstorm.Tx{tx1} }
|
|
te.Notify(common.PendingTxs)
|
|
}
|
|
|
|
func TestEngineIssueRepoll(t *testing.T) {
|
|
config := DefaultConfig()
|
|
|
|
config.Params.BatchSize = 2
|
|
|
|
sender := &common.SenderTest{}
|
|
sender.T = t
|
|
config.Sender = sender
|
|
|
|
sender.Default(true)
|
|
sender.CantGetAcceptedFrontier = false
|
|
|
|
vdr := validators.GenerateRandomValidator(1)
|
|
|
|
vals := validators.NewSet()
|
|
config.Validators = vals
|
|
|
|
vals.Add(vdr)
|
|
|
|
st := &stateTest{t: t}
|
|
config.State = st
|
|
|
|
st.Default(true)
|
|
|
|
gVtx := &Vtx{
|
|
id: GenerateID(),
|
|
status: choices.Accepted,
|
|
}
|
|
mVtx := &Vtx{
|
|
id: GenerateID(),
|
|
status: choices.Accepted,
|
|
}
|
|
|
|
st.edge = func() []ids.ID { return []ids.ID{gVtx.ID(), mVtx.ID()} }
|
|
st.getVertex = func(id ids.ID) (avalanche.Vertex, error) {
|
|
switch {
|
|
case id.Equals(gVtx.ID()):
|
|
return gVtx, nil
|
|
case id.Equals(mVtx.ID()):
|
|
return mVtx, nil
|
|
}
|
|
t.Fatalf("Unknown vertex")
|
|
panic("Should have errored")
|
|
}
|
|
|
|
te := &Transitive{}
|
|
te.Initialize(config)
|
|
te.finishBootstrapping()
|
|
|
|
newVtxID := new(ids.ID)
|
|
|
|
st.buildVertex = func(s ids.Set, txs []snowstorm.Tx) (avalanche.Vertex, error) {
|
|
if len(txs) != 0 {
|
|
t.Fatalf("Wrong vertex issued")
|
|
}
|
|
if s.Len() != 2 || !s.Contains(gVtx.ID()) || !s.Contains(mVtx.ID()) {
|
|
t.Fatalf("Wrong vertex issued")
|
|
}
|
|
|
|
vtx := &Vtx{
|
|
parents: []avalanche.Vertex{gVtx, mVtx},
|
|
id: GenerateID(),
|
|
status: choices.Processing,
|
|
bytes: []byte{1},
|
|
}
|
|
*newVtxID = vtx.ID()
|
|
return vtx, nil
|
|
}
|
|
|
|
sender.PushQueryF = func(vdrs ids.ShortSet, _ uint32, vtxID ids.ID, vtx []byte) {
|
|
vdrSet := ids.ShortSet{}
|
|
vdrSet.Add(vdr.ID())
|
|
if !vdrs.Equals(vdrSet) || !vtxID.Equals(*newVtxID) {
|
|
t.Fatalf("Wrong query message")
|
|
}
|
|
}
|
|
|
|
te.repoll()
|
|
}
|
|
|
|
func TestEngineReissue(t *testing.T) {
|
|
config := DefaultConfig()
|
|
config.Params.BatchSize = 2
|
|
config.Params.BetaVirtuous = 5
|
|
config.Params.BetaRogue = 5
|
|
|
|
sender := &common.SenderTest{}
|
|
sender.T = t
|
|
config.Sender = sender
|
|
|
|
sender.Default(true)
|
|
sender.CantGetAcceptedFrontier = false
|
|
|
|
vdr := validators.GenerateRandomValidator(1)
|
|
|
|
vals := validators.NewSet()
|
|
config.Validators = vals
|
|
|
|
vals.Add(vdr)
|
|
|
|
st := &stateTest{t: t}
|
|
config.State = st
|
|
|
|
st.Default(true)
|
|
|
|
vm := &VMTest{}
|
|
vm.T = t
|
|
config.VM = vm
|
|
|
|
vm.Default(true)
|
|
|
|
gVtx := &Vtx{
|
|
id: GenerateID(),
|
|
status: choices.Accepted,
|
|
}
|
|
mVtx := &Vtx{
|
|
id: GenerateID(),
|
|
status: choices.Accepted,
|
|
}
|
|
|
|
gTx := &TestTx{
|
|
TestTx: snowstorm.TestTx{
|
|
Identifier: GenerateID(),
|
|
Stat: choices.Accepted,
|
|
},
|
|
}
|
|
|
|
utxos := []ids.ID{GenerateID(), GenerateID()}
|
|
|
|
tx0 := &TestTx{
|
|
TestTx: snowstorm.TestTx{
|
|
Identifier: GenerateID(),
|
|
Deps: []snowstorm.Tx{gTx},
|
|
Stat: choices.Processing,
|
|
},
|
|
}
|
|
tx0.Ins.Add(utxos[0])
|
|
|
|
tx1 := &TestTx{
|
|
TestTx: snowstorm.TestTx{
|
|
Identifier: GenerateID(),
|
|
Deps: []snowstorm.Tx{gTx},
|
|
Stat: choices.Processing,
|
|
},
|
|
}
|
|
tx1.Ins.Add(utxos[1])
|
|
|
|
tx2 := &TestTx{
|
|
TestTx: snowstorm.TestTx{
|
|
Identifier: GenerateID(),
|
|
Deps: []snowstorm.Tx{gTx},
|
|
Stat: choices.Processing,
|
|
},
|
|
}
|
|
tx2.Ins.Add(utxos[1])
|
|
|
|
tx3 := &TestTx{
|
|
TestTx: snowstorm.TestTx{
|
|
Identifier: GenerateID(),
|
|
Deps: []snowstorm.Tx{gTx},
|
|
Stat: choices.Processing,
|
|
},
|
|
}
|
|
tx3.Ins.Add(utxos[0])
|
|
|
|
vtx := &Vtx{
|
|
parents: []avalanche.Vertex{gVtx, mVtx},
|
|
txs: []snowstorm.Tx{tx2},
|
|
id: GenerateID(),
|
|
status: choices.Processing,
|
|
bytes: []byte{42},
|
|
}
|
|
|
|
st.edge = func() []ids.ID { return []ids.ID{gVtx.ID(), mVtx.ID()} }
|
|
st.getVertex = func(id ids.ID) (avalanche.Vertex, error) {
|
|
switch {
|
|
case id.Equals(gVtx.ID()):
|
|
return gVtx, nil
|
|
case id.Equals(mVtx.ID()):
|
|
return mVtx, nil
|
|
case id.Equals(vtx.ID()):
|
|
return vtx, nil
|
|
}
|
|
t.Fatalf("Unknown vertex")
|
|
panic("Should have errored")
|
|
}
|
|
|
|
te := &Transitive{}
|
|
te.Initialize(config)
|
|
te.finishBootstrapping()
|
|
|
|
lastVtx := new(Vtx)
|
|
st.buildVertex = func(_ ids.Set, txs []snowstorm.Tx) (avalanche.Vertex, error) {
|
|
consumers := []snowstorm.Tx{}
|
|
for _, tx := range txs {
|
|
consumers = append(consumers, tx)
|
|
}
|
|
lastVtx = &Vtx{
|
|
parents: []avalanche.Vertex{gVtx, mVtx},
|
|
id: GenerateID(),
|
|
txs: consumers,
|
|
status: choices.Processing,
|
|
bytes: []byte{1},
|
|
}
|
|
return lastVtx, nil
|
|
}
|
|
|
|
vm.GetTxF = func(id ids.ID) (snowstorm.Tx, error) {
|
|
if !id.Equals(tx0.ID()) {
|
|
t.Fatalf("Wrong tx")
|
|
}
|
|
return tx0, nil
|
|
}
|
|
|
|
queryRequestID := new(uint32)
|
|
sender.PushQueryF = func(_ ids.ShortSet, requestID uint32, _ ids.ID, _ []byte) {
|
|
*queryRequestID = requestID
|
|
}
|
|
|
|
vm.PendingTxsF = func() []snowstorm.Tx { return []snowstorm.Tx{tx0, tx1} }
|
|
te.Notify(common.PendingTxs)
|
|
|
|
st.parseVertex = func(b []byte) (avalanche.Vertex, error) {
|
|
if !bytes.Equal(b, vtx.Bytes()) {
|
|
t.Fatalf("Wrong bytes")
|
|
}
|
|
return vtx, nil
|
|
}
|
|
te.Put(vdr.ID(), 0, vtx.ID(), vtx.Bytes())
|
|
st.parseVertex = nil
|
|
|
|
vm.PendingTxsF = func() []snowstorm.Tx { return []snowstorm.Tx{tx3} }
|
|
te.Notify(common.PendingTxs)
|
|
|
|
s := ids.Set{}
|
|
s.Add(vtx.ID())
|
|
te.Chits(vdr.ID(), *queryRequestID, s)
|
|
|
|
if len(lastVtx.txs) != 1 || !lastVtx.txs[0].ID().Equals(tx0.ID()) {
|
|
t.Fatalf("Should have re-issued the tx")
|
|
}
|
|
}
|
|
|
|
func TestEngineLargeIssue(t *testing.T) {
|
|
config := DefaultConfig()
|
|
config.Params.BatchSize = 1
|
|
config.Params.BetaVirtuous = 5
|
|
config.Params.BetaRogue = 5
|
|
|
|
sender := &common.SenderTest{}
|
|
sender.T = t
|
|
config.Sender = sender
|
|
|
|
sender.Default(true)
|
|
sender.CantGetAcceptedFrontier = false
|
|
|
|
vdr := validators.GenerateRandomValidator(1)
|
|
|
|
vals := validators.NewSet()
|
|
config.Validators = vals
|
|
|
|
vals.Add(vdr)
|
|
|
|
st := &stateTest{t: t}
|
|
config.State = st
|
|
|
|
st.Default(true)
|
|
|
|
vm := &VMTest{}
|
|
vm.T = t
|
|
config.VM = vm
|
|
|
|
vm.Default(true)
|
|
|
|
gVtx := &Vtx{
|
|
id: GenerateID(),
|
|
status: choices.Accepted,
|
|
}
|
|
mVtx := &Vtx{
|
|
id: GenerateID(),
|
|
status: choices.Accepted,
|
|
}
|
|
|
|
gTx := &TestTx{
|
|
TestTx: snowstorm.TestTx{
|
|
Identifier: GenerateID(),
|
|
Stat: choices.Accepted,
|
|
},
|
|
}
|
|
|
|
utxos := []ids.ID{GenerateID(), GenerateID()}
|
|
|
|
tx0 := &TestTx{
|
|
TestTx: snowstorm.TestTx{
|
|
Identifier: GenerateID(),
|
|
Deps: []snowstorm.Tx{gTx},
|
|
Stat: choices.Processing,
|
|
},
|
|
}
|
|
tx0.Ins.Add(utxos[0])
|
|
|
|
tx1 := &TestTx{
|
|
TestTx: snowstorm.TestTx{
|
|
Identifier: GenerateID(),
|
|
Deps: []snowstorm.Tx{gTx},
|
|
Stat: choices.Processing,
|
|
},
|
|
}
|
|
tx1.Ins.Add(utxos[1])
|
|
|
|
st.edge = func() []ids.ID { return []ids.ID{gVtx.ID(), mVtx.ID()} }
|
|
st.getVertex = func(id ids.ID) (avalanche.Vertex, error) {
|
|
switch {
|
|
case id.Equals(gVtx.ID()):
|
|
return gVtx, nil
|
|
case id.Equals(mVtx.ID()):
|
|
return mVtx, nil
|
|
}
|
|
t.Fatalf("Unknown vertex")
|
|
panic("Should have errored")
|
|
}
|
|
|
|
te := &Transitive{}
|
|
te.Initialize(config)
|
|
te.finishBootstrapping()
|
|
|
|
lastVtx := new(Vtx)
|
|
st.buildVertex = func(_ ids.Set, txs []snowstorm.Tx) (avalanche.Vertex, error) {
|
|
consumers := []snowstorm.Tx{}
|
|
for _, tx := range txs {
|
|
consumers = append(consumers, tx)
|
|
}
|
|
lastVtx = &Vtx{
|
|
parents: []avalanche.Vertex{gVtx, mVtx},
|
|
id: GenerateID(),
|
|
txs: consumers,
|
|
status: choices.Processing,
|
|
bytes: []byte{1},
|
|
}
|
|
return lastVtx, nil
|
|
}
|
|
|
|
sender.CantPushQuery = false
|
|
|
|
vm.PendingTxsF = func() []snowstorm.Tx { return []snowstorm.Tx{tx0, tx1} }
|
|
te.Notify(common.PendingTxs)
|
|
|
|
if len(lastVtx.txs) != 1 || !lastVtx.txs[0].ID().Equals(tx1.ID()) {
|
|
t.Fatalf("Should have issued txs differently")
|
|
}
|
|
}
|
|
|
|
func TestEngineGetVertex(t *testing.T) {
|
|
config := DefaultConfig()
|
|
|
|
sender := &common.SenderTest{}
|
|
sender.T = t
|
|
config.Sender = sender
|
|
|
|
sender.Default(true)
|
|
sender.CantGetAcceptedFrontier = false
|
|
|
|
vdr := validators.GenerateRandomValidator(1)
|
|
|
|
st := &stateTest{t: t}
|
|
config.State = st
|
|
|
|
st.Default(true)
|
|
|
|
gVtx := &Vtx{
|
|
id: GenerateID(),
|
|
status: choices.Accepted,
|
|
}
|
|
mVtx := &Vtx{
|
|
id: GenerateID(),
|
|
status: choices.Accepted,
|
|
}
|
|
|
|
st.edge = func() []ids.ID { return []ids.ID{gVtx.ID(), mVtx.ID()} }
|
|
st.getVertex = func(id ids.ID) (avalanche.Vertex, error) {
|
|
switch {
|
|
case id.Equals(gVtx.ID()):
|
|
return gVtx, nil
|
|
case id.Equals(mVtx.ID()):
|
|
return mVtx, nil
|
|
}
|
|
t.Fatalf("Unknown vertex")
|
|
panic("Should have errored")
|
|
}
|
|
|
|
te := &Transitive{}
|
|
te.Initialize(config)
|
|
te.finishBootstrapping()
|
|
|
|
sender.PutF = func(v ids.ShortID, _ uint32, vtxID ids.ID, vtx []byte) {
|
|
if !v.Equals(vdr.ID()) {
|
|
t.Fatalf("Wrong validator")
|
|
}
|
|
if !mVtx.ID().Equals(vtxID) {
|
|
t.Fatalf("Wrong vertex")
|
|
}
|
|
}
|
|
|
|
te.Get(vdr.ID(), 0, mVtx.ID())
|
|
}
|
|
|
|
func TestEngineInsufficientValidators(t *testing.T) {
|
|
config := DefaultConfig()
|
|
|
|
vals := validators.NewSet()
|
|
config.Validators = vals
|
|
|
|
sender := &common.SenderTest{}
|
|
sender.T = t
|
|
config.Sender = sender
|
|
|
|
sender.Default(true)
|
|
sender.CantGetAcceptedFrontier = false
|
|
|
|
st := &stateTest{t: t}
|
|
config.State = st
|
|
|
|
st.Default(true)
|
|
|
|
gVtx := &Vtx{
|
|
id: GenerateID(),
|
|
status: choices.Accepted,
|
|
}
|
|
mVtx := &Vtx{
|
|
id: GenerateID(),
|
|
status: choices.Accepted,
|
|
}
|
|
|
|
vts := []avalanche.Vertex{gVtx, mVtx}
|
|
|
|
vtx := &Vtx{
|
|
parents: vts,
|
|
id: GenerateID(),
|
|
height: 1,
|
|
status: choices.Processing,
|
|
bytes: []byte{0, 1, 2, 3},
|
|
}
|
|
|
|
st.edge = func() []ids.ID { return []ids.ID{vts[0].ID(), vts[1].ID()} }
|
|
st.getVertex = func(id ids.ID) (avalanche.Vertex, error) {
|
|
switch {
|
|
case id.Equals(gVtx.ID()):
|
|
return gVtx, nil
|
|
case id.Equals(mVtx.ID()):
|
|
return mVtx, nil
|
|
}
|
|
t.Fatalf("Unknown vertex")
|
|
panic("Should have errored")
|
|
}
|
|
|
|
te := &Transitive{}
|
|
te.Initialize(config)
|
|
te.finishBootstrapping()
|
|
|
|
queried := new(bool)
|
|
sender.PushQueryF = func(inVdrs ids.ShortSet, _ uint32, vtxID ids.ID, vtx []byte) {
|
|
*queried = true
|
|
}
|
|
|
|
te.insert(vtx)
|
|
|
|
if *queried {
|
|
t.Fatalf("Unknown query")
|
|
}
|
|
}
|
|
|
|
func TestEnginePushGossip(t *testing.T) {
|
|
config := DefaultConfig()
|
|
|
|
vdr := validators.GenerateRandomValidator(1)
|
|
vals := validators.NewSet()
|
|
vals.Add(vdr)
|
|
config.Validators = vals
|
|
|
|
sender := &common.SenderTest{}
|
|
sender.T = t
|
|
config.Sender = sender
|
|
|
|
sender.Default(true)
|
|
sender.CantGetAcceptedFrontier = false
|
|
|
|
st := &stateTest{t: t}
|
|
config.State = st
|
|
|
|
st.Default(true)
|
|
|
|
gVtx := &Vtx{
|
|
id: GenerateID(),
|
|
status: choices.Accepted,
|
|
}
|
|
mVtx := &Vtx{
|
|
id: GenerateID(),
|
|
status: choices.Accepted,
|
|
}
|
|
|
|
vts := []avalanche.Vertex{gVtx, mVtx}
|
|
|
|
vtx := &Vtx{
|
|
parents: vts,
|
|
id: GenerateID(),
|
|
height: 1,
|
|
status: choices.Processing,
|
|
bytes: []byte{0, 1, 2, 3},
|
|
}
|
|
|
|
st.edge = func() []ids.ID { return []ids.ID{vts[0].ID(), vts[1].ID()} }
|
|
st.getVertex = func(id ids.ID) (avalanche.Vertex, error) {
|
|
switch {
|
|
case id.Equals(gVtx.ID()):
|
|
return gVtx, nil
|
|
case id.Equals(mVtx.ID()):
|
|
return mVtx, nil
|
|
case id.Equals(vtx.ID()):
|
|
return vtx, nil
|
|
}
|
|
t.Fatalf("Unknown vertex")
|
|
panic("Should have errored")
|
|
}
|
|
|
|
te := &Transitive{}
|
|
te.Initialize(config)
|
|
te.finishBootstrapping()
|
|
|
|
requested := new(bool)
|
|
sender.GetF = func(vdr ids.ShortID, _ uint32, vtxID ids.ID) {
|
|
*requested = true
|
|
}
|
|
|
|
st.parseVertex = func(b []byte) (avalanche.Vertex, error) {
|
|
if bytes.Equal(b, vtx.bytes) {
|
|
return vtx, nil
|
|
}
|
|
t.Fatalf("Unknown vertex bytes")
|
|
panic("Should have errored")
|
|
}
|
|
|
|
sender.CantPushQuery = false
|
|
sender.CantChits = false
|
|
te.PushQuery(vdr.ID(), 0, vtx.ID(), vtx.Bytes())
|
|
|
|
if *requested {
|
|
t.Fatalf("Shouldn't have requested the vertex")
|
|
}
|
|
}
|
|
|
|
func TestEngineSingleQuery(t *testing.T) {
|
|
config := DefaultConfig()
|
|
|
|
vdr := validators.GenerateRandomValidator(1)
|
|
vals := validators.NewSet()
|
|
vals.Add(vdr)
|
|
config.Validators = vals
|
|
|
|
sender := &common.SenderTest{}
|
|
sender.T = t
|
|
config.Sender = sender
|
|
|
|
sender.Default(true)
|
|
sender.CantGetAcceptedFrontier = false
|
|
|
|
st := &stateTest{t: t}
|
|
config.State = st
|
|
|
|
st.Default(true)
|
|
|
|
gVtx := &Vtx{
|
|
id: GenerateID(),
|
|
status: choices.Accepted,
|
|
}
|
|
mVtx := &Vtx{
|
|
id: GenerateID(),
|
|
status: choices.Accepted,
|
|
}
|
|
|
|
vts := []avalanche.Vertex{gVtx, mVtx}
|
|
|
|
vtx := &Vtx{
|
|
parents: vts,
|
|
id: GenerateID(),
|
|
height: 1,
|
|
status: choices.Processing,
|
|
bytes: []byte{0, 1, 2, 3},
|
|
}
|
|
|
|
st.edge = func() []ids.ID { return []ids.ID{vts[0].ID(), vts[1].ID()} }
|
|
st.getVertex = func(id ids.ID) (avalanche.Vertex, error) {
|
|
switch {
|
|
case id.Equals(gVtx.ID()):
|
|
return gVtx, nil
|
|
case id.Equals(mVtx.ID()):
|
|
return mVtx, nil
|
|
case id.Equals(vtx.ID()):
|
|
return vtx, nil
|
|
}
|
|
t.Fatalf("Unknown vertex")
|
|
panic("Should have errored")
|
|
}
|
|
|
|
te := &Transitive{}
|
|
te.Initialize(config)
|
|
te.finishBootstrapping()
|
|
|
|
sender.CantPushQuery = false
|
|
sender.CantPullQuery = false
|
|
|
|
te.insert(vtx)
|
|
}
|
|
|
|
func TestEngineParentBlockingInsert(t *testing.T) {
|
|
config := DefaultConfig()
|
|
|
|
vdr := validators.GenerateRandomValidator(1)
|
|
vals := validators.NewSet()
|
|
vals.Add(vdr)
|
|
config.Validators = vals
|
|
|
|
sender := &common.SenderTest{}
|
|
sender.T = t
|
|
config.Sender = sender
|
|
|
|
sender.Default(true)
|
|
sender.CantGetAcceptedFrontier = false
|
|
|
|
st := &stateTest{t: t}
|
|
config.State = st
|
|
|
|
st.Default(true)
|
|
|
|
gVtx := &Vtx{
|
|
id: GenerateID(),
|
|
status: choices.Accepted,
|
|
}
|
|
mVtx := &Vtx{
|
|
id: GenerateID(),
|
|
status: choices.Accepted,
|
|
}
|
|
|
|
vts := []avalanche.Vertex{gVtx, mVtx}
|
|
|
|
missingVtx := &Vtx{
|
|
parents: vts,
|
|
id: GenerateID(),
|
|
height: 1,
|
|
status: choices.Unknown,
|
|
bytes: []byte{0, 1, 2, 3},
|
|
}
|
|
|
|
parentVtx := &Vtx{
|
|
parents: []avalanche.Vertex{missingVtx},
|
|
id: GenerateID(),
|
|
height: 1,
|
|
status: choices.Processing,
|
|
bytes: []byte{0, 1, 2, 3},
|
|
}
|
|
|
|
blockingVtx := &Vtx{
|
|
parents: []avalanche.Vertex{parentVtx},
|
|
id: GenerateID(),
|
|
height: 1,
|
|
status: choices.Processing,
|
|
bytes: []byte{0, 1, 2, 3},
|
|
}
|
|
|
|
st.edge = func() []ids.ID { return []ids.ID{vts[0].ID(), vts[1].ID()} }
|
|
st.getVertex = func(id ids.ID) (avalanche.Vertex, error) {
|
|
switch {
|
|
case id.Equals(gVtx.ID()):
|
|
return gVtx, nil
|
|
case id.Equals(mVtx.ID()):
|
|
return mVtx, nil
|
|
}
|
|
t.Fatalf("Unknown vertex")
|
|
panic("Should have errored")
|
|
}
|
|
|
|
te := &Transitive{}
|
|
te.Initialize(config)
|
|
te.finishBootstrapping()
|
|
|
|
te.insert(parentVtx)
|
|
te.insert(blockingVtx)
|
|
|
|
if len(te.vtxBlocked) != 2 {
|
|
t.Fatalf("Both inserts should be blocking")
|
|
}
|
|
|
|
sender.CantPushQuery = false
|
|
|
|
missingVtx.status = choices.Processing
|
|
te.insert(missingVtx)
|
|
|
|
if len(te.vtxBlocked) != 0 {
|
|
t.Fatalf("Both inserts should not longer be blocking")
|
|
}
|
|
}
|
|
|
|
func TestEngineBlockingChitRequest(t *testing.T) {
|
|
config := DefaultConfig()
|
|
|
|
vdr := validators.GenerateRandomValidator(1)
|
|
vals := validators.NewSet()
|
|
vals.Add(vdr)
|
|
config.Validators = vals
|
|
|
|
sender := &common.SenderTest{}
|
|
sender.T = t
|
|
config.Sender = sender
|
|
|
|
sender.Default(true)
|
|
sender.CantGetAcceptedFrontier = false
|
|
|
|
st := &stateTest{t: t}
|
|
config.State = st
|
|
|
|
st.Default(true)
|
|
|
|
gVtx := &Vtx{
|
|
id: GenerateID(),
|
|
status: choices.Accepted,
|
|
}
|
|
mVtx := &Vtx{
|
|
id: GenerateID(),
|
|
status: choices.Accepted,
|
|
}
|
|
|
|
vts := []avalanche.Vertex{gVtx, mVtx}
|
|
|
|
missingVtx := &Vtx{
|
|
parents: vts,
|
|
id: GenerateID(),
|
|
height: 1,
|
|
status: choices.Unknown,
|
|
bytes: []byte{0, 1, 2, 3},
|
|
}
|
|
|
|
parentVtx := &Vtx{
|
|
parents: []avalanche.Vertex{missingVtx},
|
|
id: GenerateID(),
|
|
height: 1,
|
|
status: choices.Processing,
|
|
bytes: []byte{1, 1, 2, 3},
|
|
}
|
|
|
|
blockingVtx := &Vtx{
|
|
parents: []avalanche.Vertex{parentVtx},
|
|
id: GenerateID(),
|
|
height: 1,
|
|
status: choices.Processing,
|
|
bytes: []byte{2, 1, 2, 3},
|
|
}
|
|
|
|
st.edge = func() []ids.ID { return []ids.ID{vts[0].ID(), vts[1].ID()} }
|
|
st.getVertex = func(id ids.ID) (avalanche.Vertex, error) {
|
|
switch {
|
|
case id.Equals(gVtx.ID()):
|
|
return gVtx, nil
|
|
case id.Equals(mVtx.ID()):
|
|
return mVtx, nil
|
|
}
|
|
t.Fatalf("Unknown vertex")
|
|
panic("Should have errored")
|
|
}
|
|
|
|
te := &Transitive{}
|
|
te.Initialize(config)
|
|
te.finishBootstrapping()
|
|
|
|
te.insert(parentVtx)
|
|
|
|
st.getVertex = func(vtxID ids.ID) (avalanche.Vertex, error) {
|
|
switch {
|
|
case vtxID.Equals(blockingVtx.ID()):
|
|
return blockingVtx, nil
|
|
}
|
|
t.Fatalf("Unknown vertex")
|
|
panic("Should have errored")
|
|
}
|
|
st.parseVertex = func(b []byte) (avalanche.Vertex, error) {
|
|
switch {
|
|
case bytes.Equal(b, blockingVtx.Bytes()):
|
|
return blockingVtx, nil
|
|
}
|
|
t.Fatalf("Unknown vertex")
|
|
panic("Should have errored")
|
|
}
|
|
|
|
te.PushQuery(vdr.ID(), 0, blockingVtx.ID(), blockingVtx.Bytes())
|
|
|
|
if len(te.vtxBlocked) != 3 {
|
|
t.Fatalf("Both inserts and the query should be blocking")
|
|
}
|
|
|
|
sender.CantPushQuery = false
|
|
sender.CantChits = false
|
|
|
|
missingVtx.status = choices.Processing
|
|
te.insert(missingVtx)
|
|
|
|
if len(te.vtxBlocked) != 0 {
|
|
t.Fatalf("Both inserts should not longer be blocking")
|
|
}
|
|
}
|
|
|
|
func TestEngineBlockingChitResponse(t *testing.T) {
|
|
config := DefaultConfig()
|
|
|
|
vdr := validators.GenerateRandomValidator(1)
|
|
vals := validators.NewSet()
|
|
vals.Add(vdr)
|
|
config.Validators = vals
|
|
|
|
sender := &common.SenderTest{}
|
|
sender.T = t
|
|
config.Sender = sender
|
|
|
|
sender.Default(true)
|
|
sender.CantGetAcceptedFrontier = false
|
|
|
|
st := &stateTest{t: t}
|
|
config.State = st
|
|
|
|
st.Default(true)
|
|
|
|
gVtx := &Vtx{
|
|
id: GenerateID(),
|
|
status: choices.Accepted,
|
|
}
|
|
mVtx := &Vtx{
|
|
id: GenerateID(),
|
|
status: choices.Accepted,
|
|
}
|
|
|
|
vts := []avalanche.Vertex{gVtx, mVtx}
|
|
|
|
issuedVtx := &Vtx{
|
|
parents: vts,
|
|
id: GenerateID(),
|
|
height: 1,
|
|
status: choices.Processing,
|
|
bytes: []byte{0, 1, 2, 3},
|
|
}
|
|
|
|
missingVtx := &Vtx{
|
|
parents: vts,
|
|
id: GenerateID(),
|
|
height: 1,
|
|
status: choices.Unknown,
|
|
bytes: []byte{0, 1, 2, 3},
|
|
}
|
|
|
|
blockingVtx := &Vtx{
|
|
parents: []avalanche.Vertex{missingVtx},
|
|
id: GenerateID(),
|
|
height: 1,
|
|
status: choices.Processing,
|
|
bytes: []byte{2, 1, 2, 3},
|
|
}
|
|
|
|
st.edge = func() []ids.ID { return []ids.ID{vts[0].ID(), vts[1].ID()} }
|
|
st.getVertex = func(id ids.ID) (avalanche.Vertex, error) {
|
|
switch {
|
|
case id.Equals(gVtx.ID()):
|
|
return gVtx, nil
|
|
case id.Equals(mVtx.ID()):
|
|
return mVtx, nil
|
|
}
|
|
t.Fatalf("Unknown vertex")
|
|
panic("Should have errored")
|
|
}
|
|
|
|
te := &Transitive{}
|
|
te.Initialize(config)
|
|
te.finishBootstrapping()
|
|
|
|
te.insert(blockingVtx)
|
|
|
|
queryRequestID := new(uint32)
|
|
sender.PushQueryF = func(inVdrs ids.ShortSet, requestID uint32, vtxID ids.ID, vtx []byte) {
|
|
*queryRequestID = requestID
|
|
vdrSet := ids.ShortSet{}
|
|
vdrSet.Add(vdr.ID())
|
|
if !inVdrs.Equals(vdrSet) {
|
|
t.Fatalf("Asking wrong validator for preference")
|
|
}
|
|
if !issuedVtx.ID().Equals(vtxID) {
|
|
t.Fatalf("Asking for wrong vertex")
|
|
}
|
|
}
|
|
|
|
te.insert(issuedVtx)
|
|
|
|
st.getVertex = func(id ids.ID) (avalanche.Vertex, error) {
|
|
switch {
|
|
case id.Equals(blockingVtx.ID()):
|
|
return blockingVtx, nil
|
|
}
|
|
t.Fatalf("Unknown vertex")
|
|
panic("Should have errored")
|
|
}
|
|
|
|
voteSet := ids.Set{}
|
|
voteSet.Add(blockingVtx.ID())
|
|
te.Chits(vdr.ID(), *queryRequestID, voteSet)
|
|
|
|
if len(te.vtxBlocked) != 2 {
|
|
t.Fatalf("The insert should be blocking, as well as the chit response")
|
|
}
|
|
|
|
sender.PushQueryF = nil
|
|
sender.CantPushQuery = false
|
|
sender.CantChits = false
|
|
|
|
missingVtx.status = choices.Processing
|
|
te.insert(missingVtx)
|
|
|
|
if len(te.vtxBlocked) != 0 {
|
|
t.Fatalf("Both inserts should not longer be blocking")
|
|
}
|
|
}
|
|
|
|
func TestEngineMissingTx(t *testing.T) {
|
|
config := DefaultConfig()
|
|
|
|
vdr := validators.GenerateRandomValidator(1)
|
|
vals := validators.NewSet()
|
|
vals.Add(vdr)
|
|
config.Validators = vals
|
|
|
|
sender := &common.SenderTest{}
|
|
sender.T = t
|
|
config.Sender = sender
|
|
|
|
sender.Default(true)
|
|
sender.CantGetAcceptedFrontier = false
|
|
|
|
st := &stateTest{t: t}
|
|
config.State = st
|
|
|
|
st.Default(true)
|
|
|
|
gVtx := &Vtx{
|
|
id: GenerateID(),
|
|
status: choices.Accepted,
|
|
}
|
|
mVtx := &Vtx{
|
|
id: GenerateID(),
|
|
status: choices.Accepted,
|
|
}
|
|
|
|
vts := []avalanche.Vertex{gVtx, mVtx}
|
|
|
|
issuedVtx := &Vtx{
|
|
parents: vts,
|
|
id: GenerateID(),
|
|
height: 1,
|
|
status: choices.Processing,
|
|
bytes: []byte{0, 1, 2, 3},
|
|
}
|
|
|
|
missingVtx := &Vtx{
|
|
parents: vts,
|
|
id: GenerateID(),
|
|
height: 1,
|
|
status: choices.Unknown,
|
|
bytes: []byte{0, 1, 2, 3},
|
|
}
|
|
|
|
blockingVtx := &Vtx{
|
|
parents: []avalanche.Vertex{missingVtx},
|
|
id: GenerateID(),
|
|
height: 1,
|
|
status: choices.Processing,
|
|
bytes: []byte{2, 1, 2, 3},
|
|
}
|
|
|
|
st.edge = func() []ids.ID { return []ids.ID{vts[0].ID(), vts[1].ID()} }
|
|
st.getVertex = func(id ids.ID) (avalanche.Vertex, error) {
|
|
switch {
|
|
case id.Equals(gVtx.ID()):
|
|
return gVtx, nil
|
|
case id.Equals(mVtx.ID()):
|
|
return mVtx, nil
|
|
}
|
|
t.Fatalf("Unknown vertex")
|
|
panic("Should have errored")
|
|
}
|
|
|
|
te := &Transitive{}
|
|
te.Initialize(config)
|
|
te.finishBootstrapping()
|
|
|
|
te.insert(blockingVtx)
|
|
|
|
queryRequestID := new(uint32)
|
|
sender.PushQueryF = func(inVdrs ids.ShortSet, requestID uint32, vtxID ids.ID, vtx []byte) {
|
|
*queryRequestID = requestID
|
|
vdrSet := ids.ShortSet{}
|
|
vdrSet.Add(vdr.ID())
|
|
if !inVdrs.Equals(vdrSet) {
|
|
t.Fatalf("Asking wrong validator for preference")
|
|
}
|
|
if !issuedVtx.ID().Equals(vtxID) {
|
|
t.Fatalf("Asking for wrong vertex")
|
|
}
|
|
}
|
|
|
|
te.insert(issuedVtx)
|
|
|
|
st.getVertex = func(id ids.ID) (avalanche.Vertex, error) {
|
|
switch {
|
|
case id.Equals(blockingVtx.ID()):
|
|
return blockingVtx, nil
|
|
}
|
|
t.Fatalf("Unknown vertex")
|
|
panic("Should have errored")
|
|
}
|
|
|
|
voteSet := ids.Set{}
|
|
voteSet.Add(blockingVtx.ID())
|
|
te.Chits(vdr.ID(), *queryRequestID, voteSet)
|
|
|
|
if len(te.vtxBlocked) != 2 {
|
|
t.Fatalf("The insert should be blocking, as well as the chit response")
|
|
}
|
|
|
|
sender.PushQueryF = nil
|
|
sender.CantPushQuery = false
|
|
sender.CantChits = false
|
|
|
|
missingVtx.status = choices.Processing
|
|
te.insert(missingVtx)
|
|
|
|
if len(te.vtxBlocked) != 0 {
|
|
t.Fatalf("Both inserts should not longer be blocking")
|
|
}
|
|
}
|
|
|
|
func TestEngineIssueBlockingTx(t *testing.T) {
|
|
config := DefaultConfig()
|
|
|
|
vdr := validators.GenerateRandomValidator(1)
|
|
|
|
vals := validators.NewSet()
|
|
config.Validators = vals
|
|
|
|
vals.Add(vdr)
|
|
|
|
st := &stateTest{t: t}
|
|
config.State = st
|
|
|
|
gVtx := &Vtx{
|
|
id: GenerateID(),
|
|
status: choices.Accepted,
|
|
}
|
|
|
|
vts := []avalanche.Vertex{gVtx}
|
|
utxos := []ids.ID{GenerateID(), GenerateID()}
|
|
|
|
tx0 := &TestTx{
|
|
TestTx: snowstorm.TestTx{
|
|
Identifier: GenerateID(),
|
|
Stat: choices.Processing,
|
|
},
|
|
}
|
|
tx0.Ins.Add(utxos[0])
|
|
|
|
tx1 := &TestTx{
|
|
TestTx: snowstorm.TestTx{
|
|
Identifier: GenerateID(),
|
|
Deps: []snowstorm.Tx{tx0},
|
|
Stat: choices.Processing,
|
|
},
|
|
}
|
|
tx1.Ins.Add(utxos[1])
|
|
|
|
vtx := &Vtx{
|
|
parents: vts,
|
|
id: GenerateID(),
|
|
txs: []snowstorm.Tx{tx0, tx1},
|
|
height: 1,
|
|
status: choices.Processing,
|
|
}
|
|
|
|
te := &Transitive{}
|
|
te.Initialize(config)
|
|
te.finishBootstrapping()
|
|
|
|
te.insert(vtx)
|
|
|
|
if prefs := te.Consensus.Preferences(); !prefs.Contains(vtx.ID()) {
|
|
t.Fatalf("Vertex should be preferred")
|
|
}
|
|
}
|
|
|
|
func TestEngineReissueAbortedVertex(t *testing.T) {
|
|
config := DefaultConfig()
|
|
|
|
vdr := validators.GenerateRandomValidator(1)
|
|
vdrID := vdr.ID()
|
|
|
|
vals := validators.NewSet()
|
|
config.Validators = vals
|
|
|
|
vals.Add(vdr)
|
|
|
|
sender := &common.SenderTest{}
|
|
sender.T = t
|
|
config.Sender = sender
|
|
|
|
sender.Default(true)
|
|
sender.CantGetAcceptedFrontier = false
|
|
|
|
st := &stateTest{t: t}
|
|
config.State = st
|
|
|
|
st.Default(true)
|
|
|
|
gVtx := &Vtx{
|
|
id: GenerateID(),
|
|
status: choices.Accepted,
|
|
}
|
|
|
|
vts := []avalanche.Vertex{gVtx}
|
|
|
|
vtxID0 := GenerateID()
|
|
vtxID1 := GenerateID()
|
|
|
|
vtxBytes0 := []byte{0}
|
|
vtxBytes1 := []byte{1}
|
|
|
|
vtx0 := &Vtx{
|
|
parents: vts,
|
|
id: vtxID0,
|
|
height: 1,
|
|
status: choices.Unknown,
|
|
bytes: vtxBytes0,
|
|
}
|
|
vtx1 := &Vtx{
|
|
parents: []avalanche.Vertex{vtx0},
|
|
id: vtxID1,
|
|
height: 2,
|
|
status: choices.Processing,
|
|
bytes: vtxBytes1,
|
|
}
|
|
|
|
st.edge = func() []ids.ID {
|
|
return []ids.ID{gVtx.ID()}
|
|
}
|
|
|
|
st.getVertex = func(vtxID ids.ID) (avalanche.Vertex, error) {
|
|
switch {
|
|
case vtxID.Equals(gVtx.ID()):
|
|
return gVtx, nil
|
|
}
|
|
t.Fatalf("Unknown vertex requested")
|
|
panic("Unknown vertex requested")
|
|
}
|
|
|
|
te := &Transitive{}
|
|
te.Initialize(config)
|
|
te.finishBootstrapping()
|
|
|
|
st.edge = nil
|
|
st.getVertex = nil
|
|
|
|
requestID := new(uint32)
|
|
sender.GetF = func(vID ids.ShortID, reqID uint32, vtxID ids.ID) {
|
|
*requestID = reqID
|
|
}
|
|
st.parseVertex = func(b []byte) (avalanche.Vertex, error) {
|
|
switch {
|
|
case bytes.Equal(b, vtxBytes1):
|
|
return vtx1, nil
|
|
}
|
|
t.Fatalf("Unknown bytes provided")
|
|
panic("Unknown bytes provided")
|
|
}
|
|
st.getVertex = func(vtxID ids.ID) (avalanche.Vertex, error) {
|
|
switch {
|
|
case vtxID.Equals(vtxID1):
|
|
return vtx1, nil
|
|
}
|
|
t.Fatalf("Unknown bytes provided")
|
|
panic("Unknown bytes provided")
|
|
}
|
|
|
|
te.PushQuery(vdrID, 0, vtxID1, vtx1.Bytes())
|
|
|
|
sender.GetF = nil
|
|
st.parseVertex = nil
|
|
|
|
te.GetFailed(vdrID, *requestID, vtxID0)
|
|
|
|
requested := new(bool)
|
|
sender.GetF = func(_ ids.ShortID, _ uint32, vtxID ids.ID) {
|
|
if vtxID.Equals(vtxID0) {
|
|
*requested = true
|
|
}
|
|
}
|
|
st.getVertex = func(vtxID ids.ID) (avalanche.Vertex, error) {
|
|
switch {
|
|
case vtxID.Equals(vtxID1):
|
|
return vtx1, nil
|
|
}
|
|
t.Fatalf("Unknown bytes provided")
|
|
panic("Unknown bytes provided")
|
|
}
|
|
|
|
te.PullQuery(vdrID, 0, vtxID1)
|
|
|
|
if !*requested {
|
|
t.Fatalf("Should have requested the missing vertex")
|
|
}
|
|
}
|
|
|
|
func TestEngineBootstrappingIntoConsensus(t *testing.T) {
|
|
config := DefaultConfig()
|
|
|
|
vdr := validators.GenerateRandomValidator(1)
|
|
vdrID := vdr.ID()
|
|
|
|
vals := validators.NewSet()
|
|
config.Validators = vals
|
|
config.Beacons = vals
|
|
|
|
vals.Add(vdr)
|
|
|
|
sender := &common.SenderTest{}
|
|
sender.T = t
|
|
config.Sender = sender
|
|
|
|
sender.Default(true)
|
|
|
|
st := &stateTest{t: t}
|
|
config.State = st
|
|
|
|
st.Default(true)
|
|
|
|
vm := &VMTest{}
|
|
vm.T = t
|
|
config.VM = vm
|
|
|
|
vm.Default(true)
|
|
|
|
utxos := []ids.ID{GenerateID(), GenerateID()}
|
|
|
|
txID0 := GenerateID()
|
|
txID1 := GenerateID()
|
|
|
|
txBytes0 := []byte{0}
|
|
txBytes1 := []byte{1}
|
|
|
|
tx0 := &TestTx{
|
|
TestTx: snowstorm.TestTx{
|
|
Identifier: txID0,
|
|
Stat: choices.Processing,
|
|
},
|
|
bytes: txBytes0,
|
|
}
|
|
tx0.Ins.Add(utxos[0])
|
|
|
|
tx1 := &TestTx{
|
|
TestTx: snowstorm.TestTx{
|
|
Identifier: txID1,
|
|
Deps: []snowstorm.Tx{tx0},
|
|
Stat: choices.Processing,
|
|
},
|
|
bytes: txBytes1,
|
|
}
|
|
tx1.Ins.Add(utxos[1])
|
|
|
|
vtxID0 := GenerateID()
|
|
vtxID1 := GenerateID()
|
|
|
|
vtxBytes0 := []byte{2}
|
|
vtxBytes1 := []byte{3}
|
|
|
|
vtx0 := &Vtx{
|
|
id: vtxID0,
|
|
txs: []snowstorm.Tx{tx0},
|
|
height: 1,
|
|
status: choices.Processing,
|
|
bytes: vtxBytes0,
|
|
}
|
|
vtx1 := &Vtx{
|
|
parents: []avalanche.Vertex{vtx0},
|
|
id: vtxID1,
|
|
txs: []snowstorm.Tx{tx1},
|
|
height: 2,
|
|
status: choices.Processing,
|
|
bytes: vtxBytes1,
|
|
}
|
|
|
|
requested := new(bool)
|
|
requestID := new(uint32)
|
|
sender.GetAcceptedFrontierF = func(vdrs ids.ShortSet, reqID uint32) {
|
|
if vdrs.Len() != 1 {
|
|
t.Fatalf("Should have requested from the validators")
|
|
}
|
|
if !vdrs.Contains(vdrID) {
|
|
t.Fatalf("Should have requested from %s", vdrID)
|
|
}
|
|
*requested = true
|
|
*requestID = reqID
|
|
}
|
|
|
|
te := &Transitive{}
|
|
te.Initialize(config)
|
|
te.Startup()
|
|
|
|
sender.GetAcceptedFrontierF = nil
|
|
|
|
if !*requested {
|
|
t.Fatalf("Should have requested from the validators during Initialize")
|
|
}
|
|
|
|
acceptedFrontier := ids.Set{}
|
|
acceptedFrontier.Add(vtxID0)
|
|
|
|
*requested = false
|
|
sender.GetAcceptedF = func(vdrs ids.ShortSet, reqID uint32, proposedAccepted ids.Set) {
|
|
if vdrs.Len() != 1 {
|
|
t.Fatalf("Should have requested from the validators")
|
|
}
|
|
if !vdrs.Contains(vdrID) {
|
|
t.Fatalf("Should have requested from %s", vdrID)
|
|
}
|
|
if !acceptedFrontier.Equals(proposedAccepted) {
|
|
t.Fatalf("Wrong proposedAccepted vertices.\nExpected: %s\nGot: %s", acceptedFrontier, proposedAccepted)
|
|
}
|
|
*requested = true
|
|
*requestID = reqID
|
|
}
|
|
|
|
te.AcceptedFrontier(vdrID, *requestID, acceptedFrontier)
|
|
|
|
if !*requested {
|
|
t.Fatalf("Should have requested from the validators during AcceptedFrontier")
|
|
}
|
|
|
|
st.getVertex = func(vtxID ids.ID) (avalanche.Vertex, error) {
|
|
switch {
|
|
case vtxID.Equals(vtxID0):
|
|
return nil, errMissing
|
|
}
|
|
t.Fatalf("Unknown vertex requested")
|
|
panic("Unknown vertex requested")
|
|
}
|
|
|
|
sender.GetF = func(inVdr ids.ShortID, reqID uint32, vtxID ids.ID) {
|
|
if !vdrID.Equals(inVdr) {
|
|
t.Fatalf("Asking wrong validator for vertex")
|
|
}
|
|
if !vtx0.ID().Equals(vtxID) {
|
|
t.Fatalf("Asking for wrong vertex")
|
|
}
|
|
*requestID = reqID
|
|
}
|
|
|
|
te.Accepted(vdrID, *requestID, acceptedFrontier)
|
|
|
|
st.getVertex = nil
|
|
sender.GetF = nil
|
|
|
|
vm.ParseTxF = func(b []byte) (snowstorm.Tx, error) {
|
|
switch {
|
|
case bytes.Equal(b, txBytes0):
|
|
return tx0, nil
|
|
}
|
|
t.Fatalf("Unknown bytes provided")
|
|
panic("Unknown bytes provided")
|
|
}
|
|
st.parseVertex = func(b []byte) (avalanche.Vertex, error) {
|
|
switch {
|
|
case bytes.Equal(b, vtxBytes0):
|
|
return vtx0, nil
|
|
}
|
|
t.Fatalf("Unknown bytes provided")
|
|
panic("Unknown bytes provided")
|
|
}
|
|
st.edge = func() []ids.ID {
|
|
return []ids.ID{vtxID0}
|
|
}
|
|
st.getVertex = func(vtxID ids.ID) (avalanche.Vertex, error) {
|
|
switch {
|
|
case vtxID.Equals(vtxID0):
|
|
return vtx0, nil
|
|
}
|
|
t.Fatalf("Unknown bytes provided")
|
|
panic("Unknown bytes provided")
|
|
}
|
|
|
|
te.Put(vdrID, *requestID, vtxID0, vtxBytes0)
|
|
|
|
vm.ParseTxF = nil
|
|
st.parseVertex = nil
|
|
st.edge = nil
|
|
st.getVertex = nil
|
|
|
|
if tx0.Status() != choices.Accepted {
|
|
t.Fatalf("Should have accepted %s", txID0)
|
|
}
|
|
if vtx0.Status() != choices.Accepted {
|
|
t.Fatalf("Should have accepted %s", vtxID0)
|
|
}
|
|
|
|
st.parseVertex = func(b []byte) (avalanche.Vertex, error) {
|
|
switch {
|
|
case bytes.Equal(b, vtxBytes1):
|
|
return vtx1, nil
|
|
}
|
|
t.Fatalf("Unknown bytes provided")
|
|
panic("Unknown bytes provided")
|
|
}
|
|
sender.ChitsF = func(inVdr ids.ShortID, _ uint32, chits ids.Set) {
|
|
if !inVdr.Equals(vdrID) {
|
|
t.Fatalf("Sent to the wrong validator")
|
|
}
|
|
|
|
expected := ids.Set{}
|
|
expected.Add(vtxID1)
|
|
|
|
if !expected.Equals(chits) {
|
|
t.Fatalf("Returned wrong chits")
|
|
}
|
|
}
|
|
sender.PushQueryF = func(vdrs ids.ShortSet, _ uint32, vtxID ids.ID, vtx []byte) {
|
|
if vdrs.Len() != 1 {
|
|
t.Fatalf("Should have requested from the validators")
|
|
}
|
|
if !vdrs.Contains(vdrID) {
|
|
t.Fatalf("Should have requested from %s", vdrID)
|
|
}
|
|
|
|
if !vtxID1.Equals(vtxID) {
|
|
t.Fatalf("Sent wrong query ID")
|
|
}
|
|
if !bytes.Equal(vtxBytes1, vtx) {
|
|
t.Fatalf("Sent wrong query bytes")
|
|
}
|
|
}
|
|
st.getVertex = func(vtxID ids.ID) (avalanche.Vertex, error) {
|
|
switch {
|
|
case vtxID.Equals(vtxID1):
|
|
return vtx1, nil
|
|
}
|
|
t.Fatalf("Unknown bytes provided")
|
|
panic("Unknown bytes provided")
|
|
}
|
|
|
|
te.PushQuery(vdrID, 0, vtxID1, vtxBytes1)
|
|
|
|
st.parseVertex = nil
|
|
sender.ChitsF = nil
|
|
sender.PushQueryF = nil
|
|
st.getVertex = nil
|
|
}
|