Browse Source

rpc: GetStorage and Call methods. Tests.

pull/43/merge
Ethan Buchman 10 years ago
parent
commit
dd1181f0d4
9 changed files with 229 additions and 42 deletions
  1. +25
    -0
      rpc/core/accounts.go
  2. +1
    -1
      rpc/core/mempool.go
  3. +5
    -0
      rpc/core/pipe.go
  4. +11
    -0
      rpc/core/responses.go
  5. +45
    -0
      rpc/core/txs.go
  6. +2
    -0
      rpc/handlers.go
  7. +43
    -28
      rpc/test/http_rpc_test.go
  8. +8
    -8
      rpc/test/json_rpc_test.go
  9. +89
    -5
      rpc/test/test.go

+ 25
- 0
rpc/core/accounts.go View File

@ -3,6 +3,7 @@ package core
import (
"fmt"
"github.com/tendermint/tendermint2/account"
. "github.com/tendermint/tendermint2/common"
)
func GenPrivAccount() (*ResponseGenPrivAccount, error) {
@ -14,6 +15,22 @@ func GetAccount(addr []byte) (*ResponseGetAccount, error) {
return &ResponseGetAccount{cache.GetAccount(addr)}, nil
}
func GetStorage(address, slot []byte) (*ResponseGetStorage, error) {
state := consensusState.GetState()
account := state.GetAccount(address)
if account == nil {
return nil, fmt.Errorf("Unknown address: %X", address)
}
storageRoot := account.StorageRoot
storage := state.LoadStorage(storageRoot)
_, value := storage.Get(RightPadWord256(slot).Bytes())
if value == nil {
return &ResponseGetStorage{slot, nil}, nil
}
return &ResponseGetStorage{slot, value.([]byte)}, nil
}
func ListAccounts() (*ResponseListAccounts, error) {
var blockHeight uint
var accounts []*account.Account
@ -26,6 +43,14 @@ func ListAccounts() (*ResponseListAccounts, error) {
return &ResponseListAccounts{blockHeight, accounts}, nil
}
func GetStorage(address, storage []byte) (*ResponseGetStorage, error) {
cache := mempoolReactor.Mempool.GetCache()
addr, slot := RightPadWord256(address), RightPadWord256(storage)
value := cache.GetStorage(addr, slot)
fmt.Printf("STORAGE: %x, %x, %x\n", addr, slot, value)
return &ResponseGetStorage{storage, value.Bytes()}, nil
}
func DumpStorage(addr []byte) (*ResponseDumpStorage, error) {
state := consensusState.GetState()
account := state.GetAccount(addr)


+ 1
- 1
rpc/core/mempool.go View File

@ -28,7 +28,7 @@ func BroadcastTx(tx types.Tx) (*ResponseBroadcastTx, error) {
var contractAddr []byte
// check if creates new contract
if callTx, ok := tx.(*types.CallTx); ok {
if callTx.Address == nil {
if len(callTx.Address) == 0 {
createsContract = 1
contractAddr = state.NewContractAddress(callTx.Input.Address, uint64(callTx.Input.Sequence))
}


+ 5
- 0
rpc/core/pipe.go View File

@ -5,6 +5,7 @@ import (
"github.com/tendermint/tendermint2/consensus"
mempl "github.com/tendermint/tendermint2/mempool"
"github.com/tendermint/tendermint2/p2p"
"github.com/tendermint/tendermint2/state"
)
var blockStore *bc.BlockStore
@ -27,3 +28,7 @@ func SetMempoolReactor(mr *mempl.MempoolReactor) {
func SetSwitch(sw *p2p.Switch) {
p2pSwitch = sw
}
func SetPrivValidator(priv *state.PrivValidator) {
consensusState.SetPrivValidator(priv)
}

+ 11
- 0
rpc/core/responses.go View File

@ -14,6 +14,17 @@ type ResponseGetAccount struct {
Account *account.Account
}
type ResponseGetStorage struct {
Key []byte
Value []byte
}
type ResponseCall struct {
Return []byte
GasUsed uint64
// TODO ...
}
type ResponseListAccounts struct {
BlockHeight uint
Accounts []*account.Account


+ 45
- 0
rpc/core/txs.go View File

@ -3,9 +3,54 @@ package core
import (
"fmt"
"github.com/tendermint/tendermint2/account"
. "github.com/tendermint/tendermint2/common"
"github.com/tendermint/tendermint2/state"
"github.com/tendermint/tendermint2/types"
"github.com/tendermint/tendermint2/vm"
)
func toVMAccount(acc *account.Account) *vm.Account {
return &vm.Account{
Address: RightPadWord256(acc.Address),
Balance: acc.Balance,
Code: acc.Code, // This is crazy.
Nonce: uint64(acc.Sequence),
StorageRoot: RightPadWord256(acc.StorageRoot),
Other: acc.PubKey,
}
}
//-----------------------------------------------------------------------------
// Run a contract's code on an isolated and unpersisted state
// Cannot be used to create new contracts
func Call(address, data []byte) (*ResponseCall, error) {
st := consensusState.GetState() // performs a copy
cache := mempoolReactor.Mempool.GetCache()
outAcc := cache.GetAccount(address)
if outAcc == nil {
return nil, fmt.Errorf("Account %x does not exist", address)
}
callee := toVMAccount(outAcc)
caller := &vm.Account{Address: Zero256}
txCache := state.NewTxCache(cache)
params := vm.Params{
BlockHeight: uint64(st.LastBlockHeight),
BlockHash: RightPadWord256(st.LastBlockHash),
BlockTime: st.LastBlockTime.Unix(),
GasLimit: 10000000,
}
vmach := vm.NewVM(txCache, params, caller.Address)
gas := uint64(1000000000)
ret, err := vmach.Call(caller, callee, callee.Code, data, 0, &gas)
if err != nil {
return nil, err
}
return &ResponseCall{Return: ret}, nil
}
//-----------------------------------------------------------------------------
func SignTx(tx types.Tx, privAccounts []*account.PrivAccount) (*ResponseSignTx, error) {


+ 2
- 0
rpc/handlers.go View File

@ -22,6 +22,8 @@ var funcMap = map[string]*FuncWrapper{
"blockchain": funcWrap(core.BlockchainInfo, []string{"min_height", "max_height"}),
"get_block": funcWrap(core.GetBlock, []string{"height"}),
"get_account": funcWrap(core.GetAccount, []string{"address"}),
"get_storage": funcWrap(core.GetStorage, []string{"address", "storage"}),
"call": funcWrap(core.Call, []string{"address", "data"}),
"list_validators": funcWrap(core.ListValidators, []string{}),
"dump_storage": funcWrap(core.DumpStorage, []string{"address"}),
"broadcast_tx": funcWrap(core.BroadcastTx, []string{"tx"}),


+ 43
- 28
rpc/test/http_rpc_test.go View File

@ -6,14 +6,16 @@ import (
"encoding/json"
"fmt"
"github.com/tendermint/tendermint2/binary"
. "github.com/tendermint/tendermint2/common"
"github.com/tendermint/tendermint2/config"
"github.com/tendermint/tendermint2/merkle"
"github.com/tendermint/tendermint2/rpc/core"
"github.com/tendermint/tendermint2/state"
"github.com/tendermint/tendermint2/types"
"io/ioutil"
"net/http"
"net/url"
"testing"
"time"
)
func TestHTTPStatus(t *testing.T) {
@ -88,16 +90,16 @@ func TestHTTPSignedTx(t *testing.T) {
amt := uint64(100)
toAddr := []byte{20, 143, 25, 63, 16, 177, 83, 29, 91, 91, 54, 23, 233, 46, 190, 121, 122, 34, 86, 54}
tx, priv := signTx(t, "HTTP", byteAddr, toAddr, byteKey, amt)
checkTx(t, byteAddr, priv, tx)
tx, priv := signTx(t, "HTTP", byteAddr, toAddr, nil, byteKey, amt, 0, 0)
checkTx(t, byteAddr, priv, tx.(*types.SendTx))
toAddr = []byte{20, 143, 24, 63, 16, 17, 83, 29, 90, 91, 52, 2, 0, 41, 190, 121, 122, 34, 86, 54}
tx, priv = signTx(t, "HTTP", byteAddr, toAddr, byteKey, amt)
checkTx(t, byteAddr, priv, tx)
tx, priv = signTx(t, "HTTP", byteAddr, toAddr, nil, byteKey, amt, 0, 0)
checkTx(t, byteAddr, priv, tx.(*types.SendTx))
toAddr = []byte{0, 0, 4, 0, 0, 4, 0, 0, 4, 91, 52, 2, 0, 41, 190, 121, 122, 34, 86, 54}
tx, priv = signTx(t, "HTTP", byteAddr, toAddr, byteKey, amt)
checkTx(t, byteAddr, priv, tx)
tx, priv = signTx(t, "HTTP", byteAddr, toAddr, nil, byteKey, amt, 0, 0)
checkTx(t, byteAddr, priv, tx.(*types.SendTx))
}
func TestHTTPBroadcastTx(t *testing.T) {
@ -108,27 +110,7 @@ func TestHTTPBroadcastTx(t *testing.T) {
amt := uint64(100)
toAddr := []byte{20, 143, 25, 63, 16, 177, 83, 29, 91, 91, 54, 23, 233, 46, 190, 121, 122, 34, 86, 54}
tx, priv := signTx(t, "HTTP", byteAddr, toAddr, byteKey, amt)
checkTx(t, byteAddr, priv, tx)
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 status struct {
Status string
Data core.ResponseBroadcastTx
Error string
}
requestResponse(t, "broadcast_tx", url.Values{"tx": {string(b)}}, &status)
if status.Status == "ERROR" {
t.Fatal(status.Error)
}
receipt := status.Data.Receipt
tx, receipt := broadcastTx(t, "HTTP", byteAddr, toAddr, nil, byteKey, amt, 0, 0)
if receipt.CreatesContract > 0 {
t.Fatal("This tx does not create a contract")
}
@ -148,6 +130,39 @@ func TestHTTPBroadcastTx(t *testing.T) {
}
func TestHTTPGetStorage(t *testing.T) {
priv := state.LoadPrivValidator(".tendermint/priv_validator.json")
_ = priv
//core.SetPrivValidator(priv)
byteAddr, _ := hex.DecodeString(userAddr)
var byteKey [64]byte
oh, _ := hex.DecodeString(userPriv)
copy(byteKey[:], oh)
amt := uint64(1100)
code := []byte{0x60, 0x5, 0x60, 0x1, 0x55}
_, receipt := broadcastTx(t, "HTTP", byteAddr, nil, code, byteKey, amt, 1000, 1000)
if receipt.CreatesContract == 0 {
t.Fatal("This tx creates a contract")
}
if len(receipt.TxHash) == 0 {
t.Fatal("Failed to compute tx hash")
}
contractAddr := receipt.ContractAddr
if len(contractAddr) == 0 {
t.Fatal("Creates contract but resulting address is empty")
}
time.Sleep(time.Second * 20)
v := getStorage(t, contractAddr, []byte{0x1})
got := RightPadWord256(v)
expected := RightPadWord256([]byte{0x5})
if got.Compare(expected) != 0 {
t.Fatalf("Wrong storage value. Got %x, expected %x", got.Bytes(), expected.Bytes())
}
}
/*tx.Inputs[0].Signature = mint.priv.PrivKey.Sign(account.SignBytes(tx))
err = mint.MempoolReactor.BroadcastTx(tx)
return hex.EncodeToString(merkle.HashFromBinary(tx)), err*/

+ 8
- 8
rpc/test/json_rpc_test.go View File

@ -107,16 +107,16 @@ func TestJSONSignedTx(t *testing.T) {
amt := uint64(100)
toAddr := []byte{20, 143, 25, 63, 16, 177, 83, 29, 91, 91, 54, 23, 233, 46, 190, 121, 122, 34, 86, 54}
tx, priv := signTx(t, "JSONRPC", byteAddr, toAddr, byteKey, amt)
checkTx(t, byteAddr, priv, tx)
tx, priv := signTx(t, "JSONRPC", byteAddr, toAddr, nil, byteKey, amt, 0, 0)
checkTx(t, byteAddr, priv, tx.(*types.SendTx))
toAddr = []byte{20, 143, 24, 63, 16, 17, 83, 29, 90, 91, 52, 2, 0, 41, 190, 121, 122, 34, 86, 54}
tx, priv = signTx(t, "JSONRPC", byteAddr, toAddr, byteKey, amt)
checkTx(t, byteAddr, priv, tx)
tx, priv = signTx(t, "JSONRPC", byteAddr, toAddr, nil, byteKey, amt, 0, 0)
checkTx(t, byteAddr, priv, tx.(*types.SendTx))
toAddr = []byte{0, 0, 4, 0, 0, 4, 0, 0, 4, 91, 52, 2, 0, 41, 190, 121, 122, 34, 86, 54}
tx, priv = signTx(t, "JSONRPC", byteAddr, toAddr, byteKey, amt)
checkTx(t, byteAddr, priv, tx)
tx, priv = signTx(t, "JSONRPC", byteAddr, toAddr, nil, byteKey, amt, 0, 0)
checkTx(t, byteAddr, priv, tx.(*types.SendTx))
}
func TestJSONBroadcastTx(t *testing.T) {
@ -127,8 +127,8 @@ func TestJSONBroadcastTx(t *testing.T) {
amt := uint64(100)
toAddr := []byte{20, 143, 25, 63, 16, 177, 83, 29, 91, 91, 54, 23, 233, 46, 190, 121, 122, 34, 86, 54}
tx, priv := signTx(t, "JSONRPC", byteAddr, toAddr, byteKey, amt)
checkTx(t, byteAddr, priv, tx)
tx, priv := signTx(t, "JSONRPC", byteAddr, toAddr, nil, byteKey, amt, 0, 0)
checkTx(t, byteAddr, priv, tx.(*types.SendTx))
n, w := new(int64), new(bytes.Buffer)
var err error


+ 89
- 5
rpc/test/test.go View File

@ -108,7 +108,7 @@ func getAccount(t *testing.T, typ string, addr []byte) *account.Account {
return status.Data.Account
}
func makeTx(t *testing.T, typ string, from, to []byte, amt uint64) *types.SendTx {
func makeSendTx(t *testing.T, typ string, from, to []byte, amt uint64) *types.SendTx {
acc := getAccount(t, typ, from)
nonce := 0
if acc != nil {
@ -138,6 +138,33 @@ func makeTx(t *testing.T, typ string, from, to []byte, amt uint64) *types.SendTx
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, status interface{}) {
resp, err := http.PostForm(requestAddr+method, values)
if err != nil {
@ -154,8 +181,13 @@ func requestResponse(t *testing.T, method string, values url.Values, status inte
}
}
func signTx(t *testing.T, typ string, fromAddr, toAddr []byte, key [64]byte, amt uint64) (*types.SendTx, *account.PrivAccount) {
tx := makeTx(t, typ, fromAddr, toAddr, amt)
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
@ -185,8 +217,60 @@ func signTx(t *testing.T, typ string, fromAddr, toAddr []byte, key [64]byte, amt
t.Fatal(status.Error)
}
response := status.Data
tx = response.Tx.(*types.SendTx)
return tx, privAcc
//tx = response.Tx.(*types.SendTx)
return response.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 status struct {
Status string
Data core.ResponseBroadcastTx
Error string
}
requestResponse(t, "broadcast_tx", url.Values{"tx": {string(b)}}, &status)
if status.Status == "ERROR" {
t.Fatal(status.Error)
}
return tx, status.Data.Receipt
}
func dumpStorage(t *testing.T, addr []byte) core.ResponseDumpStorage {
addrString := "\"" + hex.EncodeToString(addr) + "\""
var status struct {
Status string
Data core.ResponseDumpStorage
Error string
}
requestResponse(t, "dump_storage", url.Values{"address": {addrString}}, &status)
if status.Status != "OK" {
t.Fatal(status.Error)
}
return status.Data
}
func getStorage(t *testing.T, addr, slot []byte) []byte {
addrString := "\"" + hex.EncodeToString(addr) + "\""
slotString := "\"" + hex.EncodeToString(slot) + "\""
var status struct {
Status string
Data core.ResponseGetStorage
Error string
}
requestResponse(t, "get_storage", url.Values{"address": {addrString}, "storage": {slotString}}, &status)
if status.Status != "OK" {
t.Fatal(status.Error)
}
return status.Data.Value
}
func checkTx(t *testing.T, fromAddr []byte, priv *account.PrivAccount, tx *types.SendTx) {


Loading…
Cancel
Save