github.com/fibonacci-chain/fbc@v0.0.0-20231124064014-c7636198c1e9/app/types/account_test.go (about)

     1  package types
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  	authtypes "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/x/auth/types"
     7  	"math/big"
     8  	"testing"
     9  
    10  	ethcrypto "github.com/ethereum/go-ethereum/crypto"
    11  	"github.com/fibonacci-chain/fbc/libs/cosmos-sdk/x/auth/exported"
    12  	tmcrypto "github.com/fibonacci-chain/fbc/libs/tendermint/crypto"
    13  	"github.com/stretchr/testify/require"
    14  
    15  	"github.com/stretchr/testify/suite"
    16  
    17  	tmamino "github.com/fibonacci-chain/fbc/libs/tendermint/crypto/encoding/amino"
    18  	"github.com/fibonacci-chain/fbc/libs/tendermint/crypto/secp256k1"
    19  
    20  	"github.com/fibonacci-chain/fbc/app/crypto/ethsecp256k1"
    21  	sdk "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types"
    22  	"github.com/fibonacci-chain/fbc/libs/cosmos-sdk/x/auth"
    23  
    24  	"github.com/fibonacci-chain/fbc/libs/cosmos-sdk/codec"
    25  	"github.com/fibonacci-chain/fbc/libs/tendermint/crypto/ed25519"
    26  	"github.com/fibonacci-chain/fbc/libs/tendermint/crypto/sr25519"
    27  )
    28  
    29  func init() {
    30  	tmamino.RegisterKeyType(ethsecp256k1.PubKey{}, ethsecp256k1.PubKeyName)
    31  	tmamino.RegisterKeyType(ethsecp256k1.PrivKey{}, ethsecp256k1.PrivKeyName)
    32  }
    33  
    34  type AccountTestSuite struct {
    35  	suite.Suite
    36  
    37  	account *EthAccount
    38  }
    39  
    40  func (suite *AccountTestSuite) SetupTest() {
    41  	pubkey := secp256k1.GenPrivKey().PubKey()
    42  	addr := sdk.AccAddress(pubkey.Address())
    43  	balance := sdk.NewCoins(NewPhotonCoin(sdk.OneInt()))
    44  	baseAcc := auth.NewBaseAccount(addr, balance, pubkey, 10, 50)
    45  	suite.account = &EthAccount{
    46  		BaseAccount: baseAcc,
    47  		CodeHash:    []byte{1, 2},
    48  	}
    49  }
    50  
    51  func TestAccountTestSuite(t *testing.T) {
    52  	suite.Run(t, new(AccountTestSuite))
    53  }
    54  
    55  func (suite *AccountTestSuite) TestEthAccount_Balance() {
    56  
    57  	testCases := []struct {
    58  		name         string
    59  		denom        string
    60  		initialCoins sdk.Coins
    61  		amount       sdk.Int
    62  	}{
    63  		{"positive diff", NativeToken, sdk.Coins{}, sdk.OneInt()},
    64  		{"zero diff, same coin", NativeToken, sdk.NewCoins(NewPhotonCoin(sdk.ZeroInt())), sdk.ZeroInt()},
    65  		{"zero diff, other coin", sdk.DefaultBondDenom, sdk.NewCoins(NewPhotonCoin(sdk.ZeroInt())), sdk.ZeroInt()},
    66  		{"negative diff", NativeToken, sdk.NewCoins(NewPhotonCoin(sdk.NewInt(10))), sdk.NewInt(1)},
    67  	}
    68  
    69  	for _, tc := range testCases {
    70  		suite.Run(tc.name, func() {
    71  			suite.SetupTest() // reset values
    72  			suite.account.SetCoins(tc.initialCoins)
    73  
    74  			suite.account.SetBalance(tc.denom, sdk.NewDecFromInt(tc.amount))
    75  			suite.Require().Equal(sdk.NewDecFromInt(tc.amount), suite.account.Balance(tc.denom))
    76  		})
    77  	}
    78  
    79  }
    80  
    81  func (suite *AccountTestSuite) TestEthermintAccountJSON() {
    82  	bz, err := json.Marshal(suite.account)
    83  	suite.Require().NoError(err)
    84  
    85  	bz1, err := suite.account.MarshalJSON()
    86  	suite.Require().NoError(err)
    87  	suite.Require().Equal(string(bz1), string(bz))
    88  
    89  	var a EthAccount
    90  	suite.Require().NoError(a.UnmarshalJSON(bz))
    91  	suite.Require().Equal(suite.account.String(), a.String())
    92  	suite.Require().Equal(suite.account.PubKey, a.PubKey)
    93  }
    94  
    95  func (suite *AccountTestSuite) TestEthermintPubKeyJSON() {
    96  	privkey, err := ethsecp256k1.GenerateKey()
    97  	suite.Require().NoError(err)
    98  	bz := privkey.PubKey().Bytes()
    99  
   100  	pubk, err := tmamino.PubKeyFromBytes(bz)
   101  	suite.Require().NoError(err)
   102  	suite.Require().Equal(pubk, privkey.PubKey())
   103  }
   104  
   105  func (suite *AccountTestSuite) TestSecpPubKeyJSON() {
   106  	pubkey := secp256k1.GenPrivKey().PubKey()
   107  	bz := pubkey.Bytes()
   108  
   109  	pubk, err := tmamino.PubKeyFromBytes(bz)
   110  	suite.Require().NoError(err)
   111  	suite.Require().Equal(pubk, pubkey)
   112  }
   113  
   114  func (suite *AccountTestSuite) TestEthermintAccount_String() {
   115  	config := sdk.GetConfig()
   116  	SetBech32Prefixes(config)
   117  
   118  	bech32pubkey, err := sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeAccPub, suite.account.PubKey)
   119  	suite.Require().NoError(err)
   120  
   121  	accountStr := fmt.Sprintf(`|
   122    address: %s
   123    eth_address: %s
   124    coins:
   125    - denom: %s
   126      amount: "1.000000000000000000"
   127    public_key: %s
   128    account_number: 10
   129    sequence: 50
   130    code_hash: "0102"
   131  `, suite.account.Address, suite.account.EthAddress().String(), sdk.DefaultBondDenom, bech32pubkey)
   132  
   133  	suite.Require().Equal(accountStr, suite.account.String())
   134  
   135  	i, err := suite.account.MarshalYAML()
   136  	suite.Require().NoError(err)
   137  
   138  	var ok bool
   139  	accountStr, ok = i.(string)
   140  	suite.Require().True(ok)
   141  	suite.Require().Contains(accountStr, suite.account.Address.String())
   142  	suite.Require().Contains(accountStr, bech32pubkey)
   143  }
   144  
   145  func (suite *AccountTestSuite) TestEthermintAccount_MarshalJSON() {
   146  	bz, err := suite.account.MarshalJSON()
   147  	suite.Require().NoError(err)
   148  	suite.Require().Contains(string(bz), suite.account.EthAddress().String())
   149  
   150  	res := new(EthAccount)
   151  	err = res.UnmarshalJSON(bz)
   152  	suite.Require().NoError(err)
   153  	suite.Require().Equal(suite.account, res)
   154  
   155  	bech32pubkey, err := sdk.Bech32ifyPubKey(sdk.Bech32PubKeyTypeAccPub, suite.account.PubKey)
   156  	suite.Require().NoError(err)
   157  
   158  	// test that the sdk.AccAddress is populated from the hex address
   159  	jsonAcc := fmt.Sprintf(
   160  		`{"address":"","eth_address":"%s","coins":[{"denom":"aphoton","amount":"1"}],"public_key":"%s","account_number":10,"sequence":50,"code_hash":"0102"}`,
   161  		suite.account.EthAddress().String(), bech32pubkey,
   162  	)
   163  
   164  	res = new(EthAccount)
   165  	err = res.UnmarshalJSON([]byte(jsonAcc))
   166  	suite.Require().NoError(err)
   167  	suite.Require().Equal(suite.account.Address.String(), res.Address.String())
   168  
   169  	jsonAcc = fmt.Sprintf(
   170  		`{"address":"","eth_address":"","coins":[{"denom":"aphoton","amount":"1"}],"public_key":"%s","account_number":10,"sequence":50,"code_hash":"0102"}`,
   171  		bech32pubkey,
   172  	)
   173  
   174  	res = new(EthAccount)
   175  	err = res.UnmarshalJSON([]byte(jsonAcc))
   176  	suite.Require().Error(err, "should fail if both address are empty")
   177  
   178  	// test that the sdk.AccAddress is populated from the hex address
   179  	jsonAcc = fmt.Sprintf(
   180  		`{"address": "%s","eth_address":"0x0000000000000000000000000000000000000000","coins":[{"denom":"aphoton","amount":"1"}],"public_key":"%s","account_number":10,"sequence":50,"code_hash":"0102"}`,
   181  		suite.account.Address.String(), bech32pubkey,
   182  	)
   183  
   184  	res = new(EthAccount)
   185  	err = res.UnmarshalJSON([]byte(jsonAcc))
   186  	suite.Require().Error(err, "should fail if addresses mismatch")
   187  }
   188  
   189  func TestEthAccountAmino(t *testing.T) {
   190  	cdc := codec.New()
   191  	cdc.RegisterInterface((*exported.Account)(nil), nil)
   192  	RegisterCodec(cdc)
   193  
   194  	cdc.RegisterInterface((*tmcrypto.PubKey)(nil), nil)
   195  	cdc.RegisterConcrete(ed25519.PubKeyEd25519{},
   196  		ed25519.PubKeyAminoName, nil)
   197  	cdc.RegisterConcrete(sr25519.PubKeySr25519{},
   198  		sr25519.PubKeyAminoName, nil)
   199  	cdc.RegisterConcrete(secp256k1.PubKeySecp256k1{},
   200  		secp256k1.PubKeyAminoName, nil)
   201  
   202  	privKey := secp256k1.GenPrivKey()
   203  	pubKey := privKey.PubKey()
   204  	addr := sdk.AccAddress(pubKey.Address())
   205  
   206  	accounts := []EthAccount{
   207  		{},
   208  		{
   209  			auth.NewBaseAccount(
   210  				addr,
   211  				sdk.NewCoins(NewPhotonCoin(sdk.OneInt()), sdk.Coin{"heco", sdk.Dec{big.NewInt(1)}}),
   212  				pubKey,
   213  				1,
   214  				1,
   215  			),
   216  			ethcrypto.Keccak256(nil),
   217  		},
   218  		{
   219  			auth.NewBaseAccount(
   220  				addr,
   221  				sdk.NewCoins(NewPhotonCoin(sdk.ZeroInt()), sdk.Coin{"heco", sdk.Dec{big.NewInt(0)}}),
   222  				pubKey,
   223  				0,
   224  				0,
   225  			),
   226  			ethcrypto.Keccak256(nil),
   227  		},
   228  		{
   229  			auth.NewBaseAccount(
   230  				nil,
   231  				nil,
   232  				nil,
   233  				0,
   234  				0,
   235  			),
   236  			ethcrypto.Keccak256(nil),
   237  		},
   238  		{
   239  			BaseAccount: &auth.BaseAccount{},
   240  		},
   241  	}
   242  
   243  	for _, testAccount := range accounts {
   244  		data, err := cdc.MarshalBinaryBare(&testAccount)
   245  		if err != nil {
   246  			t.Fatal("marshal error")
   247  		}
   248  		require.Equal(t, len(data), 4+testAccount.AminoSize(cdc))
   249  
   250  		var accountFromAmino exported.Account
   251  
   252  		err = cdc.UnmarshalBinaryBare(data, &accountFromAmino)
   253  		if err != nil {
   254  			t.Fatal("unmarshal error")
   255  		}
   256  
   257  		var accountFromUnmarshaller exported.Account
   258  		v, err := cdc.UnmarshalBinaryBareWithRegisteredUnmarshaller(data, (*exported.Account)(nil))
   259  		require.NoError(t, err)
   260  		accountFromUnmarshaller, ok := v.(exported.Account)
   261  		require.True(t, ok)
   262  
   263  		require.EqualValues(t, accountFromAmino, accountFromUnmarshaller)
   264  
   265  		var ethAccount EthAccount
   266  		err = ethAccount.UnmarshalFromAmino(cdc, data[4:])
   267  		require.NoError(t, err)
   268  		require.EqualValues(t, accountFromAmino, &ethAccount)
   269  
   270  		dataFromMarshaller, err := cdc.MarshalBinaryBareWithRegisteredMarshaller(&testAccount)
   271  		require.NoError(t, err)
   272  		require.EqualValues(t, data, dataFromMarshaller)
   273  
   274  		dataFromSizer, err := cdc.MarshalBinaryWithSizer(&testAccount, false)
   275  		require.NoError(t, err)
   276  		require.EqualValues(t, data, dataFromSizer)
   277  
   278  		dataFromMarshaller, err = ethAccount.MarshalToAmino(cdc)
   279  		if dataFromMarshaller == nil {
   280  			dataFromMarshaller = []byte{}
   281  		}
   282  		require.Equal(t, data[4:], dataFromMarshaller)
   283  	}
   284  }
   285  
   286  func BenchmarkEthAccountAminoUnmarshal(b *testing.B) {
   287  	cdc := codec.New()
   288  	cdc.RegisterInterface((*exported.Account)(nil), nil)
   289  	RegisterCodec(cdc)
   290  
   291  	cdc.RegisterInterface((*tmcrypto.PubKey)(nil), nil)
   292  	cdc.RegisterConcrete(ed25519.PubKeyEd25519{},
   293  		ed25519.PubKeyAminoName, nil)
   294  	cdc.RegisterConcrete(sr25519.PubKeySr25519{},
   295  		sr25519.PubKeyAminoName, nil)
   296  	cdc.RegisterConcrete(secp256k1.PubKeySecp256k1{},
   297  		secp256k1.PubKeyAminoName, nil)
   298  
   299  	privKey := secp256k1.GenPrivKey()
   300  	pubKey := privKey.PubKey()
   301  	addr := sdk.AccAddress(pubKey.Address())
   302  
   303  	balance := sdk.NewCoins(NewPhotonCoin(sdk.OneInt()))
   304  	testAccount := EthAccount{
   305  		BaseAccount: auth.NewBaseAccount(addr, balance, pubKey, 1, 1),
   306  		CodeHash:    ethcrypto.Keccak256(nil),
   307  	}
   308  
   309  	data, _ := cdc.MarshalBinaryBare(&testAccount)
   310  
   311  	b.ResetTimer()
   312  	b.ReportAllocs()
   313  
   314  	b.Run("amino", func(b *testing.B) {
   315  		b.ReportAllocs()
   316  		for i := 0; i < b.N; i++ {
   317  			var account exported.Account
   318  			_ = cdc.UnmarshalBinaryBare(data, &account)
   319  		}
   320  	})
   321  
   322  	b.Run("unmarshaller", func(b *testing.B) {
   323  		b.ReportAllocs()
   324  		for i := 0; i < b.N; i++ {
   325  			// var account exported.Account
   326  			_, _ = cdc.UnmarshalBinaryBareWithRegisteredUnmarshaller(data, (*exported.Account)(nil))
   327  		}
   328  	})
   329  }
   330  
   331  func BenchmarkEthAccountAminoMarshal(b *testing.B) {
   332  	cdc := codec.New()
   333  	cdc.RegisterInterface((*exported.Account)(nil), nil)
   334  	RegisterCodec(cdc)
   335  
   336  	cdc.RegisterInterface((*tmcrypto.PubKey)(nil), nil)
   337  	cdc.RegisterConcrete(ed25519.PubKeyEd25519{},
   338  		ed25519.PubKeyAminoName, nil)
   339  	cdc.RegisterConcrete(sr25519.PubKeySr25519{},
   340  		sr25519.PubKeyAminoName, nil)
   341  	cdc.RegisterConcrete(secp256k1.PubKeySecp256k1{},
   342  		secp256k1.PubKeyAminoName, nil)
   343  
   344  	privKey := secp256k1.GenPrivKey()
   345  	pubKey := privKey.PubKey()
   346  	addr := sdk.AccAddress(pubKey.Address())
   347  
   348  	balance := sdk.NewCoins(NewPhotonCoin(sdk.OneInt()))
   349  	testAccount := EthAccount{
   350  		BaseAccount: auth.NewBaseAccount(addr, balance, pubKey, 1, 1),
   351  		CodeHash:    ethcrypto.Keccak256(nil),
   352  	}
   353  
   354  	b.ResetTimer()
   355  	b.ReportAllocs()
   356  
   357  	b.Run("amino", func(b *testing.B) {
   358  		b.ReportAllocs()
   359  		for i := 0; i < b.N; i++ {
   360  			data, _ := cdc.MarshalBinaryBare(&testAccount)
   361  			_ = data
   362  		}
   363  	})
   364  
   365  	b.Run("marshaller", func(b *testing.B) {
   366  		b.ReportAllocs()
   367  		for i := 0; i < b.N; i++ {
   368  			data, _ := cdc.MarshalBinaryBareWithRegisteredMarshaller(&testAccount)
   369  			_ = data
   370  		}
   371  	})
   372  
   373  	b.Run("sizer", func(b *testing.B) {
   374  		b.ReportAllocs()
   375  		for i := 0; i < b.N; i++ {
   376  			data, _ := cdc.MarshalBinaryWithSizer(&testAccount, false)
   377  			_ = data
   378  		}
   379  	})
   380  }
   381  
   382  func (acc EthAccount) utOldCopy() sdk.Account {
   383  	return &EthAccount{
   384  		authtypes.NewBaseAccount(acc.Address, acc.Coins, acc.PubKey, acc.AccountNumber, acc.Sequence),
   385  		acc.CodeHash,
   386  	}
   387  }
   388  
   389  func BenchmarkEthAccountCopy(b *testing.B) {
   390  	privKey := secp256k1.GenPrivKey()
   391  	pubKey := privKey.PubKey()
   392  	addr := sdk.AccAddress(pubKey.Address())
   393  
   394  	balance := sdk.NewCoins(NewPhotonCoin(sdk.OneInt()))
   395  	testAccount := EthAccount{
   396  		BaseAccount: auth.NewBaseAccount(addr, balance, pubKey, 1, 1),
   397  		CodeHash:    ethcrypto.Keccak256(nil),
   398  	}
   399  
   400  	var copied sdk.Account
   401  
   402  	b.Run("copy", func(b *testing.B) {
   403  		b.ReportAllocs()
   404  		for i := 0; i < b.N; i++ {
   405  			copied = testAccount.Copy()
   406  		}
   407  	})
   408  	b.Run("old", func(b *testing.B) {
   409  		b.ReportAllocs()
   410  		for i := 0; i < b.N; i++ {
   411  			copied = testAccount.utOldCopy()
   412  		}
   413  	})
   414  	_ = copied
   415  }