2019-07-29 19:34:34 +00:00
|
|
|
package chain_test
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"fmt"
|
|
|
|
"testing"
|
|
|
|
|
2019-07-30 13:55:36 +00:00
|
|
|
logging "github.com/ipfs/go-log"
|
2019-07-29 19:34:34 +00:00
|
|
|
mocknet "github.com/libp2p/go-libp2p/p2p/net/mock"
|
2019-07-30 11:45:48 +00:00
|
|
|
"github.com/stretchr/testify/require"
|
2019-07-29 19:34:34 +00:00
|
|
|
|
|
|
|
"github.com/filecoin-project/go-lotus/api"
|
2019-07-30 16:04:36 +00:00
|
|
|
"github.com/filecoin-project/go-lotus/chain"
|
2019-07-29 19:34:34 +00:00
|
|
|
"github.com/filecoin-project/go-lotus/chain/gen"
|
2019-09-03 04:36:07 +00:00
|
|
|
"github.com/filecoin-project/go-lotus/chain/store"
|
2019-07-30 16:04:36 +00:00
|
|
|
"github.com/filecoin-project/go-lotus/chain/types"
|
2019-07-29 19:34:34 +00:00
|
|
|
"github.com/filecoin-project/go-lotus/node"
|
|
|
|
"github.com/filecoin-project/go-lotus/node/modules"
|
|
|
|
"github.com/filecoin-project/go-lotus/node/repo"
|
|
|
|
)
|
|
|
|
|
2019-07-30 13:55:36 +00:00
|
|
|
const source = 0
|
|
|
|
|
2019-09-03 04:36:07 +00:00
|
|
|
func (tu *syncTestUtil) repoWithChain(t testing.TB, h int) (repo.Repo, []byte, []*store.FullTipSet) {
|
|
|
|
blks := make([]*store.FullTipSet, h)
|
2019-07-30 16:04:36 +00:00
|
|
|
|
2019-07-29 19:34:34 +00:00
|
|
|
for i := 0; i < h; i++ {
|
2019-09-03 04:36:07 +00:00
|
|
|
mts, err := tu.g.NextTipSet()
|
2019-07-30 11:45:48 +00:00
|
|
|
require.NoError(t, err)
|
2019-07-30 16:04:36 +00:00
|
|
|
|
2019-09-03 04:36:07 +00:00
|
|
|
blks[i] = mts.TipSet
|
2019-07-30 16:04:36 +00:00
|
|
|
|
2019-09-03 04:36:07 +00:00
|
|
|
ts := mts.TipSet.TipSet()
|
|
|
|
fmt.Printf("tipset at H:%d: %s\n", ts.Height(), ts.Cids())
|
|
|
|
|
2019-07-29 19:34:34 +00:00
|
|
|
}
|
|
|
|
|
2019-08-02 22:21:46 +00:00
|
|
|
r, err := tu.g.YieldRepo()
|
2019-07-30 11:45:48 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
|
2019-08-02 22:21:46 +00:00
|
|
|
genb, err := tu.g.GenesisCar()
|
2019-07-30 11:45:48 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
|
2019-07-30 16:04:36 +00:00
|
|
|
return r, genb, blks
|
2019-07-29 19:34:34 +00:00
|
|
|
}
|
|
|
|
|
2019-07-30 13:20:40 +00:00
|
|
|
type syncTestUtil struct {
|
2019-08-30 07:05:21 +00:00
|
|
|
t testing.TB
|
2019-07-29 19:34:34 +00:00
|
|
|
|
2019-08-30 07:05:21 +00:00
|
|
|
ctx context.Context
|
|
|
|
cancel func()
|
|
|
|
|
|
|
|
mn mocknet.Mocknet
|
2019-07-29 19:34:34 +00:00
|
|
|
|
2019-08-02 22:21:46 +00:00
|
|
|
g *gen.ChainGen
|
|
|
|
|
2019-07-30 13:20:40 +00:00
|
|
|
genesis []byte
|
2019-09-03 04:36:07 +00:00
|
|
|
blocks []*store.FullTipSet
|
2019-07-30 13:20:40 +00:00
|
|
|
|
|
|
|
nds []api.FullNode
|
|
|
|
}
|
|
|
|
|
2019-08-30 07:05:21 +00:00
|
|
|
func prepSyncTest(t testing.TB, h int) *syncTestUtil {
|
2019-07-30 16:04:36 +00:00
|
|
|
logging.SetLogLevel("*", "INFO")
|
|
|
|
|
2019-08-02 22:21:46 +00:00
|
|
|
g, err := gen.NewGenerator()
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
2019-08-30 07:05:21 +00:00
|
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
|
|
|
2019-07-30 16:04:36 +00:00
|
|
|
tu := &syncTestUtil{
|
2019-08-30 07:05:21 +00:00
|
|
|
t: t,
|
|
|
|
ctx: ctx,
|
|
|
|
cancel: cancel,
|
|
|
|
|
|
|
|
mn: mocknet.New(ctx),
|
|
|
|
g: g,
|
2019-07-30 16:04:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
tu.addSourceNode(h)
|
2019-09-06 20:03:28 +00:00
|
|
|
//tu.checkHeight("source", source, h)
|
2019-07-30 16:04:36 +00:00
|
|
|
|
|
|
|
// separate logs
|
|
|
|
fmt.Println("\x1b[31m///////////////////////////////////////////////////\x1b[39b")
|
|
|
|
|
|
|
|
return tu
|
|
|
|
}
|
|
|
|
|
2019-08-30 07:05:21 +00:00
|
|
|
func (tu *syncTestUtil) Shutdown() {
|
|
|
|
tu.cancel()
|
|
|
|
}
|
|
|
|
|
2019-08-02 23:14:58 +00:00
|
|
|
func (tu *syncTestUtil) mineNewBlock(src int) {
|
2019-09-03 04:36:07 +00:00
|
|
|
mts, err := tu.g.NextTipSet()
|
2019-08-02 23:14:58 +00:00
|
|
|
require.NoError(tu.t, err)
|
|
|
|
|
2019-09-03 04:36:07 +00:00
|
|
|
for _, msg := range mts.Messages {
|
2019-08-02 23:14:58 +00:00
|
|
|
require.NoError(tu.t, tu.nds[src].MpoolPush(context.TODO(), msg))
|
|
|
|
}
|
|
|
|
|
2019-09-03 04:36:07 +00:00
|
|
|
for _, fblk := range mts.TipSet.Blocks {
|
|
|
|
require.NoError(tu.t, tu.nds[src].ChainSubmitBlock(context.TODO(), fblkToBlkMsg(fblk)))
|
|
|
|
}
|
2019-08-02 23:14:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func fblkToBlkMsg(fb *types.FullBlock) *chain.BlockMsg {
|
|
|
|
out := &chain.BlockMsg{
|
|
|
|
Header: fb.Header,
|
|
|
|
}
|
|
|
|
|
2019-08-05 19:27:26 +00:00
|
|
|
for _, msg := range fb.BlsMessages {
|
|
|
|
out.BlsMessages = append(out.BlsMessages, msg.Cid())
|
|
|
|
}
|
|
|
|
for _, msg := range fb.SecpkMessages {
|
|
|
|
out.SecpkMessages = append(out.SecpkMessages, msg.Cid())
|
2019-08-02 23:14:58 +00:00
|
|
|
}
|
|
|
|
return out
|
|
|
|
}
|
|
|
|
|
2019-07-30 13:55:36 +00:00
|
|
|
func (tu *syncTestUtil) addSourceNode(gen int) {
|
2019-07-30 13:20:40 +00:00
|
|
|
if tu.genesis != nil {
|
|
|
|
tu.t.Fatal("source node already exists")
|
|
|
|
}
|
2019-07-29 19:34:34 +00:00
|
|
|
|
2019-08-02 22:21:46 +00:00
|
|
|
sourceRepo, genesis, blocks := tu.repoWithChain(tu.t, gen)
|
2019-07-30 13:20:40 +00:00
|
|
|
var out api.FullNode
|
2019-07-30 11:45:48 +00:00
|
|
|
|
2019-07-30 13:20:40 +00:00
|
|
|
err := node.New(tu.ctx,
|
|
|
|
node.FullAPI(&out),
|
2019-07-29 19:34:34 +00:00
|
|
|
node.Online(),
|
2019-07-30 11:45:48 +00:00
|
|
|
node.Repo(sourceRepo),
|
2019-07-30 13:20:40 +00:00
|
|
|
node.MockHost(tu.mn),
|
2019-07-29 19:34:34 +00:00
|
|
|
|
2019-07-30 11:45:48 +00:00
|
|
|
node.Override(new(modules.Genesis), modules.LoadGenesis(genesis)),
|
2019-07-29 19:34:34 +00:00
|
|
|
)
|
2019-07-30 13:20:40 +00:00
|
|
|
require.NoError(tu.t, err)
|
2019-07-29 19:34:34 +00:00
|
|
|
|
2019-07-30 13:20:40 +00:00
|
|
|
tu.genesis = genesis
|
2019-07-30 16:04:36 +00:00
|
|
|
tu.blocks = blocks
|
2019-07-30 13:55:36 +00:00
|
|
|
tu.nds = append(tu.nds, out) // always at 0
|
2019-07-30 13:20:40 +00:00
|
|
|
}
|
2019-07-30 11:45:48 +00:00
|
|
|
|
2019-07-30 13:20:40 +00:00
|
|
|
func (tu *syncTestUtil) addClientNode() int {
|
2019-07-30 13:55:36 +00:00
|
|
|
if tu.genesis == nil {
|
|
|
|
tu.t.Fatal("source doesn't exists")
|
|
|
|
}
|
|
|
|
|
2019-07-30 13:20:40 +00:00
|
|
|
var out api.FullNode
|
2019-07-29 19:34:34 +00:00
|
|
|
|
2019-07-30 13:20:40 +00:00
|
|
|
err := node.New(tu.ctx,
|
|
|
|
node.FullAPI(&out),
|
2019-07-29 19:34:34 +00:00
|
|
|
node.Online(),
|
|
|
|
node.Repo(repo.NewMemory(nil)),
|
2019-07-30 13:20:40 +00:00
|
|
|
node.MockHost(tu.mn),
|
2019-07-29 19:34:34 +00:00
|
|
|
|
2019-07-30 13:20:40 +00:00
|
|
|
node.Override(new(modules.Genesis), modules.LoadGenesis(tu.genesis)),
|
2019-07-29 19:34:34 +00:00
|
|
|
)
|
2019-07-30 13:20:40 +00:00
|
|
|
require.NoError(tu.t, err)
|
|
|
|
|
|
|
|
tu.nds = append(tu.nds, out)
|
|
|
|
return len(tu.nds) - 1
|
|
|
|
}
|
|
|
|
|
2019-07-30 13:55:36 +00:00
|
|
|
func (tu *syncTestUtil) connect(from, to int) {
|
|
|
|
toPI, err := tu.nds[to].NetAddrsListen(tu.ctx)
|
|
|
|
require.NoError(tu.t, err)
|
2019-07-30 13:20:40 +00:00
|
|
|
|
2019-07-30 13:55:36 +00:00
|
|
|
err = tu.nds[from].NetConnect(tu.ctx, toPI)
|
|
|
|
require.NoError(tu.t, err)
|
|
|
|
}
|
2019-07-30 13:20:40 +00:00
|
|
|
|
2019-07-30 13:55:36 +00:00
|
|
|
func (tu *syncTestUtil) checkHeight(name string, n int, h int) {
|
|
|
|
b, err := tu.nds[n].ChainHead(tu.ctx)
|
|
|
|
require.NoError(tu.t, err)
|
2019-07-30 13:20:40 +00:00
|
|
|
|
2019-07-30 13:55:36 +00:00
|
|
|
require.Equal(tu.t, uint64(h), b.Height())
|
|
|
|
fmt.Printf("%s H: %d\n", name, b.Height())
|
|
|
|
}
|
2019-07-30 13:20:40 +00:00
|
|
|
|
2019-07-30 13:55:36 +00:00
|
|
|
func (tu *syncTestUtil) compareSourceState(with int) {
|
2019-09-06 20:03:28 +00:00
|
|
|
sourceHead, err := tu.nds[source].ChainHead(tu.ctx)
|
|
|
|
require.NoError(tu.t, err)
|
|
|
|
|
|
|
|
targetHead, err := tu.nds[with].ChainHead(tu.ctx)
|
|
|
|
require.NoError(tu.t, err)
|
|
|
|
|
|
|
|
if !sourceHead.Equals(targetHead) {
|
|
|
|
fmt.Println("different chains: ", sourceHead.Height(), targetHead.Height())
|
|
|
|
tu.t.Fatalf("nodes were not synced correctly: %s != %s", sourceHead.Cids(), targetHead.Cids())
|
|
|
|
}
|
|
|
|
|
2019-07-30 13:55:36 +00:00
|
|
|
sourceAccounts, err := tu.nds[source].WalletList(tu.ctx)
|
|
|
|
require.NoError(tu.t, err)
|
2019-07-30 13:20:40 +00:00
|
|
|
|
2019-07-30 13:55:36 +00:00
|
|
|
for _, addr := range sourceAccounts {
|
|
|
|
sourceBalance, err := tu.nds[source].WalletBalance(tu.ctx, addr)
|
|
|
|
require.NoError(tu.t, err)
|
2019-07-30 16:04:36 +00:00
|
|
|
fmt.Printf("Source state check for %s, expect %s\n", addr, sourceBalance)
|
2019-07-30 11:45:48 +00:00
|
|
|
|
2019-07-30 13:55:36 +00:00
|
|
|
actBalance, err := tu.nds[with].WalletBalance(tu.ctx, addr)
|
|
|
|
require.NoError(tu.t, err)
|
2019-07-30 13:20:40 +00:00
|
|
|
|
2019-07-30 13:55:36 +00:00
|
|
|
require.Equal(tu.t, sourceBalance, actBalance)
|
2019-07-30 16:04:36 +00:00
|
|
|
fmt.Printf("Source state check <OK> for %s\n", addr)
|
2019-07-30 13:55:36 +00:00
|
|
|
}
|
|
|
|
}
|
2019-07-30 13:20:40 +00:00
|
|
|
|
2019-08-30 07:05:21 +00:00
|
|
|
func (tu *syncTestUtil) waitUntilSync(from, to int) {
|
|
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
|
|
defer cancel()
|
|
|
|
|
|
|
|
target, err := tu.nds[from].ChainHead(ctx)
|
|
|
|
if err != nil {
|
|
|
|
tu.t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
hc, err := tu.nds[to].ChainNotify(ctx)
|
|
|
|
if err != nil {
|
|
|
|
tu.t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO: some sort of timeout?
|
|
|
|
for c := range hc {
|
|
|
|
if c.Val.Equals(target) {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-09-03 04:36:07 +00:00
|
|
|
/*
|
2019-07-30 16:04:36 +00:00
|
|
|
func (tu *syncTestUtil) submitSourceBlock(to int, h int) {
|
|
|
|
// utility to simulate incoming blocks without miner process
|
2019-07-30 16:39:07 +00:00
|
|
|
// TODO: should call syncer directly, this won't work correctly in all cases
|
2019-07-30 13:20:40 +00:00
|
|
|
|
2019-07-30 16:04:36 +00:00
|
|
|
var b chain.BlockMsg
|
|
|
|
|
|
|
|
// -1 to match block.Height
|
2019-07-31 07:13:49 +00:00
|
|
|
b.Header = tu.blocks[h-1].Header
|
2019-08-01 20:40:47 +00:00
|
|
|
for _, msg := range tu.blocks[h-1].SecpkMessages {
|
2019-08-20 17:19:24 +00:00
|
|
|
c, err := tu.nds[to].(*impl.FullNodeAPI).ChainAPI.Chain.PutMessage(msg)
|
2019-07-30 16:04:36 +00:00
|
|
|
require.NoError(tu.t, err)
|
|
|
|
|
2019-08-01 20:40:47 +00:00
|
|
|
b.SecpkMessages = append(b.SecpkMessages, c)
|
2019-07-30 13:55:36 +00:00
|
|
|
}
|
2019-07-30 11:45:48 +00:00
|
|
|
|
2019-07-30 16:04:36 +00:00
|
|
|
require.NoError(tu.t, tu.nds[to].ChainSubmitBlock(tu.ctx, &b))
|
|
|
|
}
|
|
|
|
|
|
|
|
func (tu *syncTestUtil) submitSourceBlocks(to int, h int, n int) {
|
|
|
|
for i := 0; i < n; i++ {
|
2019-07-31 07:13:49 +00:00
|
|
|
tu.submitSourceBlock(to, h+i)
|
2019-07-30 16:04:36 +00:00
|
|
|
}
|
|
|
|
}
|
2019-09-03 04:36:07 +00:00
|
|
|
*/
|
2019-07-30 11:45:48 +00:00
|
|
|
|
2019-07-30 16:04:36 +00:00
|
|
|
func TestSyncSimple(t *testing.T) {
|
2019-08-02 22:21:46 +00:00
|
|
|
H := 50
|
2019-07-30 16:04:36 +00:00
|
|
|
tu := prepSyncTest(t, H)
|
2019-07-30 11:45:48 +00:00
|
|
|
|
2019-07-30 13:55:36 +00:00
|
|
|
client := tu.addClientNode()
|
2019-09-06 20:03:28 +00:00
|
|
|
//tu.checkHeight("client", client, 0)
|
2019-07-30 11:45:48 +00:00
|
|
|
|
2019-07-30 13:55:36 +00:00
|
|
|
require.NoError(t, tu.mn.LinkAll())
|
|
|
|
tu.connect(1, 0)
|
2019-08-31 01:11:32 +00:00
|
|
|
tu.waitUntilSync(0, client)
|
2019-07-30 16:04:36 +00:00
|
|
|
|
2019-09-06 20:03:28 +00:00
|
|
|
//tu.checkHeight("client", client, H)
|
2019-07-30 16:04:36 +00:00
|
|
|
|
|
|
|
tu.compareSourceState(client)
|
|
|
|
}
|
|
|
|
|
2019-08-02 22:21:46 +00:00
|
|
|
func TestSyncMining(t *testing.T) {
|
2019-09-03 04:36:07 +00:00
|
|
|
H := 50
|
2019-08-02 22:21:46 +00:00
|
|
|
tu := prepSyncTest(t, H)
|
|
|
|
|
|
|
|
client := tu.addClientNode()
|
2019-09-06 20:03:28 +00:00
|
|
|
//tu.checkHeight("client", client, 0)
|
2019-08-02 22:21:46 +00:00
|
|
|
|
|
|
|
require.NoError(t, tu.mn.LinkAll())
|
2019-08-30 07:05:21 +00:00
|
|
|
tu.connect(client, 0)
|
2019-08-31 01:03:10 +00:00
|
|
|
fmt.Println("waiting for sync...")
|
2019-08-30 07:05:21 +00:00
|
|
|
tu.waitUntilSync(0, client)
|
2019-08-02 22:21:46 +00:00
|
|
|
|
2019-08-31 01:03:10 +00:00
|
|
|
fmt.Println("after wait until sync")
|
|
|
|
|
2019-09-06 20:03:28 +00:00
|
|
|
//tu.checkHeight("client", client, H)
|
2019-08-02 22:21:46 +00:00
|
|
|
|
|
|
|
tu.compareSourceState(client)
|
|
|
|
|
2019-08-02 23:14:58 +00:00
|
|
|
for i := 0; i < 5; i++ {
|
|
|
|
tu.mineNewBlock(0)
|
2019-08-31 01:11:32 +00:00
|
|
|
tu.waitUntilSync(0, client)
|
2019-08-02 23:14:58 +00:00
|
|
|
tu.compareSourceState(client)
|
2019-08-02 22:21:46 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-08-30 07:05:21 +00:00
|
|
|
func BenchmarkSyncBasic(b *testing.B) {
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
|
|
runSyncBenchLength(b, 100)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func runSyncBenchLength(b *testing.B, l int) {
|
|
|
|
tu := prepSyncTest(b, l)
|
|
|
|
|
|
|
|
client := tu.addClientNode()
|
|
|
|
tu.checkHeight("client", client, 0)
|
|
|
|
|
|
|
|
b.ResetTimer()
|
|
|
|
|
|
|
|
require.NoError(b, tu.mn.LinkAll())
|
|
|
|
tu.connect(1, 0)
|
|
|
|
|
|
|
|
tu.waitUntilSync(0, client)
|
|
|
|
}
|
|
|
|
|
2019-07-30 17:26:53 +00:00
|
|
|
/*
|
|
|
|
TODO: this is broken because of how tu.submitSourceBlock works now
|
2019-07-30 16:04:36 +00:00
|
|
|
func TestSyncManual(t *testing.T) {
|
2019-07-30 16:39:07 +00:00
|
|
|
H := 20
|
2019-07-30 16:04:36 +00:00
|
|
|
tu := prepSyncTest(t, H)
|
|
|
|
|
|
|
|
client := tu.addClientNode()
|
|
|
|
tu.checkHeight("client", client, 0)
|
|
|
|
|
|
|
|
tu.submitSourceBlocks(client, 1, H)
|
|
|
|
|
2019-07-30 13:20:40 +00:00
|
|
|
time.Sleep(time.Second * 1)
|
2019-07-29 19:34:34 +00:00
|
|
|
|
2019-07-30 13:55:36 +00:00
|
|
|
tu.checkHeight("client", client, H)
|
|
|
|
|
|
|
|
tu.compareSourceState(client)
|
2019-07-29 19:34:34 +00:00
|
|
|
}
|
2019-07-30 16:39:07 +00:00
|
|
|
|
|
|
|
func TestSyncIncoming(t *testing.T) {
|
|
|
|
H := 1
|
|
|
|
tu := prepSyncTest(t, H)
|
|
|
|
|
|
|
|
producer := tu.addClientNode()
|
|
|
|
client := tu.addClientNode()
|
|
|
|
|
|
|
|
tu.mn.LinkAll()
|
|
|
|
tu.connect(client, producer)
|
|
|
|
|
|
|
|
for h := 0; h < H; h++ {
|
|
|
|
tu.submitSourceBlock(producer, h + 1)
|
|
|
|
|
|
|
|
time.Sleep(time.Millisecond * 200)
|
|
|
|
|
|
|
|
}
|
|
|
|
tu.checkHeight("client", client, H)
|
|
|
|
tu.checkHeight("producer", producer, H)
|
|
|
|
|
|
|
|
tu.compareSourceState(client)
|
|
|
|
}
|
2019-07-31 07:13:49 +00:00
|
|
|
*/
|