github.com/klaytn/klaytn@v1.10.2/consensus/istanbul/backend/kip103_test.go (about)

     1  package backend
     2  
     3  import (
     4  	"context"
     5  	"encoding/json"
     6  	"fmt"
     7  	"math/big"
     8  	"strings"
     9  	"testing"
    10  	"time"
    11  
    12  	"github.com/klaytn/klaytn"
    13  	"github.com/klaytn/klaytn/accounts/abi"
    14  	"github.com/klaytn/klaytn/common"
    15  	"github.com/klaytn/klaytn/common/hexutil"
    16  	"github.com/klaytn/klaytn/contracts/kip103"
    17  	"github.com/klaytn/klaytn/params"
    18  	"github.com/stretchr/testify/assert"
    19  )
    20  
    21  type mockKip103ContractCaller struct {
    22  	abi        abi.ABI
    23  	funcSigMap map[string]string
    24  	retMap     map[string][]interface{}
    25  }
    26  
    27  func (caller *mockKip103ContractCaller) CodeAt(ctx context.Context, contract common.Address, blockNumber *big.Int) ([]byte, error) {
    28  	return []byte(kip103.TreasuryRebalanceBinRuntime), nil
    29  }
    30  
    31  func (caller *mockKip103ContractCaller) CallContract(ctx context.Context, call klaytn.CallMsg, blockNumber *big.Int) ([]byte, error) {
    32  	funcSig := hexutil.Encode(call.Data[:4])[2:]
    33  	funcName := strings.Split(caller.funcSigMap[funcSig], "(")[0]
    34  	mockKey := funcName
    35  
    36  	if funcName == "retirees" || funcName == "newbies" {
    37  		lastByte := call.Data[len(call.Data)-1]
    38  		mockKey = fmt.Sprintf("%s%v", funcName, lastByte)
    39  	}
    40  
    41  	mockRet := caller.retMap[mockKey]
    42  	return caller.abi.Methods[funcName].Outputs.Pack(mockRet...)
    43  }
    44  
    45  func TestRebalanceTreasury(t *testing.T) {
    46  	bc, istBackend := newBlockChain(1)
    47  	defer func() {
    48  		istBackend.Stop()
    49  		bc.Stop()
    50  	}()
    51  
    52  	parsed, err := abi.JSON(strings.NewReader(kip103.TreasuryRebalanceABI))
    53  	if err != nil {
    54  		t.Fatal(err)
    55  	}
    56  
    57  	// time to generate blocks
    58  	time.Sleep(2 * time.Second)
    59  
    60  	block := bc.CurrentBlock()
    61  
    62  	bc.Config().Kip103CompatibleBlock = block.Number()
    63  	bc.Config().Kip103ContractAddress = common.Address{}
    64  
    65  	retireds := []struct {
    66  		addr    common.Address
    67  		balance *big.Int
    68  	}{
    69  		{
    70  			addr:    common.HexToAddress("0x9712f943b296758aaae79944ec975884188d3a96"),
    71  			balance: new(big.Int).Mul(big.NewInt(1000000), big.NewInt(params.KLAY)),
    72  		},
    73  		{
    74  			addr:    common.HexToAddress("0x5aaeb6053f3e94c9b9a09f33669435e7ef1beaed"),
    75  			balance: new(big.Int).Mul(big.NewInt(700000), big.NewInt(params.KLAY)),
    76  		},
    77  		{
    78  			addr:    common.HexToAddress("0xfb6916095ca1df60bb79ce92ce3ea74c37c5d359"),
    79  			balance: new(big.Int).Mul(big.NewInt(12345), big.NewInt(params.KLAY)),
    80  		},
    81  	}
    82  
    83  	totalRetiredBalance := big.NewInt(0)
    84  	for _, retired := range retireds {
    85  		totalRetiredBalance.Add(totalRetiredBalance, retired.balance)
    86  	}
    87  
    88  	defaultReturnMap := make(map[string][]interface{})
    89  	defaultReturnMap["getRetiredCount"] = []interface{}{big.NewInt(3)}
    90  	defaultReturnMap["retirees0"] = []interface{}{retireds[0].addr}
    91  	defaultReturnMap["retirees1"] = []interface{}{retireds[1].addr}
    92  	defaultReturnMap["retirees2"] = []interface{}{retireds[2].addr}
    93  
    94  	defaultReturnMap["getNewbieCount"] = []interface{}{big.NewInt(3)}
    95  	defaultReturnMap["newbies0"] = []interface{}{common.HexToAddress("0x819104a190255e0cedbdd9d5f59a557633d79db1"), new(big.Int).Mul(big.NewInt(1000000), big.NewInt(params.KLAY))}
    96  	defaultReturnMap["newbies1"] = []interface{}{common.HexToAddress("0x75c3098be5e4b63fbac05838daaee378dd48098d"), new(big.Int).Mul(big.NewInt(500000), big.NewInt(params.KLAY))}
    97  	defaultReturnMap["newbies2"] = []interface{}{common.HexToAddress("0xceB7ADDFBa9665d8767173D47dE4453D7b7B900D"), new(big.Int).Mul(big.NewInt(123412), big.NewInt(params.KLAY))}
    98  
    99  	defaultReturnMap["rebalanceBlockNumber"] = []interface{}{block.Number()}
   100  	defaultReturnMap["status"] = []interface{}{uint8(2)}
   101  
   102  	testCases := []struct {
   103  		modifier func(retMap map[string][]interface{})
   104  		// TODO-aidn: add result checker also
   105  		expectedErr error
   106  	}{
   107  		{
   108  			func(retMap map[string][]interface{}) {
   109  				// do nothing
   110  			},
   111  			nil,
   112  		},
   113  		{
   114  			func(retMap map[string][]interface{}) {
   115  				retMap["status"] = []interface{}{uint8(1)}
   116  			},
   117  			errNotProperStatus,
   118  		},
   119  		{
   120  			func(retMap map[string][]interface{}) {
   121  				retMap["newbies0"][1] = totalRetiredBalance
   122  				retMap["newbies1"][1] = big.NewInt(0)
   123  				retMap["newbies2"][1] = big.NewInt(0)
   124  			},
   125  			nil,
   126  		},
   127  		{
   128  			func(retMap map[string][]interface{}) {
   129  				retMap["newbies0"][1] = totalRetiredBalance
   130  				retMap["newbies1"][1] = big.NewInt(0)
   131  				retMap["newbies2"][1] = big.NewInt(1)
   132  			},
   133  			errNotEnoughRetiredBal,
   134  		},
   135  	}
   136  
   137  	for _, tc := range testCases {
   138  		// reset state
   139  		state, err := bc.StateAt(block.Root())
   140  		if err != nil {
   141  			t.Fatal(err)
   142  		}
   143  
   144  		// initializing retireds' assets
   145  		for i := range retireds {
   146  			state.SetBalance(retireds[i].addr, retireds[i].balance)
   147  		}
   148  
   149  		// modification for each test case
   150  		mockRetMap := make(map[string][]interface{})
   151  		for k, v := range defaultReturnMap {
   152  			mockRetMap[k] = v
   153  		}
   154  
   155  		tc.modifier(mockRetMap)
   156  
   157  		c := &mockKip103ContractCaller{abi: parsed, funcSigMap: kip103.TreasuryRebalanceFuncSigs, retMap: mockRetMap}
   158  		ret, err := RebalanceTreasury(state, bc, block.Header(), c)
   159  		assert.Equal(t, tc.expectedErr, err)
   160  
   161  		// balance check
   162  		if ret.Success {
   163  			totalRetired := big.NewInt(0)
   164  			for addr, amount := range ret.Retired {
   165  				totalRetired.Add(totalRetired, amount)
   166  				assert.Equal(t, big.NewInt(0), state.GetBalance(addr))
   167  			}
   168  
   169  			totalNewbie := big.NewInt(0)
   170  			for _, amount := range ret.Newbie {
   171  				// TODO: compare mockRetMap balance with state.GetBalance(addr)
   172  				totalNewbie.Add(totalNewbie, amount)
   173  			}
   174  			assert.Equal(t, totalRetired, new(big.Int).Add(totalNewbie, ret.Burnt))
   175  		}
   176  
   177  		memo, _ := json.Marshal(ret)
   178  		t.Log(string(memo))
   179  	}
   180  }