github.com/stafiprotocol/go-substrate-rpc-client@v1.4.7/rpc/rpcs_test.go (about)

     1  package rpc_test
     2  
     3  import (
     4  	"fmt"
     5  	"math/big"
     6  	"testing"
     7  	"time"
     8  
     9  	"github.com/stafiprotocol/go-substrate-rpc-client/config"
    10  	"github.com/stafiprotocol/go-substrate-rpc-client/rpc"
    11  	"github.com/stafiprotocol/go-substrate-rpc-client/signature"
    12  	"github.com/stafiprotocol/go-substrate-rpc-client/types"
    13  )
    14  
    15  func Example_simpleConnect() {
    16  	// The following example shows how to instantiate a Substrate API and use it to connect to a node
    17  
    18  	rpcs, err := rpc.NewRPCS(config.Default().RPCURL)
    19  	if err != nil {
    20  		panic(err)
    21  	}
    22  
    23  	chain, err := rpcs.System.Chain()
    24  	if err != nil {
    25  		panic(err)
    26  	}
    27  	nodeName, err := rpcs.System.Name()
    28  	if err != nil {
    29  		panic(err)
    30  	}
    31  	nodeVersion, err := rpcs.System.Version()
    32  	if err != nil {
    33  		panic(err)
    34  	}
    35  
    36  	fmt.Printf("You are connected to chain %v using %v v%v\n", chain, nodeName, nodeVersion)
    37  
    38  	// Output: You are connected to chain Development using Substrate Node v2.0.0-a200cdb9-x86_64-linux-gnu
    39  }
    40  
    41  func Example_listenToNewBlocks() {
    42  	// This example shows how to subscribe to new blocks.
    43  	//
    44  	// It displays the block number every time a new block is seen by the node you are connected to.
    45  	//
    46  	// NOTE: The example runs until 10 blocks are received or until you stop it with CTRL+C
    47  
    48  	rpcs, err := rpc.NewRPCS(config.Default().RPCURL)
    49  	if err != nil {
    50  		panic(err)
    51  	}
    52  
    53  	sub, err := rpcs.Chain.SubscribeNewHeads()
    54  	if err != nil {
    55  		panic(err)
    56  	}
    57  	defer sub.Unsubscribe()
    58  
    59  	count := 0
    60  
    61  	for {
    62  		head := <-sub.Chan()
    63  		fmt.Printf("Chain is at block: #%v\n", head.Number)
    64  		count++
    65  
    66  		if count == 10 {
    67  			sub.Unsubscribe()
    68  			break
    69  		}
    70  	}
    71  }
    72  
    73  func Example_listenToBalanceChange() {
    74  	// This example shows how to instantiate a Substrate API and use it to connect to a node and retrieve balance
    75  	// updates
    76  	//
    77  	// NOTE: The example runs until you stop it with CTRL+C
    78  
    79  	rpcs, err := rpc.NewRPCS(config.Default().RPCURL)
    80  	if err != nil {
    81  		panic(err)
    82  	}
    83  
    84  	meta, err := rpcs.State.GetMetadataLatest()
    85  	if err != nil {
    86  		panic(err)
    87  	}
    88  
    89  	// Known account we want to use (available on dev chain, with funds)
    90  	alice, err := types.HexDecodeString("0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d")
    91  	if err != nil {
    92  		panic(err)
    93  	}
    94  
    95  	key, err := types.CreateStorageKey(meta, "Balances", "FreeBalance", alice, nil)
    96  	if err != nil {
    97  		panic(err)
    98  	}
    99  
   100  	// Retrieve the initial balance
   101  	var previous types.U128
   102  	ok, err := rpcs.State.GetStorageLatest(key, &previous)
   103  	if err != nil || !ok {
   104  		panic(err)
   105  	}
   106  
   107  	fmt.Printf("%#x has a balance of %v\n", alice, previous)
   108  	fmt.Printf("You may leave this example running and transfer any value to %#x\n", alice)
   109  
   110  	// Here we subscribe to any balance changes
   111  	sub, err := rpcs.State.SubscribeStorageRaw([]types.StorageKey{key})
   112  	if err != nil {
   113  		panic(err)
   114  	}
   115  	defer sub.Unsubscribe()
   116  
   117  	// outer for loop for subscription notifications
   118  	for {
   119  		// inner loop for the changes within one of those notifications
   120  		for _, chng := range (<-sub.Chan()).Changes {
   121  			var current types.U128
   122  			if err = types.DecodeFromBytes(chng.StorageData, &current); err != nil {
   123  				panic(err)
   124  			}
   125  
   126  			// Calculate the delta
   127  			var change = types.U128{Int: big.NewInt(0).Sub(current.Int, previous.Int)}
   128  
   129  			// Only display positive value changes (Since we are pulling `previous` above already,
   130  			// the initial balance change will also be zero)
   131  			if change.Cmp(big.NewInt(0)) != 0 {
   132  				previous = current
   133  				fmt.Printf("New balance change of: %v\n", change)
   134  				return
   135  			}
   136  		}
   137  	}
   138  }
   139  
   140  func Example_unsubscribeFromListeningToUpdates() {
   141  	// This example shows how to subscribe to and later unsubscribe from listening to block updates.
   142  	//
   143  	// In this example we're calling the built-in unsubscribe() function after a timeOut of 20s to cleanup and
   144  	// unsubscribe from listening to updates.
   145  
   146  	rpcs, err := rpc.NewRPCS(config.Default().RPCURL)
   147  	if err != nil {
   148  		panic(err)
   149  	}
   150  
   151  	sub, err := rpcs.Chain.SubscribeNewHeads()
   152  	if err != nil {
   153  		panic(err)
   154  	}
   155  	defer sub.Unsubscribe()
   156  
   157  	timeout := time.After(20 * time.Second)
   158  
   159  	for {
   160  		select {
   161  		case head := <-sub.Chan():
   162  			fmt.Printf("Chain is at block: #%v\n", head.Number)
   163  		case <-timeout:
   164  			sub.Unsubscribe()
   165  			fmt.Println("Unsubscribed")
   166  			return
   167  		}
   168  	}
   169  }
   170  
   171  func Example_makeASimpleTransfer() {
   172  	// This sample shows how to create a transaction to make a transfer from one an account to another.
   173  
   174  	// Instantiate the API
   175  	rpcs, err := rpc.NewRPCS(config.Default().RPCURL)
   176  	if err != nil {
   177  		panic(err)
   178  	}
   179  
   180  	meta, err := rpcs.State.GetMetadataLatest()
   181  	if err != nil {
   182  		panic(err)
   183  	}
   184  
   185  	// Create a call, transferring 12345 units to Bob
   186  	bob, err := types.NewAddressFromHexAccountID("0x8eaf04151687736326c9fea17e25fc5287613693c912909cb226aa4794f26a48")
   187  	if err != nil {
   188  		panic(err)
   189  	}
   190  
   191  	c, err := types.NewCall(meta, "Balances.transfer", bob, types.NewUCompactFromUInt(12345))
   192  	if err != nil {
   193  		panic(err)
   194  	}
   195  
   196  	// Create the extrinsic
   197  	ext := types.NewExtrinsic(c)
   198  
   199  	genesisHash, err := rpcs.Chain.GetBlockHash(0)
   200  	if err != nil {
   201  		panic(err)
   202  	}
   203  
   204  	rv, err := rpcs.State.GetRuntimeVersionLatest()
   205  	if err != nil {
   206  		panic(err)
   207  	}
   208  
   209  	key, err := types.CreateStorageKey(meta, "System", "Account", signature.TestKeyringPairAlice.PublicKey, nil)
   210  	if err != nil {
   211  		panic(err)
   212  	}
   213  
   214  	var accountInfo types.AccountInfo
   215  	ok, err := rpcs.State.GetStorageLatest(key, &accountInfo)
   216  	if err != nil || !ok {
   217  		panic(err)
   218  	}
   219  
   220  	nonce := uint32(accountInfo.Nonce)
   221  
   222  	o := types.SignatureOptions{
   223  		BlockHash:   genesisHash,
   224  		Era:         types.ExtrinsicEra{IsMortalEra: false},
   225  		GenesisHash: genesisHash,
   226  		Nonce:       types.NewUCompactFromUInt(uint64(nonce)),
   227  		SpecVersion: rv.SpecVersion,
   228  		Tip:         types.NewUCompactFromUInt(0),
   229  	}
   230  
   231  	// Sign the transaction using Alice's default account
   232  	err = ext.Sign(signature.TestKeyringPairAlice, o)
   233  	if err != nil {
   234  		panic(err)
   235  	}
   236  
   237  	// Send the extrinsic
   238  	hash, err := rpcs.Author.SubmitExtrinsic(ext)
   239  	if err != nil {
   240  		panic(err)
   241  	}
   242  
   243  	fmt.Printf("Transfer sent with hash %#x\n", hash)
   244  }
   245  
   246  func Example_displaySystemEvents() {
   247  	// Query the system events and extract information from them. This example runs until exited via Ctrl-C
   248  
   249  	// Create our API with a default connection to the local node
   250  	rpcs, err := rpc.NewRPCS(config.Default().RPCURL)
   251  	if err != nil {
   252  		panic(err)
   253  	}
   254  	meta, err := rpcs.State.GetMetadataLatest()
   255  	if err != nil {
   256  		panic(err)
   257  	}
   258  
   259  	// Subscribe to system events via storage
   260  	key, err := types.CreateStorageKey(meta, "System", "Events", nil, nil)
   261  	if err != nil {
   262  		panic(err)
   263  	}
   264  
   265  	sub, err := rpcs.State.SubscribeStorageRaw([]types.StorageKey{key})
   266  	if err != nil {
   267  		panic(err)
   268  	}
   269  	defer sub.Unsubscribe()
   270  
   271  	// outer for loop for subscription notifications
   272  	for {
   273  		set := <-sub.Chan()
   274  		// inner loop for the changes within one of those notifications
   275  		for _, chng := range set.Changes {
   276  			if !types.Eq(chng.StorageKey, key) || !chng.HasStorageData {
   277  				// skip, we are only interested in events with content
   278  				continue
   279  			}
   280  
   281  			// Decode the event records
   282  			events := types.EventRecords{}
   283  			err = types.EventRecordsRaw(chng.StorageData).DecodeEventRecords(meta, &events)
   284  			if err != nil {
   285  				panic(err)
   286  			}
   287  
   288  			// Show what we are busy with
   289  			for _, e := range events.Balances_Endowed {
   290  				fmt.Printf("\tBalances:Endowed:: (phase=%#v)\n", e.Phase)
   291  				fmt.Printf("\t\t%#x, %v\n", e.Who, e.Balance)
   292  			}
   293  			for _, e := range events.Balances_DustLost {
   294  				fmt.Printf("\tBalances:DustLost:: (phase=%#v)\n", e.Phase)
   295  				fmt.Printf("\t\t%#x, %v\n", e.Who, e.Balance)
   296  			}
   297  			for _, e := range events.Balances_Transfer {
   298  				fmt.Printf("\tBalances:Transfer:: (phase=%#v)\n", e.Phase)
   299  				fmt.Printf("\t\t%v, %v, %v\n", e.From, e.To, e.Value)
   300  			}
   301  			for _, e := range events.Balances_BalanceSet {
   302  				fmt.Printf("\tBalances:BalanceSet:: (phase=%#v)\n", e.Phase)
   303  				fmt.Printf("\t\t%v, %v, %v\n", e.Who, e.Free, e.Reserved)
   304  			}
   305  			for _, e := range events.Balances_Deposit {
   306  				fmt.Printf("\tBalances:Deposit:: (phase=%#v)\n", e.Phase)
   307  				fmt.Printf("\t\t%v, %v\n", e.Who, e.Balance)
   308  			}
   309  			for _, e := range events.Grandpa_NewAuthorities {
   310  				fmt.Printf("\tGrandpa:NewAuthorities:: (phase=%#v)\n", e.Phase)
   311  				fmt.Printf("\t\t%v\n", e.NewAuthorities)
   312  			}
   313  			for _, e := range events.Grandpa_Paused {
   314  				fmt.Printf("\tGrandpa:Paused:: (phase=%#v)\n", e.Phase)
   315  			}
   316  			for _, e := range events.Grandpa_Resumed {
   317  				fmt.Printf("\tGrandpa:Resumed:: (phase=%#v)\n", e.Phase)
   318  			}
   319  			for _, e := range events.ImOnline_HeartbeatReceived {
   320  				fmt.Printf("\tImOnline:HeartbeatReceived:: (phase=%#v)\n", e.Phase)
   321  				fmt.Printf("\t\t%#x\n", e.AuthorityID)
   322  			}
   323  			for _, e := range events.ImOnline_AllGood {
   324  				fmt.Printf("\tImOnline:AllGood:: (phase=%#v)\n", e.Phase)
   325  			}
   326  			for _, e := range events.ImOnline_SomeOffline {
   327  				fmt.Printf("\tImOnline:SomeOffline:: (phase=%#v)\n", e.Phase)
   328  				fmt.Printf("\t\t%v\n", e.IdentificationTuples)
   329  			}
   330  			for _, e := range events.Indices_IndexAssigned {
   331  				fmt.Printf("\tIndices:IndexAssigned:: (phase=%#v)\n", e.Phase)
   332  				fmt.Printf("\t\t%#x%v\n", e.AccountID, e.AccountIndex)
   333  			}
   334  			for _, e := range events.Indices_IndexFreed {
   335  				fmt.Printf("\tIndices:IndexFreed:: (phase=%#v)\n", e.Phase)
   336  				fmt.Printf("\t\t%v\n", e.AccountIndex)
   337  			}
   338  			for _, e := range events.Offences_Offence {
   339  				fmt.Printf("\tOffences:Offence:: (phase=%#v)\n", e.Phase)
   340  				fmt.Printf("\t\t%v%v\n", e.Kind, e.OpaqueTimeSlot)
   341  			}
   342  			for _, e := range events.Session_NewSession {
   343  				fmt.Printf("\tSession:NewSession:: (phase=%#v)\n", e.Phase)
   344  				fmt.Printf("\t\t%v\n", e.SessionIndex)
   345  			}
   346  			for _, e := range events.Staking_Reward {
   347  				fmt.Printf("\tStaking:Reward:: (phase=%#v)\n", e.Phase)
   348  				fmt.Printf("\t\t%v\n", e.Amount)
   349  			}
   350  			for _, e := range events.Staking_Slash {
   351  				fmt.Printf("\tStaking:Slash:: (phase=%#v)\n", e.Phase)
   352  				fmt.Printf("\t\t%#x%v\n", e.AccountID, e.Balance)
   353  			}
   354  			for _, e := range events.Staking_OldSlashingReportDiscarded {
   355  				fmt.Printf("\tStaking:OldSlashingReportDiscarded:: (phase=%#v)\n", e.Phase)
   356  				fmt.Printf("\t\t%v\n", e.SessionIndex)
   357  			}
   358  			for _, e := range events.System_ExtrinsicSuccess {
   359  				fmt.Printf("\tSystem:ExtrinsicSuccess:: (phase=%#v)\n", e.Phase)
   360  			}
   361  			for _, e := range events.System_ExtrinsicFailed {
   362  				fmt.Printf("\tSystem:ErtrinsicFailed:: (phase=%#v)\n", e.Phase)
   363  				fmt.Printf("\t\t%v\n", e.DispatchError)
   364  			}
   365  			for _, e := range events.System_CodeUpdated {
   366  				fmt.Printf("\tSystem:CodeUpdated:: (phase=%#v)\n", e.Phase)
   367  			}
   368  			for _, e := range events.System_NewAccount {
   369  				fmt.Printf("\tSystem:NewAccount:: (phase=%#v)\n", e.Phase)
   370  				fmt.Printf("\t\t%#x\n", e.Who)
   371  			}
   372  			for _, e := range events.System_KilledAccount {
   373  				fmt.Printf("\tSystem:KilledAccount:: (phase=%#v)\n", e.Phase)
   374  				fmt.Printf("\t\t%#X\n", e.Who)
   375  			}
   376  		}
   377  	}
   378  }
   379  
   380  func Example_transactionWithEvents() {
   381  	// Display the events that occur during a transfer by sending a value to bob
   382  
   383  	// Instantiate the API
   384  	rpcs, err := rpc.NewRPCS(config.Default().RPCURL)
   385  	if err != nil {
   386  		panic(err)
   387  	}
   388  
   389  	meta, err := rpcs.State.GetMetadataLatest()
   390  	if err != nil {
   391  		panic(err)
   392  	}
   393  
   394  	// Create a call, transferring 12345 units to Bob
   395  	bob, err := types.NewAddressFromHexAccountID("0x8eaf04151687736326c9fea17e25fc5287613693c912909cb226aa4794f26a48")
   396  	if err != nil {
   397  		panic(err)
   398  	}
   399  
   400  	amount := types.NewUCompactFromUInt(12345)
   401  
   402  	c, err := types.NewCall(meta, "Balances.transfer", bob, amount)
   403  	if err != nil {
   404  		panic(err)
   405  	}
   406  
   407  	// Create the extrinsic
   408  	ext := types.NewExtrinsic(c)
   409  	if err != nil {
   410  		panic(err)
   411  	}
   412  
   413  	genesisHash, err := rpcs.Chain.GetBlockHash(0)
   414  	if err != nil {
   415  		panic(err)
   416  	}
   417  
   418  	rv, err := rpcs.State.GetRuntimeVersionLatest()
   419  	if err != nil {
   420  		panic(err)
   421  	}
   422  
   423  	// Get the nonce for Alice
   424  	key, err := types.CreateStorageKey(meta, "System", "Account", signature.TestKeyringPairAlice.PublicKey, nil)
   425  	if err != nil {
   426  		panic(err)
   427  	}
   428  
   429  	var accountInfo types.AccountInfo
   430  	ok, err := rpcs.State.GetStorageLatest(key, &accountInfo)
   431  	if err != nil || !ok {
   432  		panic(err)
   433  	}
   434  
   435  	nonce := uint32(accountInfo.Nonce)
   436  
   437  	o := types.SignatureOptions{
   438  		BlockHash:   genesisHash,
   439  		Era:         types.ExtrinsicEra{IsMortalEra: false},
   440  		GenesisHash: genesisHash,
   441  		Nonce:       types.NewUCompactFromUInt(uint64(nonce)),
   442  		SpecVersion: rv.SpecVersion,
   443  		Tip:         types.NewUCompactFromUInt(0),
   444  	}
   445  
   446  	fmt.Printf("Sending %v from %#x to %#x with nonce %v", amount, signature.TestKeyringPairAlice.PublicKey, bob.AsAccountID, nonce)
   447  
   448  	// Sign the transaction using Alice's default account
   449  	err = ext.Sign(signature.TestKeyringPairAlice, o)
   450  	if err != nil {
   451  		panic(err)
   452  	}
   453  
   454  	// Do the transfer and track the actual status
   455  	sub, err := rpcs.Author.SubmitAndWatchExtrinsic(ext)
   456  	if err != nil {
   457  		panic(err)
   458  	}
   459  	defer sub.Unsubscribe()
   460  
   461  	for {
   462  		status := <-sub.Chan()
   463  		fmt.Printf("Transaction status: %#v\n", status)
   464  
   465  		if status.IsInBlock {
   466  			fmt.Printf("Completed at block hash: %#x\n", status.AsInBlock)
   467  			return
   468  		}
   469  	}
   470  }
   471  
   472  func TestV13(t *testing.T) {
   473  	url := "wss://kusama-rpc.polkadot.io"
   474  	rpcs, err := rpc.NewRPCS(url)
   475  	if err != nil {
   476  		panic(err)
   477  	}
   478  
   479  	genesisHash, err := rpcs.Chain.GetBlockHash(0)
   480  	if err != nil {
   481  		t.Fatal(err)
   482  	}
   483  
   484  	t.Log(genesisHash.Hex())
   485  }
   486  
   487  type StakingLedger struct {
   488  	Stash          types.AccountID
   489  	Total          types.UCompact
   490  	Active         types.UCompact
   491  	Unlocking      []UnlockChunk
   492  	ClaimedRewards []uint32
   493  }
   494  
   495  type UnlockChunk struct {
   496  	Value types.UCompact
   497  	Era   types.UCompact
   498  }
   499  
   500  func QueryStakingLeder(endpoint string, ac types.AccountID) (*StakingLedger, bool, error) {
   501  	rpcs, err := rpc.NewRPCS(config.Default().RPCURL)
   502  	if err != nil {
   503  		panic(err)
   504  	}
   505  
   506  	meta, err := rpcs.State.GetMetadataLatest()
   507  	if err != nil {
   508  		return nil, false, err
   509  	}
   510  
   511  	key, err := types.CreateStorageKey(meta, "Staking", "Ledger", ac[:], nil)
   512  	if err != nil {
   513  		return nil, false, err
   514  	}
   515  
   516  	ledger := new(StakingLedger)
   517  	ok, err := rpcs.State.GetStorageLatest(key, ledger)
   518  	if err != nil {
   519  		return nil, false, err
   520  	}
   521  
   522  	return ledger, ok, nil
   523  }