2022-08-29 14:25:30 +00:00
|
|
|
// stm: #unit
|
2020-10-08 20:49:36 +00:00
|
|
|
package sub
|
|
|
|
|
|
|
|
import (
|
2022-02-11 18:30:29 +00:00
|
|
|
"bytes"
|
2020-10-08 20:49:36 +00:00
|
|
|
"context"
|
|
|
|
"testing"
|
|
|
|
|
2022-02-11 18:30:29 +00:00
|
|
|
"github.com/golang/mock/gomock"
|
2023-03-25 07:33:05 +00:00
|
|
|
blocks "github.com/ipfs/go-block-format"
|
2020-10-08 20:49:36 +00:00
|
|
|
"github.com/ipfs/go-cid"
|
2023-05-05 19:02:31 +00:00
|
|
|
"github.com/ipni/go-libipni/announce/message"
|
2022-02-11 18:30:29 +00:00
|
|
|
pubsub "github.com/libp2p/go-libp2p-pubsub"
|
|
|
|
pb "github.com/libp2p/go-libp2p-pubsub/pb"
|
2023-09-21 15:37:02 +00:00
|
|
|
"github.com/libp2p/go-libp2p/core/crypto"
|
2022-08-25 18:20:41 +00:00
|
|
|
"github.com/libp2p/go-libp2p/core/peer"
|
2022-06-14 15:00:51 +00:00
|
|
|
|
|
|
|
"github.com/filecoin-project/go-address"
|
|
|
|
|
2023-09-21 15:37:02 +00:00
|
|
|
"github.com/filecoin-project/lotus/api"
|
2022-06-14 15:00:51 +00:00
|
|
|
"github.com/filecoin-project/lotus/api/mocks"
|
|
|
|
"github.com/filecoin-project/lotus/chain/types"
|
2020-10-08 20:49:36 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
type getter struct {
|
|
|
|
msgs []*types.Message
|
|
|
|
}
|
|
|
|
|
|
|
|
func (g *getter) GetBlock(ctx context.Context, c cid.Cid) (blocks.Block, error) { panic("NYI") }
|
|
|
|
|
|
|
|
func (g *getter) GetBlocks(ctx context.Context, ks []cid.Cid) <-chan blocks.Block {
|
|
|
|
ch := make(chan blocks.Block, len(g.msgs))
|
|
|
|
for _, m := range g.msgs {
|
|
|
|
by, err := m.Serialize()
|
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
b, err := blocks.NewBlockWithCid(by, m.Cid())
|
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
ch <- b
|
|
|
|
}
|
|
|
|
close(ch)
|
|
|
|
return ch
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestFetchCidsWithDedup(t *testing.T) {
|
|
|
|
msgs := []*types.Message{}
|
|
|
|
for i := 0; i < 10; i++ {
|
|
|
|
msgs = append(msgs, &types.Message{
|
|
|
|
From: address.TestAddress,
|
|
|
|
To: address.TestAddress,
|
|
|
|
|
|
|
|
Nonce: uint64(i),
|
|
|
|
})
|
|
|
|
}
|
|
|
|
cids := []cid.Cid{}
|
|
|
|
for _, m := range msgs {
|
|
|
|
cids = append(cids, m.Cid())
|
|
|
|
}
|
|
|
|
g := &getter{msgs}
|
|
|
|
|
2021-12-14 10:33:33 +00:00
|
|
|
//stm: @CHAIN_INCOMING_FETCH_MESSAGES_BY_CID_001
|
2020-10-08 20:49:36 +00:00
|
|
|
// the cids have a duplicate
|
|
|
|
res, err := FetchMessagesByCids(context.TODO(), g, append(cids, cids[0]))
|
|
|
|
|
|
|
|
t.Logf("err: %+v", err)
|
|
|
|
t.Logf("res: %+v", res)
|
|
|
|
if err == nil {
|
|
|
|
t.Errorf("there should be an error")
|
|
|
|
}
|
|
|
|
if err == nil && (res[0] == nil || res[len(res)-1] == nil) {
|
|
|
|
t.Fatalf("there is a nil message: first %p, last %p", res[0], res[len(res)-1])
|
|
|
|
}
|
|
|
|
}
|
2022-02-11 18:30:29 +00:00
|
|
|
|
|
|
|
func TestIndexerMessageValidator_Validate(t *testing.T) {
|
|
|
|
validCid, err := cid.Decode("QmbpDgg5kRLDgMxS8vPKNFXEcA6D5MC4CkuUdSWDVtHPGK")
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
tests := []struct {
|
|
|
|
name string
|
|
|
|
selfPID string
|
|
|
|
senderPID string
|
|
|
|
extraData []byte
|
|
|
|
wantValidation pubsub.ValidationResult
|
|
|
|
}{
|
|
|
|
{
|
|
|
|
name: "invalid extra data is rejected",
|
|
|
|
selfPID: "12D3KooWQiCbqEStCkdqUvr69gQsrp9urYJZUCkzsQXia7mbqbFW",
|
|
|
|
senderPID: "12D3KooWE8yt84RVwW3sFcd6WMjbUdWrZer2YtT4dmtj3dHdahSZ",
|
|
|
|
extraData: []byte("f0127896"), // note, casting encoded address to byte is invalid.
|
|
|
|
wantValidation: pubsub.ValidationReject,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "same sender and receiver is ignored",
|
|
|
|
selfPID: "12D3KooWQiCbqEStCkdqUvr69gQsrp9urYJZUCkzsQXia7mbqbFW",
|
|
|
|
senderPID: "12D3KooWQiCbqEStCkdqUvr69gQsrp9urYJZUCkzsQXia7mbqbFW",
|
|
|
|
wantValidation: pubsub.ValidationIgnore,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
for _, tc := range tests {
|
|
|
|
tc := tc
|
|
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
|
|
mc := gomock.NewController(t)
|
|
|
|
node := mocks.NewMockFullNode(mc)
|
|
|
|
subject := NewIndexerMessageValidator(peer.ID(tc.selfPID), node, node)
|
2023-03-07 19:43:23 +00:00
|
|
|
message := message.Message{
|
2022-02-11 18:30:29 +00:00
|
|
|
Cid: validCid,
|
|
|
|
Addrs: nil,
|
|
|
|
ExtraData: tc.extraData,
|
|
|
|
}
|
|
|
|
buf := bytes.NewBuffer(nil)
|
|
|
|
if err := message.MarshalCBOR(buf); err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
topic := "topic"
|
|
|
|
pbm := &pb.Message{
|
|
|
|
Data: buf.Bytes(),
|
|
|
|
Topic: &topic,
|
|
|
|
From: nil,
|
|
|
|
Seqno: nil,
|
|
|
|
}
|
|
|
|
validate := subject.Validate(context.Background(), peer.ID(tc.senderPID), &pubsub.Message{
|
|
|
|
Message: pbm,
|
|
|
|
ReceivedFrom: peer.ID(tc.senderPID),
|
|
|
|
ValidatorData: nil,
|
|
|
|
})
|
|
|
|
|
|
|
|
if validate != tc.wantValidation {
|
|
|
|
t.Fatalf("expected %v but got %v", tc.wantValidation, validate)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
2023-09-21 15:37:02 +00:00
|
|
|
|
|
|
|
func TestIdxValidator(t *testing.T) {
|
|
|
|
validCid, err := cid.Decode("QmbpDgg5kRLDgMxS8vPKNFXEcA6D5MC4CkuUdSWDVtHPGK")
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
addr, err := address.NewFromString("f01024")
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
buf1, err := addr.MarshalBinary()
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
selfPID := "12D3KooWQiCbqEStCkdqUvr69gQsrp9urYJZUCkzsQXia7mbqbFW"
|
|
|
|
senderPID := "12D3KooWE8yt84RVwW3sFcd6WMjbUdWrZer2YtT4dmtj3dHdahSZ"
|
|
|
|
extraData := buf1
|
|
|
|
|
|
|
|
mc := gomock.NewController(t)
|
|
|
|
node := mocks.NewMockFullNode(mc)
|
|
|
|
node.EXPECT().ChainHead(gomock.Any()).Return(nil, nil).AnyTimes()
|
|
|
|
|
|
|
|
subject := NewIndexerMessageValidator(peer.ID(selfPID), node, node)
|
|
|
|
message := message.Message{
|
|
|
|
Cid: validCid,
|
|
|
|
Addrs: nil,
|
|
|
|
ExtraData: extraData,
|
|
|
|
}
|
|
|
|
buf := bytes.NewBuffer(nil)
|
|
|
|
if err := message.MarshalCBOR(buf); err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
topic := "topic"
|
|
|
|
|
|
|
|
privk, _, err := crypto.GenerateKeyPair(crypto.RSA, 2048)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
id, err := peer.IDFromPublicKey(privk.GetPublic())
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
node.EXPECT().StateMinerInfo(gomock.Any(), gomock.Any(), gomock.Any()).Return(api.MinerInfo{PeerId: &id}, nil).AnyTimes()
|
|
|
|
|
|
|
|
pbm := &pb.Message{
|
|
|
|
Data: buf.Bytes(),
|
|
|
|
Topic: &topic,
|
|
|
|
From: []byte(id),
|
|
|
|
Seqno: []byte{1, 1, 1, 1, 2, 2, 2, 2},
|
|
|
|
}
|
|
|
|
validate := subject.Validate(context.Background(), peer.ID(senderPID), &pubsub.Message{
|
|
|
|
Message: pbm,
|
|
|
|
ReceivedFrom: peer.ID("f01024"), // peer.ID(senderPID),
|
|
|
|
ValidatorData: nil,
|
|
|
|
})
|
|
|
|
if validate != pubsub.ValidationAccept {
|
|
|
|
t.Error("Expected to receive ValidationAccept")
|
|
|
|
}
|
|
|
|
msgInfo, cached := subject.peerCache.Get(addr)
|
|
|
|
if !cached {
|
|
|
|
t.Fatal("Message info should be in cache")
|
|
|
|
}
|
|
|
|
seqno := msgInfo.lastSeqno
|
|
|
|
msgInfo.rateLimit = nil // prevent interference from rate limiting
|
|
|
|
|
|
|
|
t.Log("Sending DoS msg")
|
|
|
|
privk, _, err = crypto.GenerateKeyPair(crypto.RSA, 2048)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
id2, err := peer.IDFromPublicKey(privk.GetPublic())
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
pbm = &pb.Message{
|
|
|
|
Data: buf.Bytes(),
|
|
|
|
Topic: &topic,
|
|
|
|
From: []byte(id2),
|
|
|
|
Seqno: []byte{255, 255, 255, 255, 255, 255, 255, 255},
|
|
|
|
}
|
|
|
|
validate = subject.Validate(context.Background(), peer.ID(senderPID), &pubsub.Message{
|
|
|
|
Message: pbm,
|
|
|
|
ReceivedFrom: peer.ID(senderPID),
|
|
|
|
ValidatorData: nil,
|
|
|
|
})
|
|
|
|
if validate != pubsub.ValidationReject {
|
|
|
|
t.Error("Expected to get ValidationReject")
|
|
|
|
}
|
|
|
|
msgInfo, cached = subject.peerCache.Get(addr)
|
|
|
|
if !cached {
|
|
|
|
t.Fatal("Message info should be in cache")
|
|
|
|
}
|
|
|
|
msgInfo.rateLimit = nil // prevent interference from rate limiting
|
|
|
|
|
|
|
|
// Check if DoS is possible.
|
|
|
|
if msgInfo.lastSeqno != seqno {
|
|
|
|
t.Fatal("Sequence number should not have been updated")
|
|
|
|
}
|
|
|
|
|
|
|
|
t.Log("Sending another valid message from miner...")
|
|
|
|
pbm = &pb.Message{
|
|
|
|
Data: buf.Bytes(),
|
|
|
|
Topic: &topic,
|
|
|
|
From: []byte(id),
|
|
|
|
Seqno: []byte{1, 1, 1, 1, 2, 2, 2, 3},
|
|
|
|
}
|
|
|
|
validate = subject.Validate(context.Background(), peer.ID(senderPID), &pubsub.Message{
|
|
|
|
Message: pbm,
|
|
|
|
ReceivedFrom: peer.ID("f01024"), // peer.ID(senderPID),
|
|
|
|
ValidatorData: nil,
|
|
|
|
})
|
|
|
|
if validate != pubsub.ValidationAccept {
|
|
|
|
t.Fatal("Did not receive ValidationAccept")
|
|
|
|
}
|
|
|
|
}
|