namereg rpc and tests

This commit is contained in:
Ethan Buchman
2015-05-22 17:03:22 -04:00
parent 8631d5085e
commit baaa69d7f8
9 changed files with 173 additions and 2 deletions

17
rpc/core/names.go Normal file
View File

@ -0,0 +1,17 @@
package core
import (
"fmt"
ctypes "github.com/tendermint/tendermint/rpc/core/types"
)
// XXX: need we be careful about rendering bytes as string or is that their problem ?
func NameRegEntry(name []byte) (*ctypes.ResponseNameRegEntry, error) {
st := consensusState.GetState() // performs a copy
entry := st.GetNameRegEntry(name)
if entry == nil {
return nil, fmt.Errorf("Name %s not found", name)
}
return &ctypes.ResponseNameRegEntry{entry}, nil
}

View File

@ -20,6 +20,7 @@ var Routes = map[string]*rpc.RPCFunc{
"broadcast_tx": rpc.NewRPCFunc(BroadcastTx, []string{"tx"}),
"list_unconfirmed_txs": rpc.NewRPCFunc(ListUnconfirmedTxs, []string{}),
"list_accounts": rpc.NewRPCFunc(ListAccounts, []string{}),
"name_reg_entry": rpc.NewRPCFunc(NameRegEntry, []string{"name"}),
"unsafe/gen_priv_account": rpc.NewRPCFunc(GenPrivAccount, []string{}),
"unsafe/sign_tx": rpc.NewRPCFunc(SignTx, []string{"tx", "privAccounts"}),
}

View File

@ -100,3 +100,7 @@ type ResponseDumpConsensusState struct {
RoundState string `json:"round_state"`
PeerRoundStates []string `json:"peer_round_states"`
}
type ResponseNameRegEntry struct {
Entry *types.NameRegEntry `json:"entry"`
}

View File

