|
package rpctest
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
. "github.com/tendermint/tendermint/common"
|
|
"github.com/tendermint/tendermint/types"
|
|
"testing"
|
|
)
|
|
|
|
var doNothing = func(eid string, b []byte) error { return nil }
|
|
|
|
func testStatus(t *testing.T, typ string) {
|
|
client := clients[typ]
|
|
resp, err := client.Status()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if resp.NodeInfo.ChainID != chainID {
|
|
t.Fatal(fmt.Errorf("ChainID mismatch: got %s expected %s",
|
|
resp.NodeInfo.ChainID, chainID))
|
|
}
|
|
}
|
|
|
|
func testGenPriv(t *testing.T, typ string) {
|
|
client := clients[typ]
|
|
privAcc, err := client.GenPrivAccount()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(privAcc.Address) == 0 {
|
|
t.Fatal("Failed to generate an address")
|
|
}
|
|
}
|
|
|
|
func testGetAccount(t *testing.T, typ string) {
|
|
acc := getAccount(t, typ, user[0].Address)
|
|
if acc == nil {
|
|
t.Fatalf("Account was nil")
|
|
}
|
|
if bytes.Compare(acc.Address, user[0].Address) != 0 {
|
|
t.Fatalf("Failed to get correct account. Got %x, expected %x", acc.Address, user[0].Address)
|
|
}
|
|
}
|
|
|
|
func testSignedTx(t *testing.T, typ string) {
|
|
amt := int64(100)
|
|
toAddr := user[1].Address
|
|
testOneSignTx(t, typ, toAddr, amt)
|
|
|
|
toAddr = user[2].Address
|
|
testOneSignTx(t, typ, toAddr, amt)
|
|
|
|
toAddr = user[3].Address
|
|
testOneSignTx(t, typ, toAddr, amt)
|
|
}
|
|
|
|
func testOneSignTx(t *testing.T, typ string, addr []byte, amt int64) {
|
|
tx := makeDefaultSendTx(t, typ, addr, amt)
|
|
tx2 := signTx(t, typ, tx, user[0])
|
|
tx2hash := types.TxID(chainID, tx2)
|
|
tx.SignInput(chainID, 0, user[0])
|
|
txhash := types.TxID(chainID, tx)
|
|
if bytes.Compare(txhash, tx2hash) != 0 {
|
|
t.Fatal("Got different signatures for signing via rpc vs tx_utils")
|
|
}
|
|
|
|
tx_ := signTx(t, typ, tx, user[0])
|
|
tx = tx_.(*types.SendTx)
|
|
checkTx(t, user[0].Address, user[0], tx)
|
|
}
|
|
|
|
func testBroadcastTx(t *testing.T, typ string) {
|
|
amt := int64(100)
|
|
toAddr := user[1].Address
|
|
tx := makeDefaultSendTxSigned(t, typ, toAddr, amt)
|
|
receipt := broadcastTx(t, typ, tx)
|
|
if receipt.CreatesContract > 0 {
|
|
t.Fatal("This tx does not create a contract")
|
|
}
|
|
if len(receipt.TxHash) == 0 {
|
|
t.Fatal("Failed to compute tx hash")
|
|
}
|
|
pool := node.MempoolReactor().Mempool
|
|
txs := pool.GetProposalTxs()
|
|
if len(txs) != mempoolCount {
|
|
t.Fatalf("The mem pool has %d txs. Expected %d", len(txs), mempoolCount)
|
|
}
|
|
tx2 := txs[mempoolCount-1].(*types.SendTx)
|
|
n, err := new(int64), new(error)
|
|
buf1, buf2 := new(bytes.Buffer), new(bytes.Buffer)
|
|
tx.WriteSignBytes(chainID, buf1, n, err)
|
|
tx2.WriteSignBytes(chainID, buf2, n, err)
|
|
if bytes.Compare(buf1.Bytes(), buf2.Bytes()) != 0 {
|
|
t.Fatal("inconsistent hashes for mempool tx and sent tx")
|
|
}
|
|
}
|
|
|
|
func testGetStorage(t *testing.T, typ string) {
|
|
con := newWSCon(t)
|
|
eid := types.EventStringNewBlock()
|
|
subscribe(t, con, eid)
|
|
defer func() {
|
|
unsubscribe(t, con, eid)
|
|
con.Close()
|
|
}()
|
|
|
|
amt, gasLim, fee := int64(1100), int64(1000), int64(1000)
|
|
code := []byte{0x60, 0x5, 0x60, 0x1, 0x55}
|
|
tx := makeDefaultCallTx(t, typ, nil, code, amt, gasLim, fee)
|
|
receipt := broadcastTx(t, typ, tx)
|
|
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")
|
|
}
|
|
|
|
// allow it to get mined
|
|
waitForEvent(t, con, eid, true, func() {}, doNothing)
|
|
mempoolCount = 0
|
|
|
|
v := getStorage(t, typ, contractAddr, []byte{0x1})
|
|
got := LeftPadWord256(v)
|
|
expected := LeftPadWord256([]byte{0x5})
|
|
if got.Compare(expected) != 0 {
|
|
t.Fatalf("Wrong storage value. Got %x, expected %x", got.Bytes(), expected.Bytes())
|
|
}
|
|
}
|
|
|
|
func testCallCode(t *testing.T, typ string) {
|
|
client := clients[typ]
|
|
|
|
// add two integers and return the result
|
|
code := []byte{0x60, 0x5, 0x60, 0x6, 0x1, 0x60, 0x0, 0x52, 0x60, 0x20, 0x60, 0x0, 0xf3}
|
|
data := []byte{}
|
|
expected := []byte{0xb}
|
|
callCode(t, client, user[0].PubKey.Address(), code, data, expected)
|
|
|
|
// pass two ints as calldata, add, and return the result
|
|
code = []byte{0x60, 0x0, 0x35, 0x60, 0x20, 0x35, 0x1, 0x60, 0x0, 0x52, 0x60, 0x20, 0x60, 0x0, 0xf3}
|
|
data = append(LeftPadWord256([]byte{0x5}).Bytes(), LeftPadWord256([]byte{0x6}).Bytes()...)
|
|
expected = []byte{0xb}
|
|
callCode(t, client, user[0].PubKey.Address(), code, data, expected)
|
|
}
|
|
|
|
func testCall(t *testing.T, typ string) {
|
|
con := newWSCon(t)
|
|
eid := types.EventStringNewBlock()
|
|
subscribe(t, con, eid)
|
|
defer func() {
|
|
unsubscribe(t, con, eid)
|
|
con.Close()
|
|
}()
|
|
|
|
client := clients[typ]
|
|
|
|
// create the contract
|
|
amt, gasLim, fee := int64(6969), int64(1000), int64(1000)
|
|
code, _, _ := simpleContract()
|
|
tx := makeDefaultCallTx(t, typ, nil, code, amt, gasLim, fee)
|
|
receipt := broadcastTx(t, typ, tx)
|
|
|
|
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")
|
|
}
|
|
|
|
// allow it to get mined
|
|
waitForEvent(t, con, eid, true, func() {}, doNothing)
|
|
mempoolCount = 0
|
|
|
|
// run a call through the contract
|
|
data := []byte{}
|
|
expected := []byte{0xb}
|
|
callContract(t, client, user[0].PubKey.Address(), contractAddr, data, expected)
|
|
}
|
|
|
|
func testNameReg(t *testing.T, typ string) {
|
|
client := clients[typ]
|
|
con := newWSCon(t)
|
|
|
|
types.MinNameRegistrationPeriod = 1
|
|
|
|
// register a new name, check if its there
|
|
// since entries ought to be unique and these run against different clients, we append the typ
|
|
name := "ye_old_domain_name_" + typ
|
|
data := "if not now, when"
|
|
fee := int64(1000)
|
|
numDesiredBlocks := int64(2)
|
|
amt := fee + numDesiredBlocks*types.NameCostPerByte*types.NameCostPerBlock*types.BaseEntryCost(name, data)
|
|
|
|
eid := types.EventStringNameReg(name)
|
|
subscribe(t, con, eid)
|
|
|
|
tx := makeDefaultNameTx(t, typ, name, data, amt, fee)
|
|
broadcastTx(t, typ, tx)
|
|
// verify the name by both using the event and by checking get_name
|
|
waitForEvent(t, con, eid, true, func() {}, func(eid string, b []byte) error {
|
|
// TODO: unmarshal the response
|
|
tx, err := unmarshalResponseNameReg(b)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if tx.Name != name {
|
|
t.Fatal(fmt.Sprintf("Err on received event tx.Name: Got %s, expected %s", tx.Name, name))
|
|
}
|
|
if tx.Data != data {
|
|
t.Fatal(fmt.Sprintf("Err on received event tx.Data: Got %s, expected %s", tx.Data, data))
|
|
}
|
|
return nil
|
|
})
|
|
mempoolCount = 0
|
|
entry := getNameRegEntry(t, typ, name)
|
|
if entry.Data != data {
|
|
t.Fatal(fmt.Sprintf("Err on entry.Data: Got %s, expected %s", entry.Data, data))
|
|
}
|
|
if bytes.Compare(entry.Owner, user[0].Address) != 0 {
|
|
t.Fatal(fmt.Sprintf("Err on entry.Owner: Got %s, expected %s", entry.Owner, user[0].Address))
|
|
}
|
|
|
|
unsubscribe(t, con, eid)
|
|
|
|
// for the rest we just use new block event
|
|
// since we already tested the namereg event
|
|
eid = types.EventStringNewBlock()
|
|
subscribe(t, con, eid)
|
|
defer func() {
|
|
unsubscribe(t, con, eid)
|
|
con.Close()
|
|
}()
|
|
|
|
// update the data as the owner, make sure still there
|
|
numDesiredBlocks = int64(2)
|
|
data = "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"
|
|
amt = fee + numDesiredBlocks*types.NameCostPerByte*types.NameCostPerBlock*types.BaseEntryCost(name, data)
|
|
tx = makeDefaultNameTx(t, typ, name, data, amt, fee)
|
|
broadcastTx(t, typ, tx)
|
|
// commit block
|
|
waitForEvent(t, con, eid, true, func() {}, doNothing)
|
|
mempoolCount = 0
|
|
entry = getNameRegEntry(t, typ, name)
|
|
if entry.Data != data {
|
|
t.Fatal(fmt.Sprintf("Err on entry.Data: Got %s, expected %s", entry.Data, data))
|
|
}
|
|
|
|
// try to update as non owner, should fail
|
|
nonce := getNonce(t, typ, user[1].Address)
|
|
data2 := "this is not my beautiful house"
|
|
tx = types.NewNameTxWithNonce(user[1].PubKey, name, data2, amt, fee, nonce+1)
|
|
tx.Sign(chainID, user[1])
|
|
_, err := client.BroadcastTx(tx)
|
|
if err == nil {
|
|
t.Fatal("Expected error on NameTx")
|
|
}
|
|
|
|
// commit block
|
|
waitForEvent(t, con, eid, true, func() {}, doNothing)
|
|
|
|
// now the entry should be expired, so we can update as non owner
|
|
_, err = client.BroadcastTx(tx)
|
|
waitForEvent(t, con, eid, true, func() {}, doNothing)
|
|
mempoolCount = 0
|
|
entry = getNameRegEntry(t, typ, name)
|
|
if entry.Data != data2 {
|
|
t.Fatal(fmt.Sprintf("Error on entry.Data: Got %s, expected %s", entry.Data, data2))
|
|
}
|
|
if bytes.Compare(entry.Owner, user[1].Address) != 0 {
|
|
t.Fatal(fmt.Sprintf("Err on entry.Owner: Got %s, expected %s", entry.Owner, user[1].Address))
|
|
}
|
|
}
|