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 }