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