@ -5,8 +5,6 @@ import (
"fmt"
"github.com/tendermint/tendermint/binary"
rpctypes "github.com/tendermint/tendermint/rpc/types"
// NOTE: do not import rpc/core.
// What kind of client imports all of core logic? :P
"io/ioutil"
"net/http"
"net/url"
@ -30,6 +28,7 @@ var reverseFuncMap = map[string]string{
"DumpStorage": "dump_storage",
"BroadcastTx": "broadcast_tx",
"ListAccounts": "list_accounts",
"NameRegEntry": "name_reg_entry",
"GenPrivAccount": "unsafe/gen_priv_account",
"SignTx": "unsafe/sign_tx",
}

View File

@ -28,6 +28,7 @@ type Client interface {
ListAccounts() (*ctypes.ResponseListAccounts, error)
ListUnconfirmedTxs() (*ctypes.ResponseListUnconfirmedTxs, error)
ListValidators() (*ctypes.ResponseListValidators, error)
NameRegEntry(name []byte) (*ctypes.ResponseNameRegEntry, error)
NetInfo() (*ctypes.ResponseNetInfo, error)
SignTx(tx types.Tx, privAccounts []*account.PrivAccount) (*ctypes.ResponseSignTx, error)
Status() (*ctypes.ResponseStatus, error)
@ -453,6 +454,36 @@ func (c *ClientHTTP) ListValidators() (*ctypes.ResponseListValidators, error) {
return response.Result, nil
}
func (c *ClientHTTP) NameRegEntry(name []byte) (*ctypes.ResponseNameRegEntry, error) {
values, err := argsToURLValues([]string{"name"}, name)
if err != nil {
return nil, err
}
resp, err := http.PostForm(c.addr+reverseFuncMap["NameRegEntry"], values)
if err != nil {
return nil, err
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, err
}
var response struct {
Result *ctypes.ResponseNameRegEntry `json:"result"`
Error string `json:"error"`
Id string `json:"id"`
JSONRPC string `json:"jsonrpc"`
}
binary.ReadJSON(&response, body, &err)
if err != nil {
return nil, err
}
if response.Error != "" {
return nil, fmt.Errorf(response.Error)
}
return response.Result, nil
}
func (c *ClientHTTP) NetInfo() (*ctypes.ResponseNetInfo, error) {
values, err := argsToURLValues(nil)
if err != nil {
@ -921,6 +952,33 @@ func (c *ClientJSON) ListValidators() (*ctypes.ResponseListValidators, error) {
return response.Result, nil
}
func (c *ClientJSON) NameRegEntry(name []byte) (*ctypes.ResponseNameRegEntry, error) {
request := rpctypes.RPCRequest{
JSONRPC: "2.0",
Method: reverseFuncMap["NameRegEntry"],
Params: []interface{}{name},
Id: 0,
}
body, err := c.RequestResponse(request)
if err != nil {
return nil, err
}
var response struct {
Result *ctypes.ResponseNameRegEntry `json:"result"`
Error string `json:"error"`
Id string `json:"id"`
JSONRPC string `json:"jsonrpc"`
}
binary.ReadJSON(&response, body, &err)
if err != nil {
return nil, err
}
if response.Error != "" {
return nil, fmt.Errorf(response.Error)
}
return response.Result, nil
}
func (c *ClientJSON) NetInfo() (*ctypes.ResponseNetInfo, error) {
request := rpctypes.RPCRequest{
JSONRPC: "2.0",

View File

@ -40,6 +40,10 @@ func TestHTTPCallContract(t *testing.T) {
testCall(t, "HTTP")
}
func TestHTTPNameReg(t *testing.T) {
testNameReg(t, "HTTP")
}
//--------------------------------------------------------------------------------
// Test the JSONRPC client
@ -74,3 +78,7 @@ func TestJSONCallCode(t *testing.T) {
func TestJSONCallContract(t *testing.T) {
testCall(t, "JSONRPC")
}
func TestJSONNameReg(t *testing.T) {
testNameReg(t, "JSONRPC")
}

View File

@ -120,6 +120,13 @@ func makeDefaultCallTx(t *testing.T, typ string, addr, code []byte, amt, gasLim,
return tx
}
func makeDefaultNameTx(t *testing.T, typ string, name, value []byte, amt, fee uint64) *types.NameTx {
nonce := getNonce(t, typ, user[0].Address)
tx := types.NewNameTxWithNonce(user[0].PubKey, name, value, amt, fee, nonce)
tx.Sign(user[0])
return tx
}
//-------------------------------------------------------------------------------
// rpc call wrappers (fail on err)
@ -210,6 +217,16 @@ func callContract(t *testing.T, client cclient.Client, address, data, expected [
}
}
// get the namereg entry
func getNameRegEntry(t *testing.T, typ string, name []byte) *types.NameRegEntry {
client := clients[typ]
r, err := client.NameRegEntry(name)
if err != nil {
t.Fatal(err)
}
return r.Entry
}
//--------------------------------------------------------------------------------
// utility verification function

View File

@ -190,3 +190,33 @@ func testCall(t *testing.T, typ string) {
expected := []byte{0xb}
callContract(t, client, contractAddr, data, expected)
}
func testNameReg(t *testing.T, typ string) {
con := newWSCon(t)
eid := types.EventStringNewBlock()
subscribe(t, con, eid)
defer func() {
unsubscribe(t, con, eid)
con.Close()
}()
amt, fee := uint64(6969), uint64(1000)
// since entries ought to be unique and these run against different clients, we append the typ
name := []byte("ye-old-domain-name-" + typ)
data := []byte("these are amongst the things I wish to bestow upon the youth of generations come: a safe supply of honey, and a better money. For what else shall they need?")
tx := makeDefaultNameTx(t, typ, name, data, amt, fee)
broadcastTx(t, typ, tx)
// allow it to get mined
waitForEvent(t, con, eid, true, func() {
}, func(eid string, b []byte) error {
return nil
})
entry := getNameRegEntry(t, typ, name)
if bytes.Compare(entry.Data, data) != 0 {
t.Fatal(fmt.Sprintf("Got %s, expected %s", entry.Data, data))
}
}

View File

@ -103,6 +103,43 @@ func (tx *CallTx) Sign(chainID string, privAccount *account.PrivAccount) {
tx.Input.Signature = privAccount.Sign(chainID, tx)
}
//----------------------------------------------------------------------------
// NameTx interface for creating tx
func NewNameTx(st AccountGetter, from account.PubKey, name, data []byte, amt, fee uint64) (*NameTx, error) {
addr := from.Address()
acc := st.GetAccount(addr)
if acc == nil {
return nil, fmt.Errorf("Invalid address %X from pubkey %X", addr, from)
}
nonce := uint64(acc.Sequence)
return NewNameTxWithNonce(from, name, data, amt, fee, nonce), nil
}
func NewNameTxWithNonce(from account.PubKey, name, data []byte, amt, fee, nonce uint64) *NameTx {
addr := from.Address()
input := &TxInput{
Address: addr,
Amount: amt,
Sequence: uint(nonce) + 1,
Signature: account.SignatureEd25519{},
PubKey: from,
}
return &NameTx{
Input: input,
Name: name,
Data: data,
Fee: fee,
}
}
func (tx *NameTx) Sign(privAccount *account.PrivAccount) {
tx.Input.PubKey = privAccount.PubKey
tx.Input.Signature = privAccount.Sign(tx)
}
//----------------------------------------------------------------------------
// BondTx interface for adding inputs/outputs and adding signatures