mirror of
https://github.com/tendermint/tendermint.git
synced 2026-01-07 13:55:17 +00:00
fixes from review with jae
This commit is contained in:
@@ -6,6 +6,7 @@ import (
|
||||
"io"
|
||||
|
||||
"github.com/tendermint/tendermint/binary"
|
||||
"github.com/tendermint/tendermint/merkle"
|
||||
)
|
||||
|
||||
// Signable is an interface for all signable things.
|
||||
@@ -24,6 +25,11 @@ func SignBytes(o Signable) []byte {
|
||||
return buf.Bytes()
|
||||
}
|
||||
|
||||
// HashSignBytes is a convenience method for getting the hash of the bytes of a signable
|
||||
func HashSignBytes(o Signable) []byte {
|
||||
return merkle.HashFromBinary(SignBytes(o))
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// Account resides in the application state, and is mutated by transactions
|
||||
|
||||
@@ -445,6 +445,7 @@ ACTION_LOOP:
|
||||
// cs.Step is at RoundStepNewHeight or RoundStepNewRound.
|
||||
newBlock := cs.blockStore.LoadBlock(cs.state.LastBlockHeight)
|
||||
cs.evsw.FireEvent(types.EventStringNewBlock(), newBlock)
|
||||
// TODO: go fire events from event cache
|
||||
scheduleNextAction()
|
||||
continue ACTION_LOOP
|
||||
} else {
|
||||
|
||||
177
rpc/handlers.go
177
rpc/handlers.go
@@ -10,6 +10,7 @@ import (
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"reflect"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
)
|
||||
|
||||
@@ -25,8 +26,8 @@ func RegisterRPCFuncs(mux *http.ServeMux, funcMap map[string]*RPCFunc) {
|
||||
|
||||
func RegisterEventsHandler(mux *http.ServeMux, evsw *events.EventSwitch) {
|
||||
// websocket endpoint
|
||||
w := NewWebsocketManager(evsw)
|
||||
mux.HandleFunc("/events", w.websocketHandler) // websocket.Handler(w.eventsHandler))
|
||||
wm := NewWebsocketManager(evsw)
|
||||
mux.HandleFunc("/events", wm.websocketHandler) // websocket.Handler(w.eventsHandler))
|
||||
}
|
||||
|
||||
//-------------------------------------
|
||||
@@ -193,7 +194,7 @@ func _jsonStringToArg(ty reflect.Type, arg string) (reflect.Value, error) {
|
||||
|
||||
const (
|
||||
WSConnectionReaperSeconds = 5
|
||||
MaxFailedSendsSeconds = 10
|
||||
MaxFailedSends = 10
|
||||
WriteChanBufferSize = 10
|
||||
)
|
||||
|
||||
@@ -214,103 +215,76 @@ type WSResponse struct {
|
||||
// contains the listeners id
|
||||
type Connection struct {
|
||||
id string
|
||||
wsCon *websocket.Conn
|
||||
wsConn *websocket.Conn
|
||||
writeChan chan WSResponse
|
||||
quitChan chan struct{}
|
||||
failedSends uint
|
||||
started uint32
|
||||
stopped uint32
|
||||
|
||||
evsw *events.EventSwitch
|
||||
}
|
||||
|
||||
// new websocket connection wrapper
|
||||
func NewConnection(con *websocket.Conn) *Connection {
|
||||
func NewConnection(wsConn *websocket.Conn) *Connection {
|
||||
return &Connection{
|
||||
id: con.RemoteAddr().String(),
|
||||
wsCon: con,
|
||||
id: wsConn.RemoteAddr().String(),
|
||||
wsConn: wsConn,
|
||||
writeChan: make(chan WSResponse, WriteChanBufferSize), // buffered. we keep track when its full
|
||||
}
|
||||
}
|
||||
|
||||
// start the connection and hand her the event switch
|
||||
func (con *Connection) Start(evsw *events.EventSwitch) {
|
||||
if atomic.CompareAndSwapUint32(&con.started, 0, 1) {
|
||||
con.evsw = evsw
|
||||
|
||||
// read subscriptions/unsubscriptions to events
|
||||
go con.read()
|
||||
// write responses
|
||||
con.write()
|
||||
}
|
||||
}
|
||||
|
||||
// close the connection
|
||||
func (c *Connection) Close() {
|
||||
c.wsCon.Close()
|
||||
close(c.writeChan)
|
||||
close(c.quitChan)
|
||||
}
|
||||
|
||||
// main manager for all websocket connections
|
||||
// holds the event switch
|
||||
type WebsocketManager struct {
|
||||
websocket.Upgrader
|
||||
ew *events.EventSwitch
|
||||
cons map[string]*Connection
|
||||
}
|
||||
|
||||
func NewWebsocketManager(ew *events.EventSwitch) *WebsocketManager {
|
||||
return &WebsocketManager{
|
||||
ew: ew,
|
||||
cons: make(map[string]*Connection),
|
||||
Upgrader: websocket.Upgrader{
|
||||
ReadBufferSize: 1024,
|
||||
WriteBufferSize: 1024,
|
||||
CheckOrigin: func(r *http.Request) bool {
|
||||
// TODO
|
||||
return true
|
||||
},
|
||||
},
|
||||
func (con *Connection) Stop() {
|
||||
if atomic.CompareAndSwapUint32(&con.stopped, 0, 1) {
|
||||
con.wsConn.Close()
|
||||
close(con.writeChan)
|
||||
}
|
||||
}
|
||||
|
||||
func (wm *WebsocketManager) websocketHandler(w http.ResponseWriter, r *http.Request) {
|
||||
conn, err := wm.Upgrade(w, r, nil)
|
||||
if err != nil {
|
||||
// TODO
|
||||
log.Error("Failed to upgrade to websocket connection", "error", err)
|
||||
return
|
||||
}
|
||||
wm.handleWebsocket(conn)
|
||||
|
||||
}
|
||||
|
||||
func (w *WebsocketManager) handleWebsocket(con *websocket.Conn) {
|
||||
// register connection
|
||||
c := NewConnection(con)
|
||||
w.cons[c.id] = c
|
||||
log.Info("New websocket connection", "origin", c.id)
|
||||
|
||||
// read subscriptions/unsubscriptions to events
|
||||
go w.read(c)
|
||||
// write responses
|
||||
w.write(c)
|
||||
}
|
||||
|
||||
// read from the socket and subscribe to or unsubscribe from events
|
||||
func (w *WebsocketManager) read(con *Connection) {
|
||||
func (con *Connection) read() {
|
||||
reaper := time.Tick(time.Second * WSConnectionReaperSeconds)
|
||||
for {
|
||||
select {
|
||||
case <-reaper:
|
||||
if con.failedSends > MaxFailedSendsSeconds {
|
||||
if con.failedSends > MaxFailedSends {
|
||||
// sending has failed too many times.
|
||||
// kill the connection
|
||||
con.quitChan <- struct{}{}
|
||||
con.Stop()
|
||||
return
|
||||
}
|
||||
default:
|
||||
var in []byte
|
||||
_, in, err := con.wsCon.ReadMessage()
|
||||
_, in, err := con.wsConn.ReadMessage()
|
||||
if err != nil {
|
||||
// an error reading the connection,
|
||||
// so kill the connection
|
||||
con.quitChan <- struct{}{}
|
||||
// kill the connection
|
||||
con.Stop()
|
||||
return
|
||||
}
|
||||
var req WSRequest
|
||||
err = json.Unmarshal(in, &req)
|
||||
if err != nil {
|
||||
errStr := fmt.Sprintf("Error unmarshaling data: %s", err.Error())
|
||||
con.writeChan <- WSResponse{Error: errStr}
|
||||
continue
|
||||
}
|
||||
switch req.Type {
|
||||
case "subscribe":
|
||||
log.Info("New event subscription", "con id", con.id, "event", req.Event)
|
||||
w.ew.AddListenerForEvent(con.id, req.Event, func(msg interface{}) {
|
||||
con.evsw.AddListenerForEvent(con.id, req.Event, func(msg interface{}) {
|
||||
resp := WSResponse{
|
||||
Event: req.Event,
|
||||
Data: msg,
|
||||
@@ -328,9 +302,9 @@ func (w *WebsocketManager) read(con *Connection) {
|
||||
})
|
||||
case "unsubscribe":
|
||||
if req.Event != "" {
|
||||
w.ew.RemoveListenerForEvent(req.Event, con.id)
|
||||
con.evsw.RemoveListenerForEvent(req.Event, con.id)
|
||||
} else {
|
||||
w.ew.RemoveListener(con.id)
|
||||
con.evsw.RemoveListener(con.id)
|
||||
}
|
||||
default:
|
||||
con.writeChan <- WSResponse{Error: "Unknown request type: " + req.Type}
|
||||
@@ -340,33 +314,64 @@ func (w *WebsocketManager) read(con *Connection) {
|
||||
}
|
||||
}
|
||||
|
||||
// receives on a write channel and writes out to the socket
|
||||
func (w *WebsocketManager) write(con *Connection) {
|
||||
// receives on a write channel and writes out on the socket
|
||||
func (con *Connection) write() {
|
||||
n, err := new(int64), new(error)
|
||||
for {
|
||||
select {
|
||||
case msg := <-con.writeChan:
|
||||
buf := new(bytes.Buffer)
|
||||
binary.WriteJSON(msg, buf, n, err)
|
||||
if *err != nil {
|
||||
log.Error("Failed to write JSON WSResponse", "error", err)
|
||||
} else {
|
||||
//websocket.Message.Send(con.wsCon, buf.Bytes())
|
||||
if err := con.wsCon.WriteMessage(websocket.TextMessage, buf.Bytes()); err != nil {
|
||||
log.Error("Failed to write response on websocket", "error", err)
|
||||
}
|
||||
}
|
||||
case <-con.quitChan:
|
||||
w.closeConn(con)
|
||||
msg, more := <-con.writeChan
|
||||
if !more {
|
||||
// the channel was closed, so ensure
|
||||
// connection is stopped and return
|
||||
con.Stop()
|
||||
return
|
||||
}
|
||||
buf := new(bytes.Buffer)
|
||||
binary.WriteJSON(msg, buf, n, err)
|
||||
if *err != nil {
|
||||
log.Error("Failed to write JSON WSResponse", "error", err)
|
||||
} else {
|
||||
if err := con.wsConn.WriteMessage(websocket.TextMessage, buf.Bytes()); err != nil {
|
||||
log.Error("Failed to write response on websocket", "error", err)
|
||||
con.Stop()
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// close a connection and delete from manager
|
||||
func (w *WebsocketManager) closeConn(con *Connection) {
|
||||
con.Close()
|
||||
delete(w.cons, con.id)
|
||||
// main manager for all websocket connections
|
||||
// holds the event switch
|
||||
type WebsocketManager struct {
|
||||
websocket.Upgrader
|
||||
evsw *events.EventSwitch
|
||||
}
|
||||
|
||||
func NewWebsocketManager(evsw *events.EventSwitch) *WebsocketManager {
|
||||
return &WebsocketManager{
|
||||
evsw: evsw,
|
||||
Upgrader: websocket.Upgrader{
|
||||
ReadBufferSize: 1024,
|
||||
WriteBufferSize: 1024,
|
||||
CheckOrigin: func(r *http.Request) bool {
|
||||
// TODO
|
||||
return true
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (wm *WebsocketManager) websocketHandler(w http.ResponseWriter, r *http.Request) {
|
||||
wsConn, err := wm.Upgrade(w, r, nil)
|
||||
if err != nil {
|
||||
// TODO - return http error
|
||||
log.Error("Failed to upgrade to websocket connection", "error", err)
|
||||
return
|
||||
}
|
||||
|
||||
// register connection
|
||||
con := NewConnection(wsConn)
|
||||
log.Info("New websocket connection", "origin", con.id)
|
||||
con.Start(wm.evsw)
|
||||
}
|
||||
|
||||
// rpc.websocket
|
||||
|
||||
@@ -53,7 +53,7 @@ func WriteRPCResponse(w http.ResponseWriter, res RPCResponse) {
|
||||
func RecoverAndLogHandler(handler http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
// Wrap the ResponseWriter to remember the status
|
||||
rww := &ResponseWriterWrapper{-1, w, w.(http.Hijacker)}
|
||||
rww := &ResponseWriterWrapper{-1, w}
|
||||
begin := time.Now()
|
||||
|
||||
// Common headers
|
||||
@@ -100,7 +100,6 @@ func RecoverAndLogHandler(handler http.Handler) http.Handler {
|
||||
type ResponseWriterWrapper struct {
|
||||
Status int
|
||||
http.ResponseWriter
|
||||
hj http.Hijacker // necessary for websocket upgrades
|
||||
}
|
||||
|
||||
func (w *ResponseWriterWrapper) WriteHeader(status int) {
|
||||
@@ -110,7 +109,7 @@ func (w *ResponseWriterWrapper) WriteHeader(status int) {
|
||||
|
||||
// implements http.Hijacker
|
||||
func (w *ResponseWriterWrapper) Hijack() (net.Conn, *bufio.ReadWriter, error) {
|
||||
return w.hj.Hijack()
|
||||
return w.ResponseWriter.(http.Hijacker).Hijack()
|
||||
}
|
||||
|
||||
// Stick it as a deferred statement in gouroutines to prevent the program from crashing.
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package rpc
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/gorilla/websocket"
|
||||
@@ -172,7 +171,7 @@ func TestWSSend(t *testing.T) {
|
||||
amt := uint64(100)
|
||||
|
||||
con := newWSCon(t)
|
||||
eidInput := types.EventStringAccInput(byteAddr)
|
||||
eidInput := types.EventStringAccInput(userByteAddr)
|
||||
eidOutput := types.EventStringAccOutput(toAddr)
|
||||
subscribe(t, con, eidInput)
|
||||
subscribe(t, con, eidOutput)
|
||||
@@ -182,7 +181,7 @@ func TestWSSend(t *testing.T) {
|
||||
con.Close()
|
||||
}()
|
||||
waitForEvent(t, con, eidInput, true, func() {
|
||||
broadcastTx(t, "JSONRPC", byteAddr, toAddr, nil, byteKey, amt, 0, 0)
|
||||
broadcastTx(t, "JSONRPC", userByteAddr, toAddr, nil, userBytePriv, amt, 0, 0)
|
||||
}, unmarshalValidateSend(amt, toAddr))
|
||||
waitForEvent(t, con, eidOutput, true, func() {}, unmarshalValidateSend(amt, toAddr))
|
||||
}
|
||||
@@ -190,7 +189,7 @@ func TestWSSend(t *testing.T) {
|
||||
// ensure events are only fired once for a given transaction
|
||||
func TestWSDoubleFire(t *testing.T) {
|
||||
con := newWSCon(t)
|
||||
eid := types.EventStringAccInput(byteAddr)
|
||||
eid := types.EventStringAccInput(userByteAddr)
|
||||
subscribe(t, con, eid)
|
||||
defer func() {
|
||||
unsubscribe(t, con, eid)
|
||||
@@ -200,7 +199,7 @@ func TestWSDoubleFire(t *testing.T) {
|
||||
toAddr := []byte{20, 143, 25, 63, 16, 177, 83, 29, 91, 91, 54, 23, 233, 46, 190, 121, 122, 34, 86, 54}
|
||||
// broadcast the transaction, wait to hear about it
|
||||
waitForEvent(t, con, eid, true, func() {
|
||||
broadcastTx(t, "JSONRPC", byteAddr, toAddr, nil, byteKey, amt, 0, 0)
|
||||
broadcastTx(t, "JSONRPC", userByteAddr, toAddr, nil, userBytePriv, amt, 0, 0)
|
||||
}, func(eid string, b []byte) error {
|
||||
return nil
|
||||
})
|
||||
@@ -213,9 +212,8 @@ func TestWSDoubleFire(t *testing.T) {
|
||||
|
||||
// create a contract, wait for the event, and send it a msg, validate the return
|
||||
func TestWSCallWait(t *testing.T) {
|
||||
byteAddr, _ := hex.DecodeString(userAddr)
|
||||
con := newWSCon(t)
|
||||
eid1 := types.EventStringAccInput(byteAddr)
|
||||
eid1 := types.EventStringAccInput(userByteAddr)
|
||||
subscribe(t, con, eid1)
|
||||
defer func() {
|
||||
unsubscribe(t, con, eid1)
|
||||
@@ -226,7 +224,7 @@ func TestWSCallWait(t *testing.T) {
|
||||
var contractAddr []byte
|
||||
// wait for the contract to be created
|
||||
waitForEvent(t, con, eid1, true, func() {
|
||||
_, receipt := broadcastTx(t, "JSONRPC", byteAddr, nil, code, byteKey, amt, 1000, 1000)
|
||||
_, receipt := broadcastTx(t, "JSONRPC", userByteAddr, nil, code, userBytePriv, amt, 1000, 1000)
|
||||
contractAddr = receipt.ContractAddr
|
||||
|
||||
}, unmarshalValidateCall(amt, returnCode))
|
||||
@@ -241,19 +239,18 @@ func TestWSCallWait(t *testing.T) {
|
||||
// get the return value from a call
|
||||
data := []byte{0x1} // just needs to be non empty for this to be a CallTx
|
||||
waitForEvent(t, con, eid2, true, func() {
|
||||
broadcastTx(t, "JSONRPC", byteAddr, contractAddr, data, byteKey, amt, 1000, 1000)
|
||||
broadcastTx(t, "JSONRPC", userByteAddr, contractAddr, data, userBytePriv, amt, 1000, 1000)
|
||||
}, unmarshalValidateCall(amt, returnVal))
|
||||
}
|
||||
|
||||
// create a contract and send it a msg without waiting. wait for contract event
|
||||
// and validate return
|
||||
func TestWSCallNoWait(t *testing.T) {
|
||||
byteAddr, _ := hex.DecodeString(userAddr)
|
||||
con := newWSCon(t)
|
||||
amt := uint64(10000)
|
||||
code, _, returnVal := simpleContract()
|
||||
|
||||
_, receipt := broadcastTx(t, "JSONRPC", byteAddr, nil, code, byteKey, amt, 1000, 1000)
|
||||
_, receipt := broadcastTx(t, "JSONRPC", userByteAddr, nil, code, userBytePriv, amt, 1000, 1000)
|
||||
contractAddr := receipt.ContractAddr
|
||||
|
||||
// susbscribe to the new contract
|
||||
@@ -267,23 +264,22 @@ func TestWSCallNoWait(t *testing.T) {
|
||||
// get the return value from a call
|
||||
data := []byte{0x1} // just needs to be non empty for this to be a CallTx
|
||||
waitForEvent(t, con, eid, true, func() {
|
||||
broadcastTx(t, "JSONRPC", byteAddr, contractAddr, data, byteKey, amt, 1000, 1000)
|
||||
broadcastTx(t, "JSONRPC", userByteAddr, contractAddr, data, userBytePriv, amt, 1000, 1000)
|
||||
}, unmarshalValidateCall(amt, returnVal))
|
||||
}
|
||||
|
||||
// create two contracts, one of which calls the other
|
||||
func TestWSCallCall(t *testing.T) {
|
||||
byteAddr, _ := hex.DecodeString(userAddr)
|
||||
con := newWSCon(t)
|
||||
amt := uint64(10000)
|
||||
code, _, returnVal := simpleContract()
|
||||
txid := new([]byte)
|
||||
|
||||
// deploy the two contracts
|
||||
_, receipt := broadcastTx(t, "JSONRPC", byteAddr, nil, code, byteKey, amt, 1000, 1000)
|
||||
_, receipt := broadcastTx(t, "JSONRPC", userByteAddr, nil, code, userBytePriv, amt, 1000, 1000)
|
||||
contractAddr1 := receipt.ContractAddr
|
||||
code, _, _ = simpleCallContract(contractAddr1)
|
||||
_, receipt = broadcastTx(t, "JSONRPC", byteAddr, nil, code, byteKey, amt, 1000, 1000)
|
||||
_, receipt = broadcastTx(t, "JSONRPC", userByteAddr, nil, code, userBytePriv, amt, 1000, 1000)
|
||||
contractAddr2 := receipt.ContractAddr
|
||||
|
||||
// susbscribe to the new contracts
|
||||
@@ -300,7 +296,7 @@ func TestWSCallCall(t *testing.T) {
|
||||
// call contract2, which should call contract1, and wait for ev1
|
||||
data := []byte{0x1} // just needs to be non empty for this to be a CallTx
|
||||
waitForEvent(t, con, eid1, true, func() {
|
||||
tx, _ := broadcastTx(t, "JSONRPC", byteAddr, contractAddr2, data, byteKey, amt, 1000, 1000)
|
||||
*txid = account.SignBytes(tx)
|
||||
}, unmarshalValidateCallCall(byteAddr, returnVal, txid))
|
||||
tx, _ := broadcastTx(t, "JSONRPC", userByteAddr, contractAddr2, data, userBytePriv, amt, 1000, 1000)
|
||||
*txid = account.HashSignBytes(tx)
|
||||
}, unmarshalValidateCallCall(userByteAddr, returnVal, txid))
|
||||
}
|
||||
|
||||
@@ -28,10 +28,10 @@ var (
|
||||
|
||||
mempoolCount = 0
|
||||
|
||||
userAddr = "D7DFF9806078899C8DA3FE3633CC0BF3C6C2B1BB"
|
||||
userPriv = "FDE3BD94CB327D19464027BA668194C5EFA46AE83E8419D7542CFF41F00C81972239C21C81EA7173A6C489145490C015E05D4B97448933B708A7EC5B7B4921E3"
|
||||
userPub = "2239C21C81EA7173A6C489145490C015E05D4B97448933B708A7EC5B7B4921E3"
|
||||
byteAddr, byteKey = initUserBytes()
|
||||
userAddr = "D7DFF9806078899C8DA3FE3633CC0BF3C6C2B1BB"
|
||||
userPriv = "FDE3BD94CB327D19464027BA668194C5EFA46AE83E8419D7542CFF41F00C81972239C21C81EA7173A6C489145490C015E05D4B97448933B708A7EC5B7B4921E3"
|
||||
userPub = "2239C21C81EA7173A6C489145490C015E05D4B97448933B708A7EC5B7B4921E3"
|
||||
userByteAddr, userBytePriv = initUserBytes()
|
||||
|
||||
clients = map[string]cclient.Client{
|
||||
"JSONRPC": cclient.NewClient(requestAddr, "JSONRPC"),
|
||||
@@ -39,11 +39,13 @@ var (
|
||||
}
|
||||
)
|
||||
|
||||
// returns byte versions of address and private key
|
||||
// type [64]byte needed by account.GenPrivAccountFromKey
|
||||
func initUserBytes() ([]byte, [64]byte) {
|
||||
byteAddr, _ := hex.DecodeString(userAddr)
|
||||
var byteKey [64]byte
|
||||
oh, _ := hex.DecodeString(userPriv)
|
||||
copy(byteKey[:], oh)
|
||||
userPrivByteSlice, _ := hex.DecodeString(userPriv)
|
||||
copy(byteKey[:], userPrivByteSlice)
|
||||
return byteAddr, byteKey
|
||||
}
|
||||
|
||||
|
||||
@@ -2,14 +2,12 @@ package rpc
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
. "github.com/tendermint/tendermint/common"
|
||||
"github.com/tendermint/tendermint/config"
|
||||
"github.com/tendermint/tendermint/state"
|
||||
"github.com/tendermint/tendermint/types"
|
||||
"testing"
|
||||
//"time"
|
||||
)
|
||||
|
||||
func testStatus(t *testing.T, typ string) {
|
||||
@@ -38,35 +36,34 @@ func testGenPriv(t *testing.T, typ string) {
|
||||
}
|
||||
|
||||
func testGetAccount(t *testing.T, typ string) {
|
||||
byteAddr, _ := hex.DecodeString(userAddr)
|
||||
acc := getAccount(t, typ, byteAddr)
|
||||
acc := getAccount(t, typ, userByteAddr)
|
||||
if acc == nil {
|
||||
t.Fatalf("Account was nil")
|
||||
}
|
||||
if bytes.Compare(acc.Address, byteAddr) != 0 {
|
||||
t.Fatalf("Failed to get correct account. Got %x, expected %x", acc.Address, byteAddr)
|
||||
if bytes.Compare(acc.Address, userByteAddr) != 0 {
|
||||
t.Fatalf("Failed to get correct account. Got %x, expected %x", acc.Address, userByteAddr)
|
||||
}
|
||||
}
|
||||
|
||||
func testSignedTx(t *testing.T, typ string) {
|
||||
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, typ, byteAddr, toAddr, nil, byteKey, amt, 0, 0)
|
||||
checkTx(t, byteAddr, priv, tx.(*types.SendTx))
|
||||
tx, priv := signTx(t, typ, userByteAddr, toAddr, nil, userBytePriv, amt, 0, 0)
|
||||
checkTx(t, userByteAddr, 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, typ, byteAddr, toAddr, nil, byteKey, amt, 0, 0)
|
||||
checkTx(t, byteAddr, priv, tx.(*types.SendTx))
|
||||
tx, priv = signTx(t, typ, userByteAddr, toAddr, nil, userBytePriv, amt, 0, 0)
|
||||
checkTx(t, userByteAddr, 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, typ, byteAddr, toAddr, nil, byteKey, amt, 0, 0)
|
||||
checkTx(t, byteAddr, priv, tx.(*types.SendTx))
|
||||
tx, priv = signTx(t, typ, userByteAddr, toAddr, nil, userBytePriv, amt, 0, 0)
|
||||
checkTx(t, userByteAddr, priv, tx.(*types.SendTx))
|
||||
}
|
||||
|
||||
func testBroadcastTx(t *testing.T, typ string) {
|
||||
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, receipt := broadcastTx(t, typ, byteAddr, toAddr, nil, byteKey, amt, 0, 0)
|
||||
tx, receipt := broadcastTx(t, typ, userByteAddr, toAddr, nil, userBytePriv, amt, 0, 0)
|
||||
if receipt.CreatesContract > 0 {
|
||||
t.Fatal("This tx does not create a contract")
|
||||
}
|
||||
@@ -102,7 +99,7 @@ func testGetStorage(t *testing.T, typ string) {
|
||||
|
||||
amt := uint64(1100)
|
||||
code := []byte{0x60, 0x5, 0x60, 0x1, 0x55}
|
||||
_, receipt := broadcastTx(t, typ, byteAddr, nil, code, byteKey, amt, 1000, 1000)
|
||||
_, receipt := broadcastTx(t, typ, userByteAddr, nil, code, userBytePriv, amt, 1000, 1000)
|
||||
if receipt.CreatesContract == 0 {
|
||||
t.Fatal("This tx creates a contract")
|
||||
}
|
||||
@@ -115,7 +112,6 @@ func testGetStorage(t *testing.T, typ string) {
|
||||
}
|
||||
|
||||
// allow it to get mined
|
||||
//time.Sleep(time.Second * 20)
|
||||
waitForEvent(t, con, eid, true, func() {
|
||||
}, func(eid string, b []byte) error {
|
||||
return nil
|
||||
@@ -160,7 +156,7 @@ func testCall(t *testing.T, typ string) {
|
||||
// create the contract
|
||||
amt := uint64(6969)
|
||||
code, _, _ := simpleContract()
|
||||
_, receipt := broadcastTx(t, typ, byteAddr, nil, code, byteKey, amt, 1000, 1000)
|
||||
_, receipt := broadcastTx(t, typ, userByteAddr, nil, code, userBytePriv, amt, 1000, 1000)
|
||||
if receipt.CreatesContract == 0 {
|
||||
t.Fatal("This tx creates a contract")
|
||||
}
|
||||
@@ -173,7 +169,6 @@ func testCall(t *testing.T, typ string) {
|
||||
}
|
||||
|
||||
// allow it to get mined
|
||||
//time.Sleep(time.Second * 20)
|
||||
waitForEvent(t, con, eid, true, func() {
|
||||
}, func(eid string, b []byte) error {
|
||||
return nil
|
||||
|
||||
@@ -6,7 +6,6 @@ import (
|
||||
"github.com/gorilla/websocket"
|
||||
"github.com/tendermint/tendermint/binary"
|
||||
"github.com/tendermint/tendermint/types"
|
||||
"github.com/tendermint/tendermint/vm"
|
||||
"testing"
|
||||
)
|
||||
|
||||
@@ -51,14 +50,14 @@ func unmarshalValidateSend(amt uint64, toAddr []byte) func(string, []byte) error
|
||||
return fmt.Errorf("Eventid is not correct. Got %s, expected %s", response.Event, eid)
|
||||
}
|
||||
tx := response.Data
|
||||
if bytes.Compare(tx.Inputs[0].Address, byteAddr) != 0 {
|
||||
return fmt.Errorf("Senders do not match up! Got %x, expected %x", tx.Inputs[0].Address, byteAddr)
|
||||
if bytes.Compare(tx.Inputs[0].Address, userByteAddr) != 0 {
|
||||
return fmt.Errorf("Senders do not match up! Got %x, expected %x", tx.Inputs[0].Address, userByteAddr)
|
||||
}
|
||||
if tx.Inputs[0].Amount != amt {
|
||||
return fmt.Errorf("Amt does not match up! Got %d, expected %d", tx.Inputs[0].Amount, amt)
|
||||
}
|
||||
if bytes.Compare(tx.Outputs[0].Address, toAddr) != 0 {
|
||||
return fmt.Errorf("Receivers do not match up! Got %x, expected %x", tx.Outputs[0].Address, byteAddr)
|
||||
return fmt.Errorf("Receivers do not match up! Got %x, expected %x", tx.Outputs[0].Address, userByteAddr)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -88,8 +87,8 @@ func unmarshalValidateCall(amt uint64, returnCode []byte) func(string, []byte) e
|
||||
return fmt.Errorf(response.Data.Exception)
|
||||
}
|
||||
tx := response.Data.Tx
|
||||
if bytes.Compare(tx.Input.Address, byteAddr) != 0 {
|
||||
return fmt.Errorf("Senders do not match up! Got %x, expected %x", tx.Input.Address, byteAddr)
|
||||
if bytes.Compare(tx.Input.Address, userByteAddr) != 0 {
|
||||
return fmt.Errorf("Senders do not match up! Got %x, expected %x", tx.Input.Address, userByteAddr)
|
||||
}
|
||||
if tx.Input.Amount != amt {
|
||||
return fmt.Errorf("Amt does not match up! Got %d, expected %d", tx.Input.Amount, amt)
|
||||
@@ -107,13 +106,7 @@ func unmarshalValidateCallCall(origin, returnCode []byte, txid *[]byte) func(str
|
||||
// unmarshall and assert somethings
|
||||
var response struct {
|
||||
Event string
|
||||
Data struct {
|
||||
CallData *vm.CallData
|
||||
Origin []byte
|
||||
TxId []byte
|
||||
Return []byte
|
||||
Exception string
|
||||
}
|
||||
Data types.EventMsgCall
|
||||
Error string
|
||||
}
|
||||
var err error
|
||||
|
||||
@@ -53,9 +53,7 @@ func (cache *BlockCache) GetAccount(addr []byte) *ac.Account {
|
||||
return acc
|
||||
} else {
|
||||
acc = cache.backend.GetAccount(addr)
|
||||
if acc != nil {
|
||||
cache.accounts[string(addr)] = accountInfo{acc, nil, false, false}
|
||||
}
|
||||
cache.accounts[string(addr)] = accountInfo{acc, nil, false, false}
|
||||
return acc
|
||||
}
|
||||
}
|
||||
@@ -189,7 +187,7 @@ func (cache *BlockCache) Sync() {
|
||||
}
|
||||
} else {
|
||||
if acc == nil {
|
||||
panic(Fmt("Account should not be nil for addr: %x", addrStr))
|
||||
continue
|
||||
}
|
||||
if storage != nil {
|
||||
newStorageRoot := storage.Save()
|
||||
|
||||
@@ -426,12 +426,12 @@ func ExecTx(blockCache *BlockCache, tx_ types.Tx, runCall, fireEvents bool) erro
|
||||
|
||||
txCache.UpdateAccount(caller) // because we adjusted by input above, and bumped nonce maybe.
|
||||
txCache.UpdateAccount(callee) // because we adjusted by input above.
|
||||
vmach := vm.NewVM(txCache, params, caller.Address, account.SignBytes(tx))
|
||||
vmach := vm.NewVM(txCache, params, caller.Address, account.HashSignBytes(tx))
|
||||
vmach.SetEventSwitch(_s.evsw)
|
||||
// NOTE: Call() transfers the value from caller to callee iff call succeeds.
|
||||
|
||||
ret, err := vmach.Call(caller, callee, code, tx.Data, value, &gas)
|
||||
var exception string
|
||||
exception := ""
|
||||
if err != nil {
|
||||
exception = err.Error()
|
||||
// Failure. Charge the gas fee. The 'value' was otherwise not transferred.
|
||||
@@ -440,7 +440,6 @@ func ExecTx(blockCache *BlockCache, tx_ types.Tx, runCall, fireEvents bool) erro
|
||||
blockCache.UpdateAccount(inAcc)
|
||||
// Throw away 'txCache' which holds incomplete updates (don't sync it).
|
||||
} else {
|
||||
exception = ""
|
||||
log.Debug("Successful execution")
|
||||
// Success
|
||||
if createAccount {
|
||||
@@ -455,17 +454,9 @@ func ExecTx(blockCache *BlockCache, tx_ types.Tx, runCall, fireEvents bool) erro
|
||||
if fireEvents {
|
||||
// Fire Events for sender and receiver
|
||||
// a separate event will be fired from vm for each
|
||||
_s.evsw.FireEvent(types.EventStringAccInput(tx.Input.Address), struct {
|
||||
Tx types.Tx
|
||||
Return []byte
|
||||
Exception string
|
||||
}{tx, ret, exception})
|
||||
_s.evsw.FireEvent(types.EventStringAccInput(tx.Input.Address), types.EventMsgCallTx{tx, ret, exception})
|
||||
|
||||
_s.evsw.FireEvent(types.EventStringAccReceive(tx.Address), struct {
|
||||
Tx types.Tx
|
||||
Return []byte
|
||||
Exception string
|
||||
}{tx, ret, exception})
|
||||
_s.evsw.FireEvent(types.EventStringAccReceive(tx.Address), types.EventMsgCallTx{tx, ret, exception})
|
||||
}
|
||||
} else {
|
||||
// The mempool does not call txs until
|
||||
|
||||
@@ -4,6 +4,8 @@ import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// Functions to generate eventId strings
|
||||
|
||||
func EventStringAccInput(addr []byte) string {
|
||||
return fmt.Sprintf("Acc/%x/Input", addr)
|
||||
}
|
||||
@@ -40,6 +42,31 @@ func EventStringFork() string {
|
||||
return "Fork"
|
||||
}
|
||||
|
||||
// Most event messages are basic types (a block, a transaction)
|
||||
// but some (an input to a call tx or a receive) are more exotic:
|
||||
|
||||
type EventMsgCallTx struct {
|
||||
Tx Tx
|
||||
Return []byte
|
||||
Exception string
|
||||
}
|
||||
|
||||
type CallData struct {
|
||||
Caller []byte
|
||||
Callee []byte
|
||||
Data []byte
|
||||
Value uint64
|
||||
Gas uint64
|
||||
}
|
||||
|
||||
type EventMsgCall struct {
|
||||
CallData *CallData
|
||||
Origin []byte
|
||||
TxId []byte
|
||||
Return []byte
|
||||
Exception string
|
||||
}
|
||||
|
||||
/*
|
||||
Acc/XYZ/Input -> full tx or {full tx, return value, exception}
|
||||
Acc/XYZ/Output -> full tx
|
||||
|
||||
@@ -46,11 +46,3 @@ type Params struct {
|
||||
BlockTime int64
|
||||
GasLimit uint64
|
||||
}
|
||||
|
||||
type CallData struct {
|
||||
Caller []byte
|
||||
Callee []byte
|
||||
Data []byte
|
||||
Value uint64
|
||||
Gas uint64
|
||||
}
|
||||
|
||||
12
vm/vm.go
12
vm/vm.go
@@ -91,17 +91,11 @@ func (vm *VM) Call(caller, callee *Account, code, input []byte, value uint64, ga
|
||||
panic("Could not return value to caller")
|
||||
}
|
||||
}
|
||||
// if callDepth is 0 the event is fired from ExecTx (along with the Input invent)
|
||||
// if callDepth is 0 the event is fired from ExecTx (along with the Input event)
|
||||
// otherwise, we fire from here.
|
||||
if vm.callDepth != 0 && vm.evsw != nil {
|
||||
vm.evsw.FireEvent(types.EventStringAccReceive(callee.Address.Prefix(20)), struct {
|
||||
CallData *CallData
|
||||
Origin []byte
|
||||
TxId []byte
|
||||
Return []byte
|
||||
Exception string
|
||||
}{
|
||||
&CallData{caller.Address.Prefix(20), callee.Address.Prefix(20), input, value, *gas},
|
||||
vm.evsw.FireEvent(types.EventStringAccReceive(callee.Address.Prefix(20)), types.EventMsgCall{
|
||||
&types.CallData{caller.Address.Prefix(20), callee.Address.Prefix(20), input, value, *gas},
|
||||
vm.origin.Prefix(20),
|
||||
vm.txid,
|
||||
output,
|
||||
|
||||
Reference in New Issue
Block a user