|
|
- package rpc
-
- import (
- "bytes"
- "encoding/hex"
- "github.com/tendermint/tendermint/account"
- . "github.com/tendermint/tendermint/common"
- "github.com/tendermint/tendermint/config"
- "github.com/tendermint/tendermint/consensus"
- "github.com/tendermint/tendermint/logger"
- nm "github.com/tendermint/tendermint/node"
- "github.com/tendermint/tendermint/p2p"
- ctypes "github.com/tendermint/tendermint/rpc/core/types"
- cclient "github.com/tendermint/tendermint/rpc/core_client"
- "github.com/tendermint/tendermint/state"
- "github.com/tendermint/tendermint/types"
- "testing"
- "time"
- )
-
- // global variables for use across all tests
- var (
- rpcAddr = "127.0.0.1:8089"
- requestAddr = "http://" + rpcAddr + "/"
- websocketAddr = "ws://" + rpcAddr + "/events"
-
- node *nm.Node
-
- mempoolCount = 0
-
- userAddr = "1D7A91CB32F758A02EBB9BE1FB6F8DEE56F90D42"
- userPriv = "C453604BD6480D5538B4C6FD2E3E314B5BCE518D75ADE4DA3DA85AB8ADFD819606FBAC4E285285D1D91FCBC7E91C780ADA11516F67462340B3980CE2B94940E8"
- userPub = "06FBAC4E285285D1D91FCBC7E91C780ADA11516F67462340B3980CE2B94940E8"
- userByteAddr, userBytePriv = initUserBytes()
-
- clients = map[string]cclient.Client{
- "JSONRPC": cclient.NewClient(requestAddr, "JSONRPC"),
- "HTTP": cclient.NewClient(requestAddr, "HTTP"),
- }
- )
-
- // returns byte versions of address and private key
- // type [64]byte needed by account.GenPrivAccountFromKey
- func initUserBytes() ([]byte, [64]byte) {
- byteAddr, _ := hex.DecodeString(userAddr)
- var byteKey [64]byte
- userPrivByteSlice, _ := hex.DecodeString(userPriv)
- copy(byteKey[:], userPrivByteSlice)
- return byteAddr, byteKey
- }
-
- func decodeHex(hexStr string) []byte {
- bytes, err := hex.DecodeString(hexStr)
- if err != nil {
- panic(err)
- }
- return bytes
- }
-
- // create a new node and sleep forever
- func newNode(ready chan struct{}) {
- // Create & start node
- node = nm.NewNode()
- l := p2p.NewDefaultListener("tcp", config.App().GetString("ListenAddr"), false)
- node.AddListener(l)
- node.Start()
-
- // Run the RPC server.
- node.StartRPC()
- ready <- struct{}{}
-
- // Sleep forever
- ch := make(chan struct{})
- <-ch
- }
-
- // initialize config and create new node
- func init() {
- rootDir := ".tendermint"
- config.Init(rootDir)
- app := config.App()
- app.Set("SeedNode", "")
- app.Set("DB.Backend", "memdb")
- app.Set("RPC.HTTP.ListenAddr", rpcAddr)
- app.Set("GenesisFile", rootDir+"/genesis.json")
- app.Set("PrivValidatorFile", rootDir+"/priv_validator.json")
- app.Set("Log.Stdout.Level", "debug")
- config.SetApp(app)
- logger.Reset()
-
- // Save new priv_validator file.
- priv := &state.PrivValidator{
- Address: decodeHex(userAddr),
- PubKey: account.PubKeyEd25519(decodeHex(userPub)),
- PrivKey: account.PrivKeyEd25519(decodeHex(userPriv)),
- }
- priv.SetFile(rootDir + "/priv_validator.json")
- priv.Save()
-
- consensus.RoundDuration0 = 3 * time.Second
- consensus.RoundDurationDelta = 1 * time.Second
-
- // start a node
- ready := make(chan struct{})
- go newNode(ready)
- <-ready
- }
-
- //-------------------------------------------------------------------------------
- // make transactions
-
- // make a send tx (uses get account to figure out the nonce)
- func makeSendTx(t *testing.T, typ string, from, to []byte, amt uint64) *types.SendTx {
- acc := getAccount(t, typ, from)
- nonce := 0
- if acc != nil {
- nonce = int(acc.Sequence) + 1
- }
- bytePub, err := hex.DecodeString(userPub)
- if err != nil {
- t.Fatal(err)
- }
- tx := &types.SendTx{
- Inputs: []*types.TxInput{
- &types.TxInput{
- Address: from,
- Amount: amt,
- Sequence: uint(nonce),
- Signature: account.SignatureEd25519{},
- PubKey: account.PubKeyEd25519(bytePub),
- },
- },
- Outputs: []*types.TxOutput{
- &types.TxOutput{
- Address: to,
- Amount: amt,
- },
- },
- }
- return tx
- }
-
- // make a call tx (uses get account to figure out the nonce)
- func makeCallTx(t *testing.T, typ string, from, to, data []byte, amt, gaslim, fee uint64) *types.CallTx {
- acc := getAccount(t, typ, from)
- nonce := 0
- if acc != nil {
- nonce = int(acc.Sequence) + 1
- }
-
- bytePub, err := hex.DecodeString(userPub)
- if err != nil {
- t.Fatal(err)
- }
- tx := &types.CallTx{
- Input: &types.TxInput{
- Address: from,
- Amount: amt,
- Sequence: uint(nonce),
- Signature: account.SignatureEd25519{},
- PubKey: account.PubKeyEd25519(bytePub),
- },
- Address: to,
- GasLimit: gaslim,
- Fee: fee,
- Data: data,
- }
- return tx
- }
-
- // make transactions
- //-------------------------------------------------------------------------------
- // rpc call wrappers
-
- // get the account
- func getAccount(t *testing.T, typ string, addr []byte) *account.Account {
- client := clients[typ]
- ac, err := client.GetAccount(addr)
- if err != nil {
- t.Fatal(err)
- }
- return ac.Account
- }
-
- // make and sign transaction
- func signTx(t *testing.T, typ string, fromAddr, toAddr, data []byte, key [64]byte, amt, gaslim, fee uint64) (types.Tx, *account.PrivAccount) {
- var tx types.Tx
- if data == nil {
- tx = makeSendTx(t, typ, fromAddr, toAddr, amt)
- } else {
- tx = makeCallTx(t, typ, fromAddr, toAddr, data, amt, gaslim, fee)
- }
-
- privAcc := account.GenPrivAccountFromKey(key)
- if bytes.Compare(privAcc.PubKey.Address(), fromAddr) != 0 {
- t.Fatal("Failed to generate correct priv acc")
- }
-
- client := clients[typ]
- resp, err := client.SignTx(tx, []*account.PrivAccount{privAcc})
- if err != nil {
- t.Fatal(err)
- }
- return resp.Tx, privAcc
- }
-
- // create, sign, and broadcast a transaction
- func broadcastTx(t *testing.T, typ string, fromAddr, toAddr, data []byte, key [64]byte, amt, gaslim, fee uint64) (types.Tx, ctypes.Receipt) {
- tx, _ := signTx(t, typ, fromAddr, toAddr, data, key, amt, gaslim, fee)
- client := clients[typ]
- resp, err := client.BroadcastTx(tx)
- if err != nil {
- t.Fatal(err)
- }
- mempoolCount += 1
- return tx, resp.Receipt
- }
-
- // dump all storage for an account. currently unused
- func dumpStorage(t *testing.T, addr []byte) ctypes.ResponseDumpStorage {
- client := clients["HTTP"]
- resp, err := client.DumpStorage(addr)
- if err != nil {
- t.Fatal(err)
- }
- return *resp
- }
-
- func getStorage(t *testing.T, typ string, addr, key []byte) []byte {
- client := clients[typ]
- resp, err := client.GetStorage(addr, key)
- if err != nil {
- t.Fatal(err)
- }
- return resp.Value
- }
-
- func callCode(t *testing.T, client cclient.Client, code, data, expected []byte) {
- resp, err := client.CallCode(code, data)
- if err != nil {
- t.Fatal(err)
- }
- ret := resp.Return
- // NOTE: we don't flip memory when it comes out of RETURN (?!)
- if bytes.Compare(ret, LeftPadWord256(expected).Bytes()) != 0 {
- t.Fatalf("Conflicting return value. Got %x, expected %x", ret, expected)
- }
- }
-
- func callContract(t *testing.T, client cclient.Client, address, data, expected []byte) {
- resp, err := client.Call(address, data)
- if err != nil {
- t.Fatal(err)
- }
- ret := resp.Return
- // NOTE: we don't flip memory when it comes out of RETURN (?!)
- if bytes.Compare(ret, LeftPadWord256(expected).Bytes()) != 0 {
- t.Fatalf("Conflicting return value. Got %x, expected %x", ret, expected)
- }
- }
-
- //--------------------------------------------------------------------------------
- // utility verification function
-
- func checkTx(t *testing.T, fromAddr []byte, priv *account.PrivAccount, tx *types.SendTx) {
- if bytes.Compare(tx.Inputs[0].Address, fromAddr) != 0 {
- t.Fatal("Tx input addresses don't match!")
- }
-
- signBytes := account.SignBytes(tx)
- in := tx.Inputs[0] //(*types.SendTx).Inputs[0]
-
- if err := in.ValidateBasic(); err != nil {
- t.Fatal(err)
- }
- // Check signatures
- // acc := getAccount(t, byteAddr)
- // NOTE: using the acc here instead of the in fails; it is nil.
- if !in.PubKey.VerifyBytes(signBytes, in.Signature) {
- t.Fatal(types.ErrTxInvalidSignature)
- }
- }
-
- // simple contract returns 5 + 6 = 0xb
- func simpleContract() ([]byte, []byte, []byte) {
- // this is the code we want to run when the contract is called
- contractCode := []byte{0x60, 0x5, 0x60, 0x6, 0x1, 0x60, 0x0, 0x52, 0x60, 0x20, 0x60, 0x0, 0xf3}
- // the is the code we need to return the contractCode when the contract is initialized
- lenCode := len(contractCode)
- // push code to the stack
- //code := append([]byte{byte(0x60 + lenCode - 1)}, RightPadWord256(contractCode).Bytes()...)
- code := append([]byte{0x7f}, RightPadWord256(contractCode).Bytes()...)
- // store it in memory
- code = append(code, []byte{0x60, 0x0, 0x52}...)
- // return whats in memory
- //code = append(code, []byte{0x60, byte(32 - lenCode), 0x60, byte(lenCode), 0xf3}...)
- code = append(code, []byte{0x60, byte(lenCode), 0x60, 0x0, 0xf3}...)
- // return init code, contract code, expected return
- return code, contractCode, LeftPadBytes([]byte{0xb}, 32)
- }
-
- // simple call contract calls another contract
- func simpleCallContract(addr []byte) ([]byte, []byte, []byte) {
- gas1, gas2 := byte(0x1), byte(0x1)
- value := byte(0x1)
- inOff, inSize := byte(0x0), byte(0x0) // no call data
- retOff, retSize := byte(0x0), byte(0x20)
- // this is the code we want to run (call a contract and return)
- contractCode := []byte{0x60, retSize, 0x60, retOff, 0x60, inSize, 0x60, inOff, 0x60, value, 0x73}
- contractCode = append(contractCode, addr...)
- contractCode = append(contractCode, []byte{0x61, gas1, gas2, 0xf1, 0x60, 0x20, 0x60, 0x0, 0xf3}...)
-
- // the is the code we need to return; the contractCode when the contract is initialized
- // it should copy the code from the input into memory
- lenCode := len(contractCode)
- memOff := byte(0x0)
- inOff = byte(0xc) // length of code before codeContract
- length := byte(lenCode)
-
- code := []byte{0x60, length, 0x60, inOff, 0x60, memOff, 0x37}
- // return whats in memory
- code = append(code, []byte{0x60, byte(lenCode), 0x60, 0x0, 0xf3}...)
- code = append(code, contractCode...)
- // return init code, contract code, expected return
- return code, contractCode, LeftPadBytes([]byte{0xb}, 32)
- }
|