package rpc import ( "bytes" "encoding/hex" "github.com/tendermint/tendermint/account" "github.com/tendermint/tendermint/binary" "github.com/tendermint/tendermint/config" "github.com/tendermint/tendermint/daemon" "github.com/tendermint/tendermint/logger" "github.com/tendermint/tendermint/p2p" "github.com/tendermint/tendermint/rpc" "github.com/tendermint/tendermint/rpc/core" "github.com/tendermint/tendermint/state" "github.com/tendermint/tendermint/types" "io/ioutil" "net/http" "net/url" "testing" ) var ( rpcAddr = "127.0.0.1:8089" requestAddr = "http://" + rpcAddr + "/" node *daemon.Node mempoolCount = 0 userAddr = "D7DFF9806078899C8DA3FE3633CC0BF3C6C2B1BB" userPriv = "FDE3BD94CB327D19464027BA668194C5EFA46AE83E8419D7542CFF41F00C81972239C21C81EA7173A6C489145490C015E05D4B97448933B708A7EC5B7B4921E3" userPub = "2239C21C81EA7173A6C489145490C015E05D4B97448933B708A7EC5B7B4921E3" ) func newNode(ready chan struct{}) { // Create & start node node = daemon.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 } 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() priv := state.LoadPrivValidator(rootDir + "/priv_validator.json") priv.LastHeight = 0 priv.LastRound = 0 priv.LastStep = 0 priv.Save() // start a node ready := make(chan struct{}) go newNode(ready) <-ready } func getAccount(t *testing.T, typ string, addr []byte) *account.Account { var client rpc.Client switch typ { case "JSONRPC": client = rpc.NewClient(requestAddr, "JSONRPC") case "HTTP": client = rpc.NewClient(requestAddr, "HTTP") } ac, err := client.GetAccount(addr) if err != nil { t.Fatal(err) } return ac.Account } /* func getAccount(t *testing.T, typ string, addr []byte) *account.Account { var resp *http.Response var err error switch typ { case "JSONRPC": s := rpc.JSONRPC{ JSONRPC: "2.0", Method: "get_account", Params: []interface{}{hex.EncodeToString(addr)}, Id: 0, } b, err := json.Marshal(s) if err != nil { t.Fatal(err) } buf := bytes.NewBuffer(b) resp, err = http.Post(requestAddr, "text/json", buf) case "HTTP": resp, err = http.PostForm(requestAddr+"get_account", url.Values{"address": {"\"" + (hex.EncodeToString(addr)) + "\""}}) } if err != nil { t.Fatal(err) } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) if err != nil { t.Fatal(err) } var response struct { Result core.ResponseGetAccount `json:"result"` Error string `json:"error"` Id string `json:"id"` JSONRPC string `json:"jsonrpc"` } binary.ReadJSON(&response, body, &err) if err != nil { t.Fatal(err) } return response.Result.Account }*/ 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 } 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 } func requestResponse(t *testing.T, method string, values url.Values, response interface{}) { resp, err := http.PostForm(requestAddr+method, values) if err != nil { t.Fatal(err) } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) if err != nil { t.Fatal(err) } binary.ReadJSON(response, body, &err) if err != nil { t.Fatal(err) } } 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) } n, w := new(int64), new(bytes.Buffer) var err error binary.WriteJSON(tx, w, n, &err) if err != nil { t.Fatal(err) } b := w.Bytes() privAcc := account.GenPrivAccountFromKey(key) if bytes.Compare(privAcc.PubKey.Address(), fromAddr) != 0 { t.Fatal("Faield to generate correct priv acc") } w = new(bytes.Buffer) binary.WriteJSON([]*account.PrivAccount{privAcc}, w, n, &err) if err != nil { t.Fatal(err) } var response struct { Result core.ResponseSignTx `json:"result"` Error string `json:"error"` Id string `json:"id"` JSONRPC string `json:"jsonrpc"` } requestResponse(t, "unsafe/sign_tx", url.Values{"tx": {string(b)}, "privAccounts": {string(w.Bytes())}}, &response) if response.Error != "" { t.Fatal(response.Error) } result := response.Result return result.Tx, privAcc } func broadcastTx(t *testing.T, typ string, fromAddr, toAddr, data []byte, key [64]byte, amt, gaslim, fee uint64) (types.Tx, core.Receipt) { tx, _ := signTx(t, typ, fromAddr, toAddr, data, key, amt, gaslim, fee) n, w := new(int64), new(bytes.Buffer) var err error binary.WriteJSON(tx, w, n, &err) if err != nil { t.Fatal(err) } b := w.Bytes() var response struct { Result core.ResponseBroadcastTx `json:"result"` Error string `json:"error"` Id string `json:"id"` JSONRPC string `json:"jsonrpc"` } requestResponse(t, "broadcast_tx", url.Values{"tx": {string(b)}}, &response) if response.Error != "" { t.Fatal(response.Error) } return tx, response.Result.Receipt } func dumpStorage(t *testing.T, addr []byte) core.ResponseDumpStorage { addrString := "\"" + hex.EncodeToString(addr) + "\"" var response struct { Result core.ResponseDumpStorage `json:"result"` Error string `json:"error"` Id string `json:"id"` JSONRPC string `json:"jsonrpc"` } requestResponse(t, "dump_storage", url.Values{"address": {addrString}}, &response) if response.Error != "" { t.Fatal(response.Error) } return response.Result } func getStorage(t *testing.T, addr, slot []byte) []byte { addrString := "\"" + hex.EncodeToString(addr) + "\"" slotString := "\"" + hex.EncodeToString(slot) + "\"" var response struct { Result core.ResponseGetStorage `json:"result"` Error string `json:"error"` Id string `json:"id"` JSONRPC string `json:"jsonrpc"` } requestResponse(t, "get_storage", url.Values{"address": {addrString}, "storage": {slotString}}, &response) if response.Error != "" { t.Fatal(response.Error) } return response.Result.Value } 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; its PubKeyNil ... ? if !in.PubKey.VerifyBytes(signBytes, in.Signature) { t.Fatal(types.ErrTxInvalidSignature) } }