github.com/aidoskuneen/adk-node@v0.0.0-20220315131952-2e32567cb7f4/les/sync_test.go (about)

     1  // Copyright 2021 The adkgo Authors
     2  // This file is part of the adkgo library (adapted for adkgo from go--ethereum v1.10.8).
     3  //
     4  // the adkgo library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // the adkgo library is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the adkgo library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package les
    18  
    19  import (
    20  	"fmt"
    21  	"math/big"
    22  	"testing"
    23  	"time"
    24  
    25  	"github.com/aidoskuneen/adk-node/accounts/abi/bind"
    26  	"github.com/aidoskuneen/adk-node/core"
    27  	"github.com/aidoskuneen/adk-node/core/types"
    28  	"github.com/aidoskuneen/adk-node/crypto"
    29  	"github.com/aidoskuneen/adk-node/light"
    30  	"github.com/aidoskuneen/adk-node/params"
    31  )
    32  
    33  // Test light syncing which will download all headers from genesis.
    34  func TestLightSyncingLes3(t *testing.T) { testCheckpointSyncing(t, lpv3, 0) }
    35  
    36  // Test legacy checkpoint syncing which will download tail headers
    37  // based on a hardcoded checkpoint.
    38  func TestLegacyCheckpointSyncingLes3(t *testing.T) { testCheckpointSyncing(t, lpv3, 1) }
    39  
    40  // Test checkpoint syncing which will download tail headers based
    41  // on a verified checkpoint.
    42  func TestCheckpointSyncingLes3(t *testing.T) { testCheckpointSyncing(t, lpv3, 2) }
    43  
    44  func testCheckpointSyncing(t *testing.T, protocol int, syncMode int) {
    45  	config := light.TestServerIndexerConfig
    46  
    47  	waitIndexers := func(cIndexer, bIndexer, btIndexer *core.ChainIndexer) {
    48  		for {
    49  			cs, _, _ := cIndexer.Sections()
    50  			bts, _, _ := btIndexer.Sections()
    51  			if cs >= 1 && bts >= 1 {
    52  				break
    53  			}
    54  			time.Sleep(10 * time.Millisecond)
    55  		}
    56  	}
    57  	// Generate 128+1 blocks (totally 1 CHT section)
    58  	netconfig := testnetConfig{
    59  		blocks:    int(config.ChtSize + config.ChtConfirms),
    60  		protocol:  protocol,
    61  		indexFn:   waitIndexers,
    62  		nopruning: true,
    63  	}
    64  	server, client, tearDown := newClientServerEnv(t, netconfig)
    65  	defer tearDown()
    66  
    67  	expected := config.ChtSize + config.ChtConfirms
    68  
    69  	// Checkpoint syncing or legacy checkpoint syncing.
    70  	if syncMode == 1 || syncMode == 2 {
    71  		// Assemble checkpoint 0
    72  		s, _, head := server.chtIndexer.Sections()
    73  		cp := &params.TrustedCheckpoint{
    74  			SectionIndex: 0,
    75  			SectionHead:  head,
    76  			CHTRoot:      light.GetChtRoot(server.db, s-1, head),
    77  			BloomRoot:    light.GetBloomTrieRoot(server.db, s-1, head),
    78  		}
    79  		if syncMode == 1 {
    80  			// Register the assembled checkpoint as hardcoded one.
    81  			client.handler.checkpoint = cp
    82  			client.handler.backend.blockchain.AddTrustedCheckpoint(cp)
    83  		} else {
    84  			// Register the assembled checkpoint into oracle.
    85  			header := server.backend.Blockchain().CurrentHeader()
    86  
    87  			data := append([]byte{0x19, 0x00}, append(oracleAddr.Bytes(), append([]byte{0, 0, 0, 0, 0, 0, 0, 0}, cp.Hash().Bytes()...)...)...)
    88  			sig, _ := crypto.Sign(crypto.Keccak256(data), signerKey)
    89  			sig[64] += 27 // Transform V from 0/1 to 27/28 according to the yellow paper
    90  			auth, _ := bind.NewKeyedTransactorWithChainID(signerKey, big.NewInt(1337))
    91  			if _, err := server.handler.server.oracle.Contract().RegisterCheckpoint(auth, cp.SectionIndex, cp.Hash().Bytes(), new(big.Int).Sub(header.Number, big.NewInt(1)), header.ParentHash, [][]byte{sig}); err != nil {
    92  				t.Error("register checkpoint failed", err)
    93  			}
    94  			server.backend.Commit()
    95  
    96  			// Wait for the checkpoint registration
    97  			for {
    98  				_, hash, _, err := server.handler.server.oracle.Contract().Contract().GetLatestCheckpoint(nil)
    99  				if err != nil || hash == [32]byte{} {
   100  					time.Sleep(10 * time.Millisecond)
   101  					continue
   102  				}
   103  				break
   104  			}
   105  			expected += 1
   106  		}
   107  	}
   108  
   109  	done := make(chan error)
   110  	client.handler.syncEnd = func(header *types.Header) {
   111  		if header.Number.Uint64() == expected {
   112  			done <- nil
   113  		} else {
   114  			done <- fmt.Errorf("blockchain length mismatch, want %d, got %d", expected, header.Number)
   115  		}
   116  	}
   117  
   118  	// Create connected peer pair.
   119  	peer1, peer2, err := newTestPeerPair("peer", protocol, server.handler, client.handler)
   120  	if err != nil {
   121  		t.Fatalf("Failed to connect testing peers %v", err)
   122  	}
   123  	defer peer1.close()
   124  	defer peer2.close()
   125  
   126  	select {
   127  	case err := <-done:
   128  		if err != nil {
   129  			t.Error("sync failed", err)
   130  		}
   131  		return
   132  	case <-time.NewTimer(10 * time.Second).C:
   133  		t.Error("checkpoint syncing timeout")
   134  	}
   135  }
   136  
   137  func TestMissOracleBackendLES3(t *testing.T)             { testMissOracleBackend(t, true, lpv3) }
   138  func TestMissOracleBackendNoCheckpointLES3(t *testing.T) { testMissOracleBackend(t, false, lpv3) }
   139  
   140  func testMissOracleBackend(t *testing.T, hasCheckpoint bool, protocol int) {
   141  	config := light.TestServerIndexerConfig
   142  
   143  	waitIndexers := func(cIndexer, bIndexer, btIndexer *core.ChainIndexer) {
   144  		for {
   145  			cs, _, _ := cIndexer.Sections()
   146  			bts, _, _ := btIndexer.Sections()
   147  			if cs >= 1 && bts >= 1 {
   148  				break
   149  			}
   150  			time.Sleep(10 * time.Millisecond)
   151  		}
   152  	}
   153  	// Generate 128+1 blocks (totally 1 CHT section)
   154  	netconfig := testnetConfig{
   155  		blocks:    int(config.ChtSize + config.ChtConfirms),
   156  		protocol:  protocol,
   157  		indexFn:   waitIndexers,
   158  		nopruning: true,
   159  	}
   160  	server, client, tearDown := newClientServerEnv(t, netconfig)
   161  	defer tearDown()
   162  
   163  	expected := config.ChtSize + config.ChtConfirms
   164  
   165  	s, _, head := server.chtIndexer.Sections()
   166  	cp := &params.TrustedCheckpoint{
   167  		SectionIndex: 0,
   168  		SectionHead:  head,
   169  		CHTRoot:      light.GetChtRoot(server.db, s-1, head),
   170  		BloomRoot:    light.GetBloomTrieRoot(server.db, s-1, head),
   171  	}
   172  	// Register the assembled checkpoint into oracle.
   173  	header := server.backend.Blockchain().CurrentHeader()
   174  
   175  	data := append([]byte{0x19, 0x00}, append(oracleAddr.Bytes(), append([]byte{0, 0, 0, 0, 0, 0, 0, 0}, cp.Hash().Bytes()...)...)...)
   176  	sig, _ := crypto.Sign(crypto.Keccak256(data), signerKey)
   177  	sig[64] += 27 // Transform V from 0/1 to 27/28 according to the yellow paper
   178  	auth, _ := bind.NewKeyedTransactorWithChainID(signerKey, big.NewInt(1337))
   179  	if _, err := server.handler.server.oracle.Contract().RegisterCheckpoint(auth, cp.SectionIndex, cp.Hash().Bytes(), new(big.Int).Sub(header.Number, big.NewInt(1)), header.ParentHash, [][]byte{sig}); err != nil {
   180  		t.Error("register checkpoint failed", err)
   181  	}
   182  	server.backend.Commit()
   183  
   184  	// Wait for the checkpoint registration
   185  	for {
   186  		_, hash, _, err := server.handler.server.oracle.Contract().Contract().GetLatestCheckpoint(nil)
   187  		if err != nil || hash == [32]byte{} {
   188  			time.Sleep(100 * time.Millisecond)
   189  			continue
   190  		}
   191  		break
   192  	}
   193  	expected += 1
   194  
   195  	// Explicitly set the oracle as nil. In normal use case it can happen
   196  	// that user wants to unlock something which blocks the oracle backend
   197  	// initialisation. But at the same time syncing starts.
   198  	//
   199  	// See https://github.com/aidoskuneen/adk-node/issues/20097 for more detail.
   200  	//
   201  	// In this case, client should run light sync or legacy checkpoint sync
   202  	// if hardcoded checkpoint is configured.
   203  	client.handler.backend.oracle = nil
   204  
   205  	// For some private networks it can happen checkpoint syncing is enabled
   206  	// but there is no hardcoded checkpoint configured.
   207  	if hasCheckpoint {
   208  		client.handler.checkpoint = cp
   209  		client.handler.backend.blockchain.AddTrustedCheckpoint(cp)
   210  	}
   211  
   212  	done := make(chan error)
   213  	client.handler.syncEnd = func(header *types.Header) {
   214  		if header.Number.Uint64() == expected {
   215  			done <- nil
   216  		} else {
   217  			done <- fmt.Errorf("blockchain length mismatch, want %d, got %d", expected, header.Number)
   218  		}
   219  	}
   220  	// Create connected peer pair.
   221  	if _, _, err := newTestPeerPair("peer", 2, server.handler, client.handler); err != nil {
   222  		t.Fatalf("Failed to connect testing peers %v", err)
   223  	}
   224  	select {
   225  	case err := <-done:
   226  		if err != nil {
   227  			t.Error("sync failed", err)
   228  		}
   229  		return
   230  	case <-time.NewTimer(10 * time.Second).C:
   231  		t.Error("checkpoint syncing timeout")
   232  	}
   233  }
   234  
   235  func TestSyncFromConfiguredCheckpointLES3(t *testing.T) { testSyncFromConfiguredCheckpoint(t, lpv3) }
   236  
   237  func testSyncFromConfiguredCheckpoint(t *testing.T, protocol int) {
   238  	config := light.TestServerIndexerConfig
   239  
   240  	waitIndexers := func(cIndexer, bIndexer, btIndexer *core.ChainIndexer) {
   241  		for {
   242  			cs, _, _ := cIndexer.Sections()
   243  			bts, _, _ := btIndexer.Sections()
   244  			if cs >= 2 && bts >= 2 {
   245  				break
   246  			}
   247  			time.Sleep(10 * time.Millisecond)
   248  		}
   249  	}
   250  	// Generate 256+1 blocks (totally 2 CHT sections)
   251  	netconfig := testnetConfig{
   252  		blocks:    int(2*config.ChtSize + config.ChtConfirms),
   253  		protocol:  protocol,
   254  		indexFn:   waitIndexers,
   255  		nopruning: true,
   256  	}
   257  	server, client, tearDown := newClientServerEnv(t, netconfig)
   258  	defer tearDown()
   259  
   260  	// Configure the local checkpoint(the first section)
   261  	head := server.handler.blockchain.GetHeaderByNumber(config.ChtSize - 1).Hash()
   262  	cp := &params.TrustedCheckpoint{
   263  		SectionIndex: 0,
   264  		SectionHead:  head,
   265  		CHTRoot:      light.GetChtRoot(server.db, 0, head),
   266  		BloomRoot:    light.GetBloomTrieRoot(server.db, 0, head),
   267  	}
   268  	client.handler.backend.config.SyncFromCheckpoint = true
   269  	client.handler.backend.config.Checkpoint = cp
   270  	client.handler.checkpoint = cp
   271  	client.handler.backend.blockchain.AddTrustedCheckpoint(cp)
   272  
   273  	var (
   274  		start       = make(chan error, 1)
   275  		end         = make(chan error, 1)
   276  		expectStart = config.ChtSize - 1
   277  		expectEnd   = 2*config.ChtSize + config.ChtConfirms
   278  	)
   279  	client.handler.syncStart = func(header *types.Header) {
   280  		if header.Number.Uint64() == expectStart {
   281  			start <- nil
   282  		} else {
   283  			start <- fmt.Errorf("blockchain length mismatch, want %d, got %d", expectStart, header.Number)
   284  		}
   285  	}
   286  	client.handler.syncEnd = func(header *types.Header) {
   287  		if header.Number.Uint64() == expectEnd {
   288  			end <- nil
   289  		} else {
   290  			end <- fmt.Errorf("blockchain length mismatch, want %d, got %d", expectEnd, header.Number)
   291  		}
   292  	}
   293  	// Create connected peer pair.
   294  	if _, _, err := newTestPeerPair("peer", 2, server.handler, client.handler); err != nil {
   295  		t.Fatalf("Failed to connect testing peers %v", err)
   296  	}
   297  
   298  	select {
   299  	case err := <-start:
   300  		if err != nil {
   301  			t.Error("sync failed", err)
   302  		}
   303  		return
   304  	case <-time.NewTimer(10 * time.Second).C:
   305  		t.Error("checkpoint syncing timeout")
   306  	}
   307  
   308  	select {
   309  	case err := <-end:
   310  		if err != nil {
   311  			t.Error("sync failed", err)
   312  		}
   313  		return
   314  	case <-time.NewTimer(10 * time.Second).C:
   315  		t.Error("checkpoint syncing timeout")
   316  	}
   317  }
   318  
   319  func TestSyncAll(t *testing.T) { testSyncAll(t, lpv3) }
   320  
   321  func testSyncAll(t *testing.T, protocol int) {
   322  	config := light.TestServerIndexerConfig
   323  
   324  	waitIndexers := func(cIndexer, bIndexer, btIndexer *core.ChainIndexer) {
   325  		for {
   326  			cs, _, _ := cIndexer.Sections()
   327  			bts, _, _ := btIndexer.Sections()
   328  			if cs >= 2 && bts >= 2 {
   329  				break
   330  			}
   331  			time.Sleep(10 * time.Millisecond)
   332  		}
   333  	}
   334  	// Generate 256+1 blocks (totally 2 CHT sections)
   335  	netconfig := testnetConfig{
   336  		blocks:    int(2*config.ChtSize + config.ChtConfirms),
   337  		protocol:  protocol,
   338  		indexFn:   waitIndexers,
   339  		nopruning: true,
   340  	}
   341  	server, client, tearDown := newClientServerEnv(t, netconfig)
   342  	defer tearDown()
   343  
   344  	client.handler.backend.config.SyncFromCheckpoint = true
   345  
   346  	var (
   347  		start       = make(chan error, 1)
   348  		end         = make(chan error, 1)
   349  		expectStart = uint64(0)
   350  		expectEnd   = 2*config.ChtSize + config.ChtConfirms
   351  	)
   352  	client.handler.syncStart = func(header *types.Header) {
   353  		if header.Number.Uint64() == expectStart {
   354  			start <- nil
   355  		} else {
   356  			start <- fmt.Errorf("blockchain length mismatch, want %d, got %d", expectStart, header.Number)
   357  		}
   358  	}
   359  	client.handler.syncEnd = func(header *types.Header) {
   360  		if header.Number.Uint64() == expectEnd {
   361  			end <- nil
   362  		} else {
   363  			end <- fmt.Errorf("blockchain length mismatch, want %d, got %d", expectEnd, header.Number)
   364  		}
   365  	}
   366  	// Create connected peer pair.
   367  	if _, _, err := newTestPeerPair("peer", 2, server.handler, client.handler); err != nil {
   368  		t.Fatalf("Failed to connect testing peers %v", err)
   369  	}
   370  
   371  	select {
   372  	case err := <-start:
   373  		if err != nil {
   374  			t.Error("sync failed", err)
   375  		}
   376  		return
   377  	case <-time.NewTimer(10 * time.Second).C:
   378  		t.Error("checkpoint syncing timeout")
   379  	}
   380  
   381  	select {
   382  	case err := <-end:
   383  		if err != nil {
   384  			t.Error("sync failed", err)
   385  		}
   386  		return
   387  	case <-time.NewTimer(10 * time.Second).C:
   388  		t.Error("checkpoint syncing timeout")
   389  	}
   390  }