github.com/klaytn/klaytn@v1.12.1/node/sc/vt_recovery_test.go (about)

     1  // Copyright 2019 The klaytn Authors
     2  // This file is part of the klaytn library.
     3  //
     4  // The klaytn 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 klaytn 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 klaytn library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package sc
    18  
    19  import (
    20  	"log"
    21  	"math/big"
    22  	"os"
    23  	"sync"
    24  	"testing"
    25  	"time"
    26  
    27  	"github.com/klaytn/klaytn/accounts/abi/bind"
    28  	"github.com/klaytn/klaytn/accounts/abi/bind/backends"
    29  	"github.com/klaytn/klaytn/blockchain"
    30  	"github.com/klaytn/klaytn/blockchain/types"
    31  	"github.com/klaytn/klaytn/common"
    32  	sctoken "github.com/klaytn/klaytn/contracts/sc_erc20"
    33  	scnft "github.com/klaytn/klaytn/contracts/sc_erc721"
    34  	"github.com/klaytn/klaytn/crypto"
    35  	"github.com/klaytn/klaytn/params"
    36  	"github.com/klaytn/klaytn/storage/database"
    37  	"github.com/stretchr/testify/assert"
    38  )
    39  
    40  type testInfo struct {
    41  	t                 *testing.T
    42  	sim               *backends.SimulatedBackend
    43  	sc                *SubBridge
    44  	bm                *BridgeManager
    45  	localInfo         *BridgeInfo
    46  	remoteInfo        *BridgeInfo
    47  	tokenLocalAddr    common.Address
    48  	tokenRemoteAddr   common.Address
    49  	tokenLocalBridge  *sctoken.ServiceChainToken
    50  	tokenRemoteBridge *sctoken.ServiceChainToken
    51  	nftLocalAddr      common.Address
    52  	nftRemoteAddr     common.Address
    53  	nftLocalBridge    *scnft.ServiceChainNFT
    54  	nftRemoteBridge   *scnft.ServiceChainNFT
    55  	nodeAuth          *bind.TransactOpts
    56  	chainAuth         *bind.TransactOpts
    57  	aliceAuth         *bind.TransactOpts
    58  	recoveryCh        chan bool
    59  	mu                sync.Mutex
    60  	nftIndex          int64
    61  }
    62  
    63  const (
    64  	testGasLimit     = 1000000
    65  	testAmount       = 321
    66  	testToken        = 123
    67  	testNFT          = int64(7321)
    68  	testChargeToken  = 100000
    69  	testTimeout      = 10 * time.Second
    70  	testTxCount      = 7
    71  	testBlockOffset  = 3 // +2 for genesis and bridge contract, +1 by a hardcoded hint
    72  	testPendingCount = 3
    73  )
    74  
    75  type operations struct {
    76  	request     func(*testInfo, *BridgeInfo)
    77  	handle      func(*testInfo, *BridgeInfo, IRequestValueTransferEvent)
    78  	dummyHandle func(*testInfo, *BridgeInfo)
    79  }
    80  
    81  var ops = map[uint8]*operations{
    82  	KLAY: {
    83  		request:     requestKLAYTransfer,
    84  		handle:      handleKLAYTransfer,
    85  		dummyHandle: dummyHandleRequestKLAYTransfer,
    86  	},
    87  	ERC20: {
    88  		request:     requestTokenTransfer,
    89  		handle:      handleTokenTransfer,
    90  		dummyHandle: dummyHandleRequestTokenTransfer,
    91  	},
    92  	ERC721: {
    93  		request:     requestNFTTransfer,
    94  		handle:      handleNFTTransfer,
    95  		dummyHandle: dummyHandleRequestNFTTransfer,
    96  	},
    97  }
    98  
    99  // TestBasicKLAYTransferRecovery tests each methods of the value transfer recovery.
   100  func TestBasicKLAYTransferRecovery(t *testing.T) {
   101  	tempDir, err := os.MkdirTemp(os.TempDir(), "sc")
   102  	assert.NoError(t, err)
   103  	defer func() {
   104  		if err := os.RemoveAll(tempDir); err != nil {
   105  			t.Fatalf("fail to delete file %v", err)
   106  		}
   107  	}()
   108  
   109  	// 1. Init dummy chain and do some value transfers.
   110  	info := prepare(t, func(info *testInfo) {
   111  		for i := 0; i < testTxCount; i++ {
   112  			ops[KLAY].request(info, info.localInfo)
   113  		}
   114  	})
   115  	defer info.sim.Close()
   116  	vtr := NewValueTransferRecovery(&SCConfig{VTRecovery: true}, info.localInfo, info.remoteInfo)
   117  
   118  	// 2. Update recovery hint.
   119  	err = vtr.updateRecoveryHint()
   120  	if err != nil {
   121  		t.Fatal("fail to update value transfer hint")
   122  	}
   123  	t.Log("value transfer hint", vtr.child2parentHint)
   124  	assert.Equal(t, uint64(testTxCount), vtr.child2parentHint.requestNonce)
   125  	assert.Equal(t, uint64(testTxCount-testPendingCount), vtr.child2parentHint.handleNonce)
   126  
   127  	// 3. Request events by using the hint.
   128  	err = vtr.retrievePendingEvents()
   129  	if err != nil {
   130  		t.Fatal("fail to retrieve pending events from the bridge contract")
   131  	}
   132  
   133  	// 4. Check pending events.
   134  	t.Log("check pending tx", "len", len(vtr.childEvents))
   135  	count := 0
   136  	for _, ev := range vtr.childEvents {
   137  		assert.Equal(t, info.nodeAuth.From, ev.GetFrom())
   138  		assert.Equal(t, info.aliceAuth.From, ev.GetTo())
   139  		assert.Equal(t, big.NewInt(testAmount), ev.GetValueOrTokenId())
   140  		assert.Condition(t, func() bool {
   141  			return uint64(testBlockOffset) <= ev.GetRaw().BlockNumber
   142  		})
   143  		count++
   144  	}
   145  	assert.Equal(t, testPendingCount, count)
   146  
   147  	// 5. Recover pending events
   148  	info.recoveryCh <- true
   149  	assert.Equal(t, nil, vtr.recoverPendingEvents())
   150  	ops[KLAY].dummyHandle(info, info.remoteInfo)
   151  
   152  	// 6. Check empty pending events.
   153  	err = vtr.updateRecoveryHint()
   154  	if err != nil {
   155  		t.Fatal("fail to update value transfer hint")
   156  	}
   157  	err = vtr.retrievePendingEvents()
   158  	if err != nil {
   159  		t.Fatal("fail to retrieve pending events from the bridge contract")
   160  	}
   161  	assert.Equal(t, 0, len(vtr.childEvents))
   162  
   163  	assert.Equal(t, nil, vtr.Recover()) // nothing to recover
   164  }
   165  
   166  // TestKLAYTransferLongRangeRecovery tests a long block range recovery.
   167  func TestKLAYTransferLongRangeRecovery(t *testing.T) {
   168  	tempDir := os.TempDir() + "sc"
   169  	os.MkdirAll(tempDir, os.ModePerm)
   170  	oldMaxPendingTxs := maxPendingTxs
   171  	maxPendingTxs = 2
   172  	defer func() {
   173  		maxPendingTxs = oldMaxPendingTxs
   174  		if err := os.RemoveAll(tempDir); err != nil {
   175  			t.Fatalf("fail to delete file %v", err)
   176  		}
   177  	}()
   178  
   179  	// 1. Init dummy chain and do some value transfers.
   180  	info := prepare(t, func(info *testInfo) {
   181  		for i := 0; i < testTxCount; i++ {
   182  			ops[KLAY].request(info, info.localInfo)
   183  			for i := uint64(0); i < filterLogsStride; i++ {
   184  				info.sim.Commit()
   185  			}
   186  		}
   187  	})
   188  	defer info.sim.Close()
   189  	// TODO-Klaytn need to remove sleep
   190  	time.Sleep(1 * time.Second)
   191  	info.sim.Commit()
   192  
   193  	vtr := NewValueTransferRecovery(&SCConfig{VTRecovery: true}, info.localInfo, info.remoteInfo)
   194  
   195  	err := vtr.updateRecoveryHint()
   196  	if err != nil {
   197  		t.Fatal("fail to update a value transfer hint")
   198  	}
   199  	assert.Equal(t, uint64(testTxCount), vtr.child2parentHint.requestNonce)
   200  	assert.Equal(t, uint64(testTxCount-testPendingCount), vtr.child2parentHint.handleNonce)
   201  
   202  	// 2. first recovery.
   203  	info.recoveryCh <- true
   204  	err = vtr.Recover()
   205  	if err != nil {
   206  		t.Fatal("fail to recover the value transfer")
   207  	}
   208  	// TODO-Klaytn need to remove sleep
   209  	time.Sleep(1 * time.Second)
   210  	info.sim.Commit()
   211  
   212  	err = vtr.updateRecoveryHint()
   213  	if err != nil {
   214  		t.Fatal("fail to update value transfer hint")
   215  	}
   216  	assert.Equal(t, uint64(testTxCount), vtr.child2parentHint.requestNonce)
   217  	assert.Equal(t, uint64(testTxCount-testPendingCount+maxPendingTxs), vtr.child2parentHint.handleNonce)
   218  
   219  	// 3. second recovery.
   220  	err = vtr.Recover()
   221  	if err != nil {
   222  		t.Fatal("fail to recover the value transfer")
   223  	}
   224  	// TODO-Klaytn need to remove sleep
   225  	time.Sleep(1 * time.Second)
   226  	info.sim.Commit()
   227  
   228  	// 4. Check if recovery is done.
   229  	err = vtr.updateRecoveryHint()
   230  	if err != nil {
   231  		t.Fatal("fail to update value transfer hint")
   232  	}
   233  	assert.Equal(t, uint64(testTxCount), vtr.child2parentHint.requestNonce)
   234  	assert.Equal(t, uint64(testTxCount), vtr.child2parentHint.handleNonce)
   235  }
   236  
   237  // TestBasicTokenTransferRecovery tests the token transfer recovery.
   238  func TestBasicTokenTransferRecovery(t *testing.T) {
   239  	tempDir, err := os.MkdirTemp(os.TempDir(), "sc")
   240  	assert.NoError(t, err)
   241  	defer func() {
   242  		if err := os.RemoveAll(tempDir); err != nil {
   243  			t.Fatalf("fail to delete file %v", err)
   244  		}
   245  	}()
   246  
   247  	info := prepare(t, func(info *testInfo) {
   248  		for i := 0; i < testTxCount; i++ {
   249  			ops[ERC20].request(info, info.localInfo)
   250  		}
   251  	})
   252  	defer info.sim.Close()
   253  
   254  	vtr := NewValueTransferRecovery(&SCConfig{VTRecovery: true}, info.localInfo, info.remoteInfo)
   255  	err = vtr.updateRecoveryHint()
   256  	if err != nil {
   257  		t.Fatal("fail to update a value transfer hint")
   258  	}
   259  	assert.NotEqual(t, vtr.child2parentHint.requestNonce, vtr.child2parentHint.handleNonce)
   260  	t.Log("token transfer hint", vtr.child2parentHint)
   261  
   262  	info.recoveryCh <- true
   263  	err = vtr.Recover()
   264  	if err != nil {
   265  		t.Fatal("fail to recover the value transfer")
   266  	}
   267  	ops[ERC20].dummyHandle(info, info.remoteInfo)
   268  
   269  	err = vtr.updateRecoveryHint()
   270  	if err != nil {
   271  		t.Fatal("fail to update a value transfer hint")
   272  	}
   273  	assert.Equal(t, vtr.child2parentHint.requestNonce, vtr.child2parentHint.handleNonce)
   274  }
   275  
   276  // TestBasicNFTTransferRecovery tests the NFT transfer recovery.
   277  // TODO-Klaytn-ServiceChain: implement NFT transfer.
   278  func TestBasicNFTTransferRecovery(t *testing.T) {
   279  	tempDir, err := os.MkdirTemp(os.TempDir(), "sc")
   280  	assert.NoError(t, err)
   281  	defer func() {
   282  		if err := os.RemoveAll(tempDir); err != nil {
   283  			t.Fatalf("fail to delete file %v", err)
   284  		}
   285  	}()
   286  
   287  	info := prepare(t, func(info *testInfo) {
   288  		for i := 0; i < testTxCount; i++ {
   289  			ops[ERC721].request(info, info.localInfo)
   290  		}
   291  	})
   292  	defer info.sim.Close()
   293  
   294  	vtr := NewValueTransferRecovery(&SCConfig{VTRecovery: true}, info.localInfo, info.remoteInfo)
   295  	err = vtr.updateRecoveryHint()
   296  	if err != nil {
   297  		t.Fatal("fail to update a value transfer hint")
   298  	}
   299  	assert.NotEqual(t, vtr.child2parentHint.requestNonce, vtr.child2parentHint.handleNonce)
   300  	t.Log("token transfer hint", vtr.child2parentHint)
   301  
   302  	info.recoveryCh <- true
   303  	err = vtr.Recover()
   304  	if err != nil {
   305  		t.Fatal("fail to recover the value transfer")
   306  	}
   307  	ops[ERC721].dummyHandle(info, info.remoteInfo)
   308  
   309  	err = vtr.updateRecoveryHint()
   310  	if err != nil {
   311  		t.Fatal("fail to update a value transfer hint")
   312  	}
   313  	assert.Equal(t, vtr.child2parentHint.requestNonce, vtr.child2parentHint.handleNonce)
   314  }
   315  
   316  // TestMethodRecover tests the valueTransferRecovery.Recover() method.
   317  func TestMethodRecover(t *testing.T) {
   318  	tempDir, err := os.MkdirTemp(os.TempDir(), "sc")
   319  	assert.NoError(t, err)
   320  	defer func() {
   321  		if err := os.RemoveAll(tempDir); err != nil {
   322  			t.Fatalf("fail to delete file %v", err)
   323  		}
   324  	}()
   325  
   326  	info := prepare(t, func(info *testInfo) {
   327  		for i := 0; i < testTxCount; i++ {
   328  			ops[KLAY].request(info, info.localInfo)
   329  		}
   330  	})
   331  	defer info.sim.Close()
   332  
   333  	vtr := NewValueTransferRecovery(&SCConfig{VTRecovery: true}, info.localInfo, info.remoteInfo)
   334  	err = vtr.updateRecoveryHint()
   335  	if err != nil {
   336  		t.Fatal("fail to update a value transfer hint")
   337  	}
   338  	assert.NotEqual(t, vtr.child2parentHint.requestNonce, vtr.child2parentHint.handleNonce)
   339  
   340  	info.recoveryCh <- true
   341  	err = vtr.Recover()
   342  	if err != nil {
   343  		t.Fatal("fail to recover the value transfer")
   344  	}
   345  	ops[KLAY].dummyHandle(info, info.remoteInfo)
   346  
   347  	err = vtr.updateRecoveryHint()
   348  	if err != nil {
   349  		t.Fatal("fail to update a value transfer hint")
   350  	}
   351  	assert.Equal(t, vtr.child2parentHint.requestNonce, vtr.child2parentHint.handleNonce)
   352  }
   353  
   354  // TestMethodStop tests the Stop method for stop the internal goroutine.
   355  func TestMethodStop(t *testing.T) {
   356  	tempDir, err := os.MkdirTemp(os.TempDir(), "sc")
   357  	assert.NoError(t, err)
   358  	defer func() {
   359  		if err := os.RemoveAll(tempDir); err != nil {
   360  			t.Fatalf("fail to delete file %v", err)
   361  		}
   362  	}()
   363  
   364  	info := prepare(t, func(info *testInfo) {
   365  		for i := 0; i < testTxCount; i++ {
   366  			ops[KLAY].request(info, info.localInfo)
   367  		}
   368  	})
   369  	defer info.sim.Close()
   370  
   371  	vtr := NewValueTransferRecovery(&SCConfig{VTRecovery: true, VTRecoveryInterval: 1}, info.localInfo, info.remoteInfo)
   372  	err = vtr.updateRecoveryHint()
   373  	if err != nil {
   374  		t.Fatal("fail to update a value transfer hint")
   375  	}
   376  	assert.NotEqual(t, vtr.child2parentHint.requestNonce, vtr.child2parentHint.handleNonce)
   377  
   378  	info.recoveryCh <- true
   379  	err = vtr.Start()
   380  	if err != nil {
   381  		t.Fatal("fail to start the value transfer")
   382  	}
   383  	assert.Equal(t, nil, vtr.WaitRunningStatus(true, 5*time.Second))
   384  	err = vtr.Stop()
   385  	if err != nil {
   386  		t.Fatal("fail to stop the value transfer")
   387  	}
   388  	assert.Equal(t, false, vtr.isRunning)
   389  }
   390  
   391  // TestFlagVTRecovery tests the disabled vtrecovery option.
   392  func TestFlagVTRecovery(t *testing.T) {
   393  	tempDir, err := os.MkdirTemp(os.TempDir(), "sc")
   394  	assert.NoError(t, err)
   395  	defer func() {
   396  		if err := os.RemoveAll(tempDir); err != nil {
   397  			t.Fatalf("fail to delete file %v", err)
   398  		}
   399  	}()
   400  
   401  	info := prepare(t, func(info *testInfo) {
   402  		for i := 0; i < testTxCount; i++ {
   403  			ops[KLAY].request(info, info.localInfo)
   404  		}
   405  	})
   406  	defer info.sim.Close()
   407  
   408  	vtr := NewValueTransferRecovery(&SCConfig{VTRecovery: true, VTRecoveryInterval: 60}, info.localInfo, info.remoteInfo)
   409  	vtr.Start()
   410  	assert.Equal(t, nil, vtr.WaitRunningStatus(true, 5*time.Second))
   411  	vtr.Stop()
   412  
   413  	vtr = NewValueTransferRecovery(&SCConfig{VTRecovery: false}, info.localInfo, info.remoteInfo)
   414  	err = vtr.Start()
   415  	assert.Equal(t, ErrVtrDisabled, err)
   416  	vtr.Stop()
   417  }
   418  
   419  // TestAlreadyStartedVTRecovery tests the already started VTR error cases.
   420  func TestAlreadyStartedVTRecovery(t *testing.T) {
   421  	tempDir, err := os.MkdirTemp(os.TempDir(), "sc")
   422  	assert.NoError(t, err)
   423  	defer func() {
   424  		if err := os.RemoveAll(tempDir); err != nil {
   425  			t.Fatalf("fail to delete file %v", err)
   426  		}
   427  	}()
   428  	info := prepare(t, func(info *testInfo) {
   429  		for i := 0; i < testTxCount; i++ {
   430  			ops[KLAY].request(info, info.localInfo)
   431  		}
   432  	})
   433  	defer info.sim.Close()
   434  
   435  	vtr := NewValueTransferRecovery(&SCConfig{VTRecovery: true, VTRecoveryInterval: 60}, info.localInfo, info.remoteInfo)
   436  	err = vtr.Start()
   437  	assert.Equal(t, nil, err)
   438  	assert.Equal(t, nil, vtr.WaitRunningStatus(true, 5*time.Second))
   439  
   440  	err = vtr.Start()
   441  	assert.Equal(t, ErrVtrAlreadyStarted, err)
   442  
   443  	vtr.Stop()
   444  }
   445  
   446  // TestScenarioMainChainRecovery tests the value transfer recovery of the parent chain to child chain value transfers.
   447  func TestScenarioMainChainRecovery(t *testing.T) {
   448  	tempDir, err := os.MkdirTemp(os.TempDir(), "sc")
   449  	assert.NoError(t, err)
   450  	defer func() {
   451  		if err := os.RemoveAll(tempDir); err != nil {
   452  			t.Fatalf("fail to delete file %v", err)
   453  		}
   454  	}()
   455  
   456  	info := prepare(t, func(info *testInfo) {
   457  		for i := 0; i < testTxCount; i++ {
   458  			ops[KLAY].request(info, info.remoteInfo)
   459  		}
   460  	})
   461  	defer info.sim.Close()
   462  
   463  	vtr := NewValueTransferRecovery(&SCConfig{VTRecovery: true}, info.localInfo, info.remoteInfo)
   464  	err = vtr.updateRecoveryHint()
   465  	if err != nil {
   466  		t.Fatal("fail to update a value transfer hint")
   467  	}
   468  	assert.NotEqual(t, vtr.parent2childHint.requestNonce, vtr.parent2childHint.handleNonce)
   469  
   470  	info.recoveryCh <- true
   471  	err = vtr.Recover()
   472  	if err != nil {
   473  		t.Fatal("fail to recover the value transfer")
   474  	}
   475  	ops[KLAY].dummyHandle(info, info.localInfo)
   476  
   477  	err = vtr.updateRecoveryHint()
   478  	if err != nil {
   479  		t.Fatal("fail to update a value transfer hint")
   480  	}
   481  	assert.Equal(t, vtr.parent2childHint.requestNonce, vtr.parent2childHint.handleNonce)
   482  }
   483  
   484  // TestScenarioAutomaticRecovery tests the recovery of the internal goroutine.
   485  func TestScenarioAutomaticRecovery(t *testing.T) {
   486  	tempDir, err := os.MkdirTemp(os.TempDir(), "sc")
   487  	assert.NoError(t, err)
   488  	defer func() {
   489  		if err := os.RemoveAll(tempDir); err != nil {
   490  			t.Fatalf("fail to delete file %v", err)
   491  		}
   492  	}()
   493  
   494  	info := prepare(t, func(info *testInfo) {
   495  		for i := 0; i < testTxCount; i++ {
   496  			ops[KLAY].request(info, info.localInfo)
   497  		}
   498  	})
   499  	defer info.sim.Close()
   500  
   501  	vtr := NewValueTransferRecovery(&SCConfig{VTRecovery: true, VTRecoveryInterval: 1}, info.localInfo, info.remoteInfo)
   502  	err = vtr.updateRecoveryHint()
   503  	if err != nil {
   504  		t.Fatal("fail to update a value transfer hint")
   505  	}
   506  	assert.NotEqual(t, vtr.child2parentHint.requestNonce, vtr.child2parentHint.handleNonce)
   507  
   508  	info.recoveryCh <- true
   509  	err = vtr.Start()
   510  	if err != nil {
   511  		t.Fatal("fail to start the value transfer")
   512  	}
   513  	assert.Equal(t, nil, vtr.WaitRunningStatus(true, 5*time.Second))
   514  	ops[KLAY].dummyHandle(info, info.remoteInfo)
   515  
   516  	err = vtr.updateRecoveryHint()
   517  	if err != nil {
   518  		t.Fatal("fail to update a value transfer hint")
   519  	}
   520  	vtr.Stop()
   521  	assert.Equal(t, vtr.child2parentHint.requestNonce, vtr.child2parentHint.handleNonce)
   522  }
   523  
   524  // TestMultiOperatorRequestRecovery tests value transfer recovery for the multi-operator.
   525  func TestMultiOperatorRequestRecovery(t *testing.T) {
   526  	tempDir, err := os.MkdirTemp(os.TempDir(), "sc")
   527  	assert.NoError(t, err)
   528  	defer func() {
   529  		if err := os.RemoveAll(tempDir); err != nil {
   530  			t.Fatalf("fail to delete file %v", err)
   531  		}
   532  	}()
   533  
   534  	// 1. Init dummy chain and do some value transfers.
   535  	info := prepare(t, func(info *testInfo) {
   536  		for i := 0; i < testTxCount; i++ {
   537  			ops[KLAY].request(info, info.localInfo)
   538  		}
   539  	})
   540  	defer info.sim.Close()
   541  
   542  	// 2. Set multi-operator.
   543  	cAcc := info.nodeAuth
   544  	pAcc := info.chainAuth
   545  	opts := &bind.TransactOpts{From: cAcc.From, Signer: cAcc.Signer, GasLimit: testGasLimit}
   546  	_, err = info.localInfo.bridge.RegisterOperator(opts, pAcc.From)
   547  	assert.NoError(t, err)
   548  	opts = &bind.TransactOpts{From: pAcc.From, Signer: pAcc.Signer, GasLimit: testGasLimit}
   549  	_, err = info.remoteInfo.bridge.RegisterOperator(opts, cAcc.From)
   550  	assert.NoError(t, err)
   551  	info.sim.Commit()
   552  
   553  	// 3. Set operator threshold.
   554  	opts = &bind.TransactOpts{From: cAcc.From, Signer: cAcc.Signer, GasLimit: testGasLimit}
   555  	_, err = info.localInfo.bridge.SetOperatorThreshold(opts, voteTypeValueTransfer, 2)
   556  	assert.NoError(t, err)
   557  	opts = &bind.TransactOpts{From: pAcc.From, Signer: pAcc.Signer, GasLimit: testGasLimit}
   558  	_, err = info.remoteInfo.bridge.SetOperatorThreshold(opts, voteTypeValueTransfer, 2)
   559  	assert.NoError(t, err)
   560  	info.sim.Commit()
   561  
   562  	vtr := NewValueTransferRecovery(&SCConfig{VTRecovery: true}, info.localInfo, info.remoteInfo)
   563  
   564  	// 4. Update recovery hint.
   565  	err = vtr.updateRecoveryHint()
   566  	if err != nil {
   567  		t.Fatal("fail to update value transfer hint")
   568  	}
   569  	t.Log("value transfer hint", vtr.child2parentHint)
   570  	assert.Equal(t, uint64(testTxCount), vtr.child2parentHint.requestNonce)
   571  	assert.Equal(t, uint64(testTxCount-testPendingCount), vtr.child2parentHint.handleNonce)
   572  
   573  	// 5. Request events by using the hint.
   574  	err = vtr.retrievePendingEvents()
   575  	if err != nil {
   576  		t.Fatal("fail to retrieve pending events from the bridge contract")
   577  	}
   578  
   579  	// 6. Check pending events.
   580  	t.Log("check pending tx", "len", len(vtr.childEvents))
   581  	count := 0
   582  	for _, ev := range vtr.childEvents {
   583  		assert.Equal(t, info.nodeAuth.From, ev.GetFrom())
   584  		assert.Equal(t, info.aliceAuth.From, ev.GetTo())
   585  		assert.Equal(t, big.NewInt(testAmount), ev.GetValueOrTokenId())
   586  		assert.Condition(t, func() bool {
   587  			return uint64(testBlockOffset) <= ev.GetRaw().BlockNumber
   588  		})
   589  		count++
   590  	}
   591  	assert.Equal(t, testPendingCount, count)
   592  
   593  	// 7. Recover pending events
   594  	info.recoveryCh <- true
   595  	assert.Equal(t, nil, vtr.recoverPendingEvents())
   596  	ops[KLAY].dummyHandle(info, info.remoteInfo)
   597  
   598  	// 8. Recover from the other operator (value transfer is not recovered yet).
   599  	err = vtr.updateRecoveryHint()
   600  	if err != nil {
   601  		t.Fatal("fail to update value transfer hint")
   602  	}
   603  	t.Log("value transfer hint", vtr.child2parentHint)
   604  	assert.Equal(t, uint64(testTxCount), vtr.child2parentHint.requestNonce)
   605  	assert.Equal(t, uint64(testTxCount-testPendingCount), vtr.child2parentHint.handleNonce)
   606  
   607  	err = vtr.retrievePendingEvents()
   608  	if err != nil {
   609  		t.Fatal("fail to retrieve pending events from the bridge contract")
   610  	}
   611  	assert.Equal(t, testPendingCount, len(vtr.childEvents))
   612  	assert.Equal(t, nil, vtr.recoverPendingEvents())
   613  	info.remoteInfo.account = info.localInfo.account // other operator
   614  	ops[KLAY].dummyHandle(info, info.remoteInfo)
   615  
   616  	// 9. Check results.
   617  	err = vtr.updateRecoveryHint()
   618  	if err != nil {
   619  		t.Fatal("fail to update value transfer hint")
   620  	}
   621  	err = vtr.retrievePendingEvents()
   622  	if err != nil {
   623  		t.Fatal("fail to retrieve pending events from the bridge contract")
   624  	}
   625  	assert.Equal(t, 0, len(vtr.childEvents))
   626  	assert.Equal(t, nil, vtr.Recover()) // nothing to recover
   627  }
   628  
   629  // prepare generates dummy blocks for testing value transfer recovery.
   630  func prepare(t *testing.T, vtcallback func(*testInfo)) *testInfo {
   631  	// Setup configuration.
   632  	config := &SCConfig{}
   633  	tempDir, err := os.MkdirTemp(os.TempDir(), "sc")
   634  	assert.NoError(t, err)
   635  	defer func() {
   636  		if err := os.RemoveAll(tempDir); err != nil {
   637  			t.Fatalf("fail to delete file %v", err)
   638  		}
   639  	}()
   640  	config.DataDir = tempDir
   641  	config.VTRecovery = true
   642  
   643  	bacc, err := NewBridgeAccounts(nil, config.DataDir, database.NewDBManager(&database.DBConfig{DBType: database.MemoryDB}), DefaultBridgeTxGasLimit, DefaultBridgeTxGasLimit)
   644  	assert.NoError(t, err)
   645  	bacc.pAccount.chainID = big.NewInt(0)
   646  	bacc.cAccount.chainID = big.NewInt(0)
   647  
   648  	cAcc := bacc.cAccount.GenerateTransactOpts()
   649  	pAcc := bacc.pAccount.GenerateTransactOpts()
   650  
   651  	// Generate a new random account and a funded simulator.
   652  	aliceKey, _ := crypto.GenerateKey()
   653  	aliceAuth := bind.NewKeyedTransactor(aliceKey)
   654  
   655  	// Alloc genesis and create a simulator.
   656  	alloc := blockchain.GenesisAlloc{
   657  		cAcc.From:      {Balance: big.NewInt(params.KLAY)},
   658  		pAcc.From:      {Balance: big.NewInt(params.KLAY)},
   659  		aliceAuth.From: {Balance: big.NewInt(params.KLAY)},
   660  	}
   661  	sim := backends.NewSimulatedBackend(alloc)
   662  
   663  	sc := &SubBridge{
   664  		chainDB:        database.NewDBManager(&database.DBConfig{DBType: database.MemoryDB}),
   665  		config:         config,
   666  		peers:          newBridgePeerSet(),
   667  		bridgeAccounts: bacc,
   668  		localBackend:   sim,
   669  		remoteBackend:  sim,
   670  	}
   671  	handler, err := NewSubBridgeHandler(sc)
   672  	if err != nil {
   673  		log.Fatalf("Failed to initialize the bridgeHandler : %v", err)
   674  		return nil
   675  	}
   676  	sc.handler = handler
   677  	sc.blockchain = sim.BlockChain()
   678  
   679  	// Prepare manager and deploy bridge contract.
   680  	bm, err := NewBridgeManager(sc)
   681  	localAddr, err := bm.DeployBridgeTest(sim, 10000, true)
   682  	assert.NoError(t, err)
   683  	remoteAddr, err := bm.DeployBridgeTest(sim, 10000, false)
   684  	assert.NoError(t, err)
   685  
   686  	localInfo, _ := bm.GetBridgeInfo(localAddr)
   687  	remoteInfo, _ := bm.GetBridgeInfo(remoteAddr)
   688  	sim.Commit()
   689  
   690  	// Prepare token contract
   691  	tokenLocalAddr, tx, tokenLocal, err := sctoken.DeployServiceChainToken(cAcc, sim, localAddr)
   692  	if err != nil {
   693  		log.Fatalf("Failed to DeployServiceChainToken: %v", err)
   694  	}
   695  	sim.Commit()
   696  	assert.Nil(t, bind.CheckWaitMined(sim, tx))
   697  
   698  	tokenRemoteAddr, tx, tokenRemote, err := sctoken.DeployServiceChainToken(pAcc, sim, remoteAddr)
   699  	if err != nil {
   700  		log.Fatalf("Failed to DeployServiceChainToken: %v", err)
   701  	}
   702  	sim.Commit()
   703  	assert.Nil(t, bind.CheckWaitMined(sim, tx))
   704  
   705  	testToken := big.NewInt(testChargeToken)
   706  	opts := &bind.TransactOpts{From: pAcc.From, Signer: pAcc.Signer, GasLimit: testGasLimit}
   707  	tx, err = tokenRemote.Transfer(opts, remoteAddr, testToken)
   708  	if err != nil {
   709  		log.Fatalf("Failed to Transfer for charging: %v", err)
   710  	}
   711  	sim.Commit()
   712  	assert.Nil(t, bind.CheckWaitMined(sim, tx))
   713  
   714  	// Prepare NFT contract
   715  	nftLocalAddr, tx, nftLocal, err := scnft.DeployServiceChainNFT(cAcc, sim, localAddr)
   716  	if err != nil {
   717  		log.Fatalf("Failed to DeployServiceChainNFT: %v", err)
   718  	}
   719  	sim.Commit()
   720  	assert.Nil(t, bind.CheckWaitMined(sim, tx))
   721  
   722  	nftRemoteAddr, tx, nftRemote, err := scnft.DeployServiceChainNFT(pAcc, sim, remoteAddr)
   723  	if err != nil {
   724  		log.Fatalf("Failed to DeployServiceChainNFT: %v", err)
   725  	}
   726  	sim.Commit()
   727  	assert.Nil(t, bind.CheckWaitMined(sim, tx))
   728  
   729  	// Register tokens on the bridge
   730  	nodeOpts := &bind.TransactOpts{From: cAcc.From, Signer: cAcc.Signer, GasLimit: testGasLimit}
   731  	chainOpts := &bind.TransactOpts{From: pAcc.From, Signer: pAcc.Signer, GasLimit: testGasLimit}
   732  	tx, err = localInfo.bridge.RegisterToken(nodeOpts, tokenLocalAddr, tokenRemoteAddr)
   733  	sim.Commit()
   734  	assert.Nil(t, bind.CheckWaitMined(sim, tx))
   735  
   736  	tx, err = localInfo.bridge.RegisterToken(nodeOpts, nftLocalAddr, nftRemoteAddr)
   737  	sim.Commit()
   738  	assert.Nil(t, bind.CheckWaitMined(sim, tx))
   739  
   740  	tx, err = remoteInfo.bridge.RegisterToken(chainOpts, tokenRemoteAddr, tokenLocalAddr)
   741  	sim.Commit()
   742  	assert.Nil(t, bind.CheckWaitMined(sim, tx))
   743  
   744  	tx, err = remoteInfo.bridge.RegisterToken(chainOpts, nftRemoteAddr, nftLocalAddr)
   745  	sim.Commit()
   746  	assert.Nil(t, bind.CheckWaitMined(sim, tx))
   747  
   748  	// Register an NFT to chain account (minting)
   749  	for i := 0; i < testTxCount; i++ {
   750  		opts := &bind.TransactOpts{From: cAcc.From, Signer: cAcc.Signer, GasLimit: testGasLimit}
   751  		tx, err = nftLocal.MintWithTokenURI(opts, cAcc.From, big.NewInt(testNFT+int64(i)), "testURI")
   752  		assert.NoError(t, err)
   753  		sim.Commit()
   754  		assert.Nil(t, bind.CheckWaitMined(sim, tx))
   755  
   756  		opts = &bind.TransactOpts{From: pAcc.From, Signer: pAcc.Signer, GasLimit: testGasLimit}
   757  		tx, err = nftRemote.MintWithTokenURI(opts, remoteAddr, big.NewInt(testNFT+int64(i)), "testURI")
   758  		assert.NoError(t, err)
   759  		sim.Commit()
   760  		assert.Nil(t, bind.CheckWaitMined(sim, tx))
   761  	}
   762  
   763  	// Register the owner as a signer
   764  	_, err = localInfo.bridge.RegisterOperator(&bind.TransactOpts{From: cAcc.From, Signer: cAcc.Signer, GasLimit: testGasLimit}, cAcc.From)
   765  	assert.NoError(t, err)
   766  	_, err = remoteInfo.bridge.RegisterOperator(&bind.TransactOpts{From: pAcc.From, Signer: pAcc.Signer, GasLimit: testGasLimit}, pAcc.From)
   767  	assert.NoError(t, err)
   768  	sim.Commit()
   769  
   770  	// Subscribe events.
   771  	err = bm.SubscribeEvent(localAddr)
   772  	if err != nil {
   773  		t.Fatalf("local bridge manager event subscription failed")
   774  	}
   775  	err = bm.SubscribeEvent(remoteAddr)
   776  	if err != nil {
   777  		t.Fatalf("remote bridge manager event subscription failed")
   778  	}
   779  
   780  	// Prepare channel for event handling.
   781  	requestVTCh := make(chan RequestValueTransferEvent)
   782  	requestVTencodedCh := make(chan RequestValueTransferEncodedEvent)
   783  	handleVTCh := make(chan *HandleValueTransferEvent)
   784  	recoveryCh := make(chan bool)
   785  	bm.SubscribeReqVTev(requestVTCh)
   786  	bm.SubscribeReqVTencodedEv(requestVTencodedCh)
   787  	bm.SubscribeHandleVTev(handleVTCh)
   788  
   789  	info := testInfo{
   790  		t, sim, sc, bm, localInfo, remoteInfo,
   791  		tokenLocalAddr, tokenRemoteAddr, tokenLocal, tokenRemote,
   792  		nftLocalAddr, nftRemoteAddr, nftLocal, nftRemote,
   793  		cAcc, pAcc, aliceAuth, recoveryCh,
   794  		sync.Mutex{},
   795  		testNFT,
   796  	}
   797  
   798  	// Start a event handling loop.
   799  	wg := sync.WaitGroup{}
   800  	wg.Add((2 * testTxCount) - testPendingCount)
   801  	isRecovery := false
   802  	reqHandler := func(ev IRequestValueTransferEvent) {
   803  		t.Log("request value transfer", "nonce", ev.GetRequestNonce())
   804  		if ev.GetRequestNonce() >= (testTxCount - testPendingCount) {
   805  			t.Log("missing handle value transfer", "nonce", ev.GetRequestNonce())
   806  		} else {
   807  			switch ev.GetTokenType() {
   808  			case KLAY, ERC20, ERC721:
   809  				break
   810  			default:
   811  				t.Errorf("received ev.TokenType is unknown: %v", ev.GetTokenType())
   812  				return
   813  			}
   814  
   815  			if ev.GetRaw().Address == info.localInfo.address {
   816  				ops[ev.GetTokenType()].handle(&info, info.remoteInfo, ev)
   817  			} else {
   818  				ops[ev.GetTokenType()].handle(&info, info.localInfo, ev)
   819  			}
   820  		}
   821  	}
   822  	go func() {
   823  		for {
   824  			select {
   825  			case ev := <-recoveryCh:
   826  				isRecovery = ev
   827  			case ev := <-requestVTCh:
   828  				reqHandler(ev)
   829  				if !isRecovery {
   830  					wg.Done()
   831  				}
   832  			case ev := <-requestVTencodedCh:
   833  				reqHandler(ev)
   834  				if !isRecovery {
   835  					wg.Done()
   836  				}
   837  			case ev := <-handleVTCh:
   838  				t.Log("handle value transfer", "nonce", ev.HandleNonce)
   839  				if !isRecovery {
   840  					wg.Done()
   841  				}
   842  			}
   843  		}
   844  	}()
   845  
   846  	// Request value transfer.
   847  	vtcallback(&info)
   848  	WaitGroupWithTimeOut(&wg, testTimeout, t)
   849  
   850  	return &info
   851  }
   852  
   853  func requestKLAYTransfer(info *testInfo, bi *BridgeInfo) {
   854  	bi.account.Lock()
   855  	defer bi.account.UnLock()
   856  
   857  	opts := bi.account.GenerateTransactOpts()
   858  	opts.Value = big.NewInt(testAmount)
   859  	tx, err := bi.bridge.RequestKLAYTransfer(opts, info.aliceAuth.From, big.NewInt(testAmount), nil)
   860  	if err != nil {
   861  		log.Fatalf("Failed to RequestKLAYTransfer: %v", err)
   862  	}
   863  	info.sim.Commit()
   864  	assert.Nil(info.t, bind.CheckWaitMined(info.sim, tx))
   865  }
   866  
   867  func handleKLAYTransfer(info *testInfo, bi *BridgeInfo, ev IRequestValueTransferEvent) {
   868  	bi.account.Lock()
   869  	defer bi.account.UnLock()
   870  
   871  	assert.Equal(info.t, new(big.Int).SetUint64(testAmount), ev.GetValueOrTokenId())
   872  	opts := bi.account.GenerateTransactOpts()
   873  	tx, err := bi.bridge.HandleKLAYTransfer(opts, ev.GetRaw().TxHash, ev.GetFrom(), ev.GetTo(), ev.GetValueOrTokenId(), ev.GetRequestNonce(), ev.GetRaw().BlockNumber, ev.GetExtraData())
   874  	if err != nil {
   875  		log.Fatalf("\tFailed to HandleKLAYTransfer: %v", err)
   876  	}
   877  	info.sim.Commit()
   878  	assert.Nil(info.t, bind.CheckWaitMined(info.sim, tx))
   879  }
   880  
   881  // TODO-Klaytn-ServiceChain: use ChildChainEventHandler
   882  func dummyHandleRequestKLAYTransfer(info *testInfo, bi *BridgeInfo) {
   883  	for _, ev := range bi.GetPendingRequestEvents() {
   884  		handleKLAYTransfer(info, bi, ev.(RequestValueTransferEvent))
   885  	}
   886  	info.sim.Commit()
   887  }
   888  
   889  func requestTokenTransfer(info *testInfo, bi *BridgeInfo) {
   890  	bi.account.Lock()
   891  	defer bi.account.UnLock()
   892  
   893  	var tx *types.Transaction
   894  
   895  	testToken := big.NewInt(testToken)
   896  	opts := bi.account.GenerateTransactOpts()
   897  
   898  	var err error
   899  	if bi.onChildChain {
   900  		tx, err = info.tokenLocalBridge.RequestValueTransfer(opts, testToken, info.chainAuth.From, big.NewInt(0), nil)
   901  	} else {
   902  		tx, err = info.tokenRemoteBridge.RequestValueTransfer(opts, testToken, info.nodeAuth.From, big.NewInt(0), nil)
   903  	}
   904  
   905  	if err != nil {
   906  		log.Fatalf("Failed to RequestValueTransfer for charging: %v", err)
   907  	}
   908  	info.sim.Commit()
   909  	assert.Nil(info.t, bind.CheckWaitMined(info.sim, tx))
   910  }
   911  
   912  func handleTokenTransfer(info *testInfo, bi *BridgeInfo, ev IRequestValueTransferEvent) {
   913  	bi.account.Lock()
   914  	defer bi.account.UnLock()
   915  
   916  	assert.Equal(info.t, new(big.Int).SetUint64(testToken), ev.GetValueOrTokenId())
   917  	tx, err := bi.bridge.HandleERC20Transfer(
   918  		bi.account.GenerateTransactOpts(), ev.GetRaw().TxHash, ev.GetFrom(), ev.GetTo(), info.tokenRemoteAddr, ev.GetValueOrTokenId(), ev.GetRequestNonce(), ev.GetRaw().BlockNumber, ev.GetExtraData())
   919  	if err != nil {
   920  		log.Fatalf("Failed to HandleERC20Transfer: %v", err)
   921  	}
   922  	info.sim.Commit()
   923  	assert.Nil(info.t, bind.CheckWaitMined(info.sim, tx))
   924  }
   925  
   926  // TODO-Klaytn-ServiceChain: use ChildChainEventHandler
   927  func dummyHandleRequestTokenTransfer(info *testInfo, bi *BridgeInfo) {
   928  	for _, ev := range bi.GetPendingRequestEvents() {
   929  		handleTokenTransfer(info, bi, ev.(RequestValueTransferEvent))
   930  	}
   931  	info.sim.Commit()
   932  }
   933  
   934  func requestNFTTransfer(info *testInfo, bi *BridgeInfo) {
   935  	bi.account.Lock()
   936  	defer bi.account.UnLock()
   937  
   938  	var tx *types.Transaction
   939  
   940  	opts := bi.account.GenerateTransactOpts()
   941  	// TODO-Klaytn need to separate child / parent chain nftIndex.
   942  	nftIndex := new(big.Int).SetInt64(info.nftIndex)
   943  
   944  	var err error
   945  	if bi.onChildChain {
   946  		tx, err = info.nftLocalBridge.RequestValueTransfer(opts, nftIndex, info.aliceAuth.From, nil)
   947  	} else {
   948  		tx, err = info.nftRemoteBridge.RequestValueTransfer(opts, nftIndex, info.aliceAuth.From, nil)
   949  	}
   950  
   951  	if err != nil {
   952  		log.Fatalf("Failed to requestNFTTransfer for charging: %v", err)
   953  	}
   954  	info.nftIndex++
   955  	info.sim.Commit()
   956  	assert.Nil(info.t, bind.CheckWaitMined(info.sim, tx))
   957  }
   958  
   959  func handleNFTTransfer(info *testInfo, bi *BridgeInfo, ev IRequestValueTransferEvent) {
   960  	bi.account.Lock()
   961  	defer bi.account.UnLock()
   962  
   963  	var nftAddr common.Address
   964  
   965  	if bi.onChildChain {
   966  		nftAddr = info.nftLocalAddr
   967  	} else {
   968  		nftAddr = info.nftRemoteAddr
   969  	}
   970  	uri := GetURI(ev)
   971  	tx, err := bi.bridge.HandleERC721Transfer(
   972  		bi.account.GenerateTransactOpts(),
   973  		ev.GetRaw().TxHash, ev.GetFrom(), ev.GetTo(), nftAddr, ev.GetValueOrTokenId(),
   974  		ev.GetRequestNonce(), ev.GetRaw().BlockNumber, uri, ev.GetExtraData())
   975  	if err != nil {
   976  		log.Fatalf("Failed to handleERC721Transfer: %v", err)
   977  	}
   978  	info.sim.Commit()
   979  	assert.Nil(info.t, bind.CheckWaitMined(info.sim, tx))
   980  }
   981  
   982  // TODO-Klaytn-ServiceChain: use ChildChainEventHandler
   983  func dummyHandleRequestNFTTransfer(info *testInfo, bi *BridgeInfo) {
   984  	for _, ev := range bi.GetPendingRequestEvents() {
   985  		handleNFTTransfer(info, bi, ev)
   986  	}
   987  	info.sim.Commit()
   988  }