github.com/hyperledger/burrow@v0.34.5-0.20220512172541-77f09336001d/integration/rpcinfo/info_server_test.go (about) 1 // +build integration 2 3 // Space above here matters 4 // Copyright Monax Industries Limited 5 // SPDX-License-Identifier: Apache-2.0 6 7 package rpcinfo 8 9 import ( 10 "context" 11 "encoding/json" 12 "sort" 13 "testing" 14 "time" 15 16 "github.com/hyperledger/burrow/rpc" 17 "github.com/hyperledger/burrow/rpc/lib/jsonrpc" 18 19 tmjson "github.com/tendermint/tendermint/libs/json" 20 21 "github.com/hyperledger/burrow/integration" 22 "github.com/hyperledger/burrow/txs/payload" 23 24 "github.com/hyperledger/burrow/core" 25 26 "github.com/hyperledger/burrow/binary" 27 "github.com/hyperledger/burrow/event" 28 "github.com/hyperledger/burrow/execution/exec" 29 "github.com/hyperledger/burrow/integration/rpctest" 30 "github.com/hyperledger/burrow/rpc/rpcinfo/infoclient" 31 "github.com/hyperledger/burrow/rpc/rpctransact" 32 "github.com/hyperledger/burrow/txs" 33 "github.com/stretchr/testify/assert" 34 "github.com/stretchr/testify/require" 35 ctypes "github.com/tendermint/tendermint/consensus/types" 36 ) 37 38 const timeout = 5 * time.Second 39 40 func TestInfoServer(t *testing.T) { 41 kern, shutdown := integration.RunNode(t, rpctest.GenesisDoc, rpctest.PrivateAccounts) 42 defer shutdown() 43 inputAddress := rpctest.PrivateAccounts[0].GetAddress() 44 infoAddress := "http://" + kern.InfoListenAddress().String() 45 var clients = map[string]rpc.Client{ 46 "JSON RPC": jsonrpc.NewClient(infoAddress), 47 "URI": jsonrpc.NewURIClient(infoAddress), 48 } 49 cli := rpctest.NewTransactClient(t, kern.GRPCListenAddress().String()) 50 for clientName, rpcClient := range clients { 51 t.Run(clientName, func(t *testing.T) { 52 t.Run("Status", func(t *testing.T) { 53 t.Parallel() 54 resp, err := infoclient.Status(rpcClient) 55 require.NoError(t, err) 56 assert.Contains(t, resp.GetNodeInfo().GetMoniker(), "node") 57 assert.Equal(t, rpctest.GenesisDoc.GetChainID(), resp.NodeInfo.Network, 58 "ChainID should match NodeInfo.Network") 59 }) 60 61 t.Run("Account", func(t *testing.T) { 62 t.Parallel() 63 acc := rpctest.GetAccount(t, rpcClient, rpctest.PrivateAccounts[0].GetAddress()) 64 if acc == nil { 65 t.Fatal("Account was nil") 66 } 67 if acc.GetAddress() != rpctest.PrivateAccounts[0].GetAddress() { 68 t.Fatalf("Failed to get correct account. Got %s, expected %s", acc.GetAddress(), 69 rpctest.PrivateAccounts[0].GetAddress()) 70 } 71 }) 72 73 t.Run("Storage", func(t *testing.T) { 74 t.Parallel() 75 amt, gasLim, fee := uint64(1100), uint64(1000), uint64(1000) 76 code := []byte{0x60, 0x5, 0x60, 0x1, 0x55} 77 // Call with nil address will create a contract 78 txe, err := cli.CallTxSync(context.Background(), &payload.CallTx{ 79 Input: &payload.TxInput{ 80 Address: inputAddress, 81 Amount: amt, 82 }, 83 Data: code, 84 GasLimit: gasLim, 85 Fee: fee, 86 }) 87 require.NoError(t, err) 88 assert.Equal(t, true, txe.Receipt.CreatesContract, "This transaction should"+ 89 " create a contract") 90 assert.NotEqual(t, 0, len(txe.TxHash), "Receipt should contain a"+ 91 " transaction hash") 92 contractAddr := txe.Receipt.ContractAddress 93 assert.NotEqual(t, 0, len(contractAddr), "Transactions claims to have"+ 94 " created a contract but the contract address is empty") 95 96 v := rpctest.GetStorage(t, rpcClient, contractAddr, []byte{0x1}) 97 got := binary.LeftPadWord256(v) 98 expected := binary.LeftPadWord256([]byte{0x5}) 99 if got.Compare(expected) != 0 { 100 t.Fatalf("Wrong storage value. Got %x, expected %x", got.Bytes(), 101 expected.Bytes()) 102 } 103 }) 104 105 t.Run("Block", func(t *testing.T) { 106 t.Parallel() 107 waitNBlocks(t, kern, 1) 108 res, err := infoclient.Block(rpcClient, 1) 109 require.NoError(t, err) 110 assert.Equal(t, int64(1), res.Block.Height) 111 }) 112 113 t.Run("WaitBlocks", func(t *testing.T) { 114 t.Parallel() 115 waitNBlocks(t, kern, 5) 116 }) 117 118 t.Run("BlockchainInfo", func(t *testing.T) { 119 t.Parallel() 120 // wait a mimimal number of blocks to ensure that the later query for block 121 // headers has a non-trivial length 122 nBlocks := 4 123 waitNBlocks(t, kern, nBlocks) 124 125 resp, err := infoclient.Blocks(rpcClient, 1, 0) 126 if err != nil { 127 t.Fatalf("Failed to get blockchain info: %v", err) 128 } 129 lastBlockHeight := resp.LastHeight 130 nMetaBlocks := len(resp.BlockMetas) 131 assert.True(t, uint64(nMetaBlocks) <= lastBlockHeight, 132 "Logically number of block metas should be equal or less than block height.") 133 assert.True(t, nBlocks <= len(resp.BlockMetas), 134 "Should see at least %v BlockMetas after waiting for %v blocks but saw %v", 135 nBlocks, nBlocks, len(resp.BlockMetas)) 136 // For the maximum number (default to 20) of retrieved block headers, 137 // check that they correctly chain to each other. 138 lastBlockHash := resp.BlockMetas[0].Header.Hash() 139 for i := 1; i < nMetaBlocks-1; i++ { 140 // the blockhash in header of height h should be identical to the hash 141 // in the LastBlockID of the header of block height h+1. 142 assert.Equal(t, lastBlockHash, resp.BlockMetas[i].Header.LastBlockID.Hash, 143 "Blockchain should be a hash tree!") 144 lastBlockHash = resp.BlockMetas[i].Header.Hash() 145 } 146 147 // Now retrieve only two blockheaders (h=1, and h=2) and check that we got 148 // two results. 149 resp, err = infoclient.Blocks(rpcClient, 1, 2) 150 assert.NoError(t, err) 151 assert.Equal(t, 2, len(resp.BlockMetas), 152 "Should see 2 BlockMetas after extracting 2 blocks") 153 }) 154 155 t.Run("UnconfirmedTxs", func(t *testing.T) { 156 amt, gasLim, fee := uint64(1100), uint64(1000), uint64(1000) 157 code := []byte{0x60, 0x5, 0x60, 0x1, 0x55} 158 // Call with nil address will create a contract 159 txEnv := rpctest.MakeDefaultCallTx(t, rpcClient, nil, code, amt, gasLim, fee) 160 txChan := make(chan []*txs.Envelope) 161 162 // We want to catch the Tx in mempool before it gets reaped by tendermint 163 // consensus. We should be able to do this almost always if we broadcast our 164 // transaction immediately after a block has been committed. There is about 165 // 1 second between blocks, and we will have the lock on Reap 166 // So we wait for a block here 167 waitNBlocks(t, kern, 1) 168 169 go func() { 170 for { 171 resp, err := infoclient.UnconfirmedTxs(rpcClient, -1) 172 if err != nil { 173 // We get an error on exit 174 return 175 } 176 if resp.NumTxs > 0 { 177 txChan <- resp.Txs 178 } 179 } 180 }() 181 182 broadcastTxSync(t, cli, txEnv) 183 select { 184 case <-time.After(time.Second * timeout): 185 t.Fatal("Timeout out waiting for unconfirmed transactions to appear") 186 case transactions := <-txChan: 187 assert.Len(t, transactions, 1, "There should only be a single transaction in the "+ 188 "mempool during this test (previous txs should have made it into a block)") 189 assert.Contains(t, transactions, txEnv, "Transaction should be returned by ListUnconfirmedTxs") 190 } 191 }) 192 193 t.Run("Validators", func(t *testing.T) { 194 t.Parallel() 195 resp, err := infoclient.Validators(rpcClient) 196 assert.NoError(t, err) 197 assert.Len(t, resp.BondedValidators, 1) 198 validator := resp.BondedValidators[0] 199 assert.Equal(t, rpctest.GenesisDoc.Validators[0].PublicKey, validator.PublicKey) 200 }) 201 202 t.Run("Consensus", func(t *testing.T) { 203 t.Parallel() 204 resp, err := infoclient.Consensus(rpcClient) 205 require.NoError(t, err) 206 207 // Now I do a special dance... because the votes section of RoundState has will Marshal but not Unmarshal yet 208 // TODO: put in a PR in tendermint to fix thiss 209 rawMap := make(map[string]json.RawMessage) 210 err = json.Unmarshal(resp.RoundState, &rawMap) 211 require.NoError(t, err) 212 delete(rawMap, "votes") 213 214 bs, err := json.Marshal(rawMap) 215 require.NoError(t, err) 216 217 rs := new(ctypes.RoundState) 218 err = tmjson.Unmarshal(bs, rs) 219 require.NoError(t, err) 220 221 assert.Equal(t, rs.Validators.Validators[0].Address, rs.Validators.Proposer.Address) 222 }) 223 224 t.Run("Names", func(t *testing.T) { 225 t.Parallel() 226 names := []string{"bib", "flub", "flib"} 227 sort.Strings(names) 228 for _, name := range names { 229 _, err := rpctest.UpdateName(cli, inputAddress, name, name, 99999) 230 require.NoError(t, err) 231 } 232 233 entry, err := infoclient.Name(rpcClient, names[0]) 234 require.NoError(t, err) 235 assert.Equal(t, names[0], entry.Name) 236 assert.Equal(t, names[0], entry.Data) 237 238 entry, err = infoclient.Name(rpcClient, "asdasdas") 239 require.NoError(t, err) 240 require.Nil(t, entry) 241 242 var namesOut []string 243 entries, err := infoclient.Names(rpcClient, "") 244 require.NoError(t, err) 245 for _, entry := range entries { 246 namesOut = append(namesOut, entry.Name) 247 } 248 require.Equal(t, names, namesOut) 249 250 namesOut = namesOut[:0] 251 entries, err = infoclient.Names(rpcClient, "fl") 252 require.NoError(t, err) 253 for _, entry := range entries { 254 namesOut = append(namesOut, entry.Name) 255 } 256 require.Equal(t, []string{"flib", "flub"}, namesOut) 257 }) 258 }) 259 } 260 261 } 262 263 func waitNBlocks(t testing.TB, kern *core.Kernel, n int) { 264 subID := event.GenSubID() 265 ch, err := kern.Emitter.Subscribe(context.Background(), subID, exec.QueryForBlockExecution(), 10) 266 require.NoError(t, err) 267 defer kern.Emitter.UnsubscribeAll(context.Background(), subID) 268 for i := 0; i < n; i++ { 269 <-ch 270 } 271 } 272 273 func broadcastTxSync(t testing.TB, cli rpctransact.TransactClient, txEnv *txs.Envelope) *exec.TxExecution { 274 txe, err := cli.BroadcastTxSync(context.Background(), &rpctransact.TxEnvelopeParam{ 275 Envelope: txEnv, 276 }) 277 require.NoError(t, err) 278 return txe 279 }