github.com/klaytn/klaytn@v1.10.2/tests/kip103_test.go (about)

     1  package tests
     2  
     3  import (
     4  	"context"
     5  	"math/big"
     6  	"os"
     7  	"testing"
     8  	"time"
     9  
    10  	"github.com/klaytn/klaytn"
    11  	"github.com/klaytn/klaytn/accounts/abi/bind"
    12  	"github.com/klaytn/klaytn/api"
    13  	"github.com/klaytn/klaytn/blockchain/types"
    14  	"github.com/klaytn/klaytn/common"
    15  	"github.com/klaytn/klaytn/common/hexutil"
    16  	"github.com/klaytn/klaytn/consensus/istanbul"
    17  	"github.com/klaytn/klaytn/contracts/kip103"
    18  	"github.com/klaytn/klaytn/log"
    19  	"github.com/klaytn/klaytn/networks/rpc"
    20  	"github.com/klaytn/klaytn/node/cn"
    21  	"github.com/klaytn/klaytn/params"
    22  	"github.com/stretchr/testify/assert"
    23  )
    24  
    25  type testKip103TxTransactor struct {
    26  	node *cn.CN
    27  }
    28  
    29  func (t *testKip103TxTransactor) FilterLogs(ctx context.Context, query klaytn.FilterQuery) ([]types.Log, error) {
    30  	return nil, nil
    31  }
    32  
    33  func (t *testKip103TxTransactor) SubscribeFilterLogs(ctx context.Context, query klaytn.FilterQuery, ch chan<- types.Log) (klaytn.Subscription, error) {
    34  	return nil, nil
    35  }
    36  
    37  func (t *testKip103TxTransactor) PendingCodeAt(ctx context.Context, account common.Address) ([]byte, error) {
    38  	return t.CodeAt(ctx, account, nil)
    39  }
    40  
    41  func (t *testKip103TxTransactor) PendingNonceAt(ctx context.Context, account common.Address) (uint64, error) {
    42  	return t.node.TxPool().GetPendingNonce(account), nil
    43  }
    44  
    45  func (t *testKip103TxTransactor) SuggestGasPrice(ctx context.Context) (*big.Int, error) {
    46  	return big.NewInt(int64(t.node.BlockChain().Config().UnitPrice)), nil
    47  }
    48  
    49  func (t *testKip103TxTransactor) EstimateGas(ctx context.Context, call klaytn.CallMsg) (gas uint64, err error) {
    50  	return uint64(1e8), nil
    51  }
    52  
    53  func (t *testKip103TxTransactor) SendTransaction(ctx context.Context, tx *types.Transaction) error {
    54  	return t.node.TxPool().AddLocal(tx)
    55  }
    56  
    57  func (t *testKip103TxTransactor) ChainID(ctx context.Context) (*big.Int, error) {
    58  	return t.node.BlockChain().Config().ChainID, nil
    59  }
    60  
    61  func (t *testKip103TxTransactor) CodeAt(ctx context.Context, contract common.Address, blockNumber *big.Int) ([]byte, error) {
    62  	if blockNumber == nil {
    63  		blockNumber = t.node.BlockChain().CurrentBlock().Number()
    64  	}
    65  	root := t.node.BlockChain().GetHeaderByNumber(blockNumber.Uint64()).Root
    66  	state, err := t.node.BlockChain().StateAt(root)
    67  	if err != nil {
    68  		return nil, err
    69  	}
    70  	return state.GetCode(contract), nil
    71  }
    72  
    73  func (t *testKip103TxTransactor) CallContract(ctx context.Context, call klaytn.CallMsg, blockNumber *big.Int) ([]byte, error) {
    74  	if blockNumber == nil {
    75  		blockNumber = t.node.BlockChain().CurrentBlock().Number()
    76  	}
    77  
    78  	price := hexutil.Big(*t.node.TxPool().GasPrice())
    79  	if call.GasPrice != nil {
    80  		price = hexutil.Big(*call.GasPrice)
    81  	}
    82  
    83  	value := hexutil.Big(*big.NewInt(0))
    84  	if call.Value != nil {
    85  		value = hexutil.Big(*call.Value)
    86  	}
    87  
    88  	arg := api.CallArgs{From: call.From, To: call.To, Gas: hexutil.Uint64(1e8), GasPrice: &price, Value: value, Data: call.Data}
    89  	bn := rpc.BlockNumber(blockNumber.Int64())
    90  
    91  	apiBackend := api.NewPublicBlockChainAPI(t.node.APIBackend)
    92  	return apiBackend.Call(ctx, arg, rpc.NewBlockNumberOrHashWithNumber(bn))
    93  }
    94  
    95  func TestRebalanceTreasury_EOA(t *testing.T) {
    96  	log.EnableLogForTest(log.LvlError, log.LvlInfo)
    97  
    98  	// prepare chain configuration
    99  	config := params.CypressChainConfig.Copy()
   100  	config.LondonCompatibleBlock = big.NewInt(0)
   101  	config.IstanbulCompatibleBlock = big.NewInt(0)
   102  	config.EthTxTypeCompatibleBlock = big.NewInt(0)
   103  	config.MagmaCompatibleBlock = big.NewInt(0)
   104  	config.KoreCompatibleBlock = big.NewInt(0)
   105  	config.Istanbul.SubGroupSize = 1
   106  	config.Istanbul.ProposerPolicy = uint64(istanbul.RoundRobin)
   107  	config.Governance.Reward.MintingAmount = new(big.Int).Mul(big.NewInt(9000000000000000000), big.NewInt(params.KLAY))
   108  
   109  	// make a blockchain node
   110  	fullNode, node, validator, _, workspace := newBlockchain(t, config)
   111  	defer func() {
   112  		fullNode.Stop()
   113  		os.RemoveAll(workspace)
   114  	}()
   115  
   116  	optsOwner := bind.NewKeyedTransactor(validator.Keys[0])
   117  	transactor := &testKip103TxTransactor{node: node}
   118  	targetBlockNum := new(big.Int).Add(node.BlockChain().CurrentBlock().Number(), big.NewInt(5))
   119  
   120  	contractAddr, _, contract, err := kip103.DeployTreasuryRebalance(optsOwner, transactor, targetBlockNum)
   121  	if err != nil {
   122  		t.Fatal(err)
   123  	}
   124  
   125  	// set kip103 hardfork config
   126  	node.BlockChain().Config().Kip103CompatibleBlock = targetBlockNum
   127  	node.BlockChain().Config().Kip103ContractAddress = contractAddr
   128  
   129  	t.Log("ContractOwner Addr:", validator.GetAddr().String())
   130  	t.Log("Contract Addr:", contractAddr.String())
   131  	t.Log("Target Block:", targetBlockNum.Int64())
   132  
   133  	// naive waiting for tx processing
   134  	time.Sleep(2 * time.Second)
   135  
   136  	// prepare newbie accounts
   137  	numNewbie := 3
   138  	newbieAccs := make([]TestAccount, numNewbie)
   139  	newbieAllocs := make([]*big.Int, numNewbie)
   140  
   141  	state, err := node.BlockChain().State()
   142  	if err != nil {
   143  		t.Fatal(err)
   144  	}
   145  	totalNewbieAlloc := state.GetBalance(validator.Addr)
   146  	t.Log("Total Newbie amount: ", totalNewbieAlloc)
   147  
   148  	for i := 0; i < numNewbie; i++ {
   149  		newbieAccs[i] = genKlaytnLegacyAccount(t)
   150  		newbieAllocs[i] = new(big.Int).Div(totalNewbieAlloc, big.NewInt(2))
   151  		totalNewbieAlloc.Sub(totalNewbieAlloc, newbieAllocs[i])
   152  
   153  		t.Log("Newbie", i, "Addr:", newbieAccs[i].GetAddr().String())
   154  		t.Log("Newbie", i, "Amount:", newbieAllocs[i])
   155  	}
   156  
   157  	// register RegisterRetired
   158  	if _, err := contract.RegisterRetired(optsOwner, validator.Addr); err != nil {
   159  		t.Fatal(err)
   160  	}
   161  
   162  	// register newbies
   163  	for i, newbie := range newbieAccs {
   164  		if _, err := contract.RegisterNewbie(optsOwner, newbie.GetAddr(), newbieAllocs[i]); err != nil {
   165  			t.Fatal(err)
   166  		}
   167  	}
   168  
   169  	// initialized -> registered
   170  	if _, err := contract.FinalizeRegistration(optsOwner); err != nil {
   171  		t.Fatal(err)
   172  	}
   173  
   174  	// approve
   175  	if _, err := contract.Approve(optsOwner, validator.GetAddr()); err != nil {
   176  		t.Fatal(err)
   177  	}
   178  
   179  	// registered -> approved
   180  	if _, err := contract.FinalizeApproval(optsOwner); err != nil {
   181  		t.Fatal(err)
   182  	}
   183  
   184  	header := waitBlock(node.BlockChain(), targetBlockNum.Uint64())
   185  	if header == nil {
   186  		t.Fatal("timeout")
   187  	}
   188  
   189  	curState, err := node.BlockChain().StateAt(header.Root)
   190  	if err != nil {
   191  		t.Fatal(err)
   192  	}
   193  
   194  	balRetired := curState.GetBalance(validator.GetAddr())
   195  	assert.Equal(t, balRetired, big.NewInt(0))
   196  
   197  	for j, newbie := range newbieAccs {
   198  		balNewbie := curState.GetBalance(newbie.GetAddr())
   199  		assert.Equal(t, newbieAllocs[j], balNewbie)
   200  	}
   201  }