rpc: GetStorage and Call methods. Tests.
This commit is contained in:
parent
6f0199aadf
commit
c1b06d8101
|
@ -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
|
||||
|
|
|
@ -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,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)
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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"}),
|
||||
|
|
|
@ -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*/
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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…
Reference in New Issue