Browse Source

Log not error; Remove Listener TMSP messages...; Make counter BigEndian

pull/1780/head
Jae Kwon 9 years ago
parent
commit
9696a71f6e
23 changed files with 413 additions and 509 deletions
  1. +11
    -9
      README.md
  2. +23
    -30
      client/client.go
  3. +22
    -33
      example/golang/counter.go
  4. +13
    -25
      example/golang/dummy.go
  5. +2
    -2
      example/golang/dummy_test.go
  6. +1
    -0
      example/js/.gitignore
  7. +35
    -42
      example/js/app.js
  8. +83
    -54
      example/js/msgs.js
  9. +10
    -0
      example/js/package.json
  10. +131
    -116
      example/js/server.js
  11. +27
    -0
      example/js/types.js
  12. +0
    -111
      example/js/wire.js
  13. +1
    -0
      example/python/app.py
  14. +1
    -0
      example/python3/app.py
  15. +11
    -21
      server/server.go
  16. +5
    -4
      tests/test.sh
  17. +11
    -8
      tests/test_counter.sh
  18. +8
    -4
      tests/test_dummy.sh
  19. +6
    -15
      types/application.go
  20. +0
    -6
      types/events.go
  21. +10
    -14
      types/messages.go
  22. +0
    -13
      types/retcode.go
  23. +2
    -2
      types/retcode_string.go

+ 11
- 9
README.md View File

@ -12,9 +12,9 @@ For more information on TMSP, motivations, and tutorials, please visit [our blog
* __Arguments__:
* `TxBytes ([]byte)`
* __Returns__:
* `RetCode (int8)`
* `RetData ([]KVPair)`
* `Error (string)`
* `Code (int8)`
* `Result ([]byte)`
* `Log (string)`
* __Usage__:<br/>
Append and run a transaction. The transaction may or may not be final.
@ -22,15 +22,16 @@ For more information on TMSP, motivations, and tutorials, please visit [our blog
* __Arguments__:
* `TxBytes ([]byte)`
* __Returns__:
* `RetCode (int8)`
* `RetData ([]KVPair)`
* `Error (string)`
* `Code (int8)`
* `Result ([]byte)`
* `Log (string)`
* __Usage__:<br/>
Validate a transaction. This message should not mutate the state.
#### GetHash
* __Returns__:
* `Hash ([]byte)`
* `Log (string)`
* __Usage__:<br/>
Return a Merkle root hash of the application state
@ -49,7 +50,7 @@ For more information on TMSP, motivations, and tutorials, please visit [our blog
* `Key (string)`
* `Value (string)`
* __Returns__:
* `Error (string)`
* `Log (string)`
* __Usage__:<br/>
Set application options. E.g. Key="mode", Value="mempool" for a mempool connection, or Key="mode", Value="consensus" for a consensus connection.
Other options are application specific.
@ -59,9 +60,10 @@ For more information on TMSP, motivations, and tutorials, please visit [our blog
### Jan 23th, 2016
* Added CheckTx/Query TMSP message types
* Added RetData/Error fields to AppendTx/CheckTx/SetOption
* Added Result/Log fields to AppendTx/CheckTx/SetOption
* Removed Listener messages
* Removed RetCode from ResponseSetOption and ResponseGetHash
* Removed Code from ResponseSetOption and ResponseGetHash
* Made examples BigEndian
### Jan 12th, 2016


client/golang/client.go → client/client.go View File


+ 22
- 33
example/golang/counter.go View File

@ -2,6 +2,7 @@ package example
import (
"encoding/binary"
"fmt"
. "github.com/tendermint/go-common"
"github.com/tendermint/tmsp/types"
@ -17,66 +18,54 @@ func NewCounterApplication(serial bool) *CounterApplication {
return &CounterApplication{serial: serial}
}
func (app *CounterApplication) Echo(message string) string {
return message
func (app *CounterApplication) Info() string {
return Fmt("hashes:%v, txs:%v", app.hashCount, app.txCount)
}
func (app *CounterApplication) Info() []string {
return []string{Fmt("hashes:%v, txs:%v", app.hashCount, app.txCount)}
}
func (app *CounterApplication) SetOption(key string, value string) types.RetCode {
func (app *CounterApplication) SetOption(key string, value string) (log string) {
if key == "serial" && value == "on" {
app.serial = true
}
return types.RetCodeOK
return ""
}
func (app *CounterApplication) AppendTx(tx []byte) ([]types.Event, types.RetCode) {
func (app *CounterApplication) AppendTx(tx []byte) (code types.RetCode, result []byte, log string) {
if app.serial {
tx8 := make([]byte, 8)
copy(tx8, tx)
txValue := binary.LittleEndian.Uint64(tx8)
copy(tx8[len(tx8)-len(tx):], tx)
txValue := binary.BigEndian.Uint64(tx8)
if txValue != uint64(app.txCount) {
return nil, types.RetCodeBadNonce
return types.RetCodeBadNonce, nil, fmt.Sprintf("Invalid nonce. Expected %v, got %v", app.txCount, txValue)
}
}
app.txCount += 1
return nil, types.RetCodeOK
return types.RetCodeOK, nil, ""
}
func (app *CounterApplication) CheckTx(tx []byte) types.RetCode {
func (app *CounterApplication) CheckTx(tx []byte) (code types.RetCode, result []byte, log string) {
if app.serial {
tx8 := make([]byte, 8)
copy(tx8, tx)
txValue := binary.LittleEndian.Uint64(tx8)
copy(tx8[len(tx8)-len(tx):], tx)
txValue := binary.BigEndian.Uint64(tx8)
if txValue < uint64(app.txCount) {
return types.RetCodeBadNonce
return types.RetCodeBadNonce, nil, fmt.Sprintf("Invalid nonce. Expected >= %v, got %v", app.txCount, txValue)
}
}
return types.RetCodeOK
return types.RetCodeOK, nil, ""
}
func (app *CounterApplication) GetHash() ([]byte, types.RetCode) {
func (app *CounterApplication) GetHash() (hash []byte, log string) {
app.hashCount += 1
if app.txCount == 0 {
return nil, types.RetCodeOK
return nil, ""
} else {
hash := make([]byte, 32)
binary.LittleEndian.PutUint64(hash, uint64(app.txCount))
return hash, types.RetCodeOK
hash := make([]byte, 8)
binary.BigEndian.PutUint64(hash, uint64(app.txCount))
return hash, ""
}
}
func (app *CounterApplication) AddListener(key string) types.RetCode {
return types.RetCodeOK
}
func (app *CounterApplication) RemListener(key string) types.RetCode {
return types.RetCodeOK
}
func (app *CounterApplication) Query(query []byte) ([]byte, types.RetCode) {
return nil, types.RetCodeOK
func (app *CounterApplication) Query(query []byte) (result []byte, log string) {
return nil, fmt.Sprintf("Query is not supported")
}

+ 13
- 25
example/golang/dummy.go View File

@ -18,40 +18,28 @@ func NewDummyApplication() *DummyApplication {
return &DummyApplication{state: state}
}
func (app *DummyApplication) Echo(message string) string {
return message
func (app *DummyApplication) Info() string {
return Fmt("size:%v", app.state.Size())
}
func (app *DummyApplication) Info() []string {
return []string{Fmt("size:%v", app.state.Size())}
func (app *DummyApplication) SetOption(key string, value string) (log string) {
return ""
}
func (app *DummyApplication) SetOption(key string, value string) types.RetCode {
return types.RetCodeOK
}
func (app *DummyApplication) AppendTx(tx []byte) ([]types.Event, types.RetCode) {
func (app *DummyApplication) AppendTx(tx []byte) (code types.RetCode, result []byte, log string) {
app.state.Set(tx, tx)
return nil, types.RetCodeOK
}
func (app *DummyApplication) CheckTx(tx []byte) types.RetCode {
return types.RetCodeOK // all txs are valid
}
func (app *DummyApplication) GetHash() ([]byte, types.RetCode) {
hash := app.state.Hash()
return hash, types.RetCodeOK
return types.RetCodeOK, nil, ""
}
func (app *DummyApplication) AddListener(key string) types.RetCode {
return types.RetCodeOK
func (app *DummyApplication) CheckTx(tx []byte) (code types.RetCode, result []byte, log string) {
return types.RetCodeOK, nil, ""
}
func (app *DummyApplication) RemListener(key string) types.RetCode {
return types.RetCodeOK
func (app *DummyApplication) GetHash() (hash []byte, log string) {
hash = app.state.Hash()
return hash, ""
}
func (app *DummyApplication) Query(query []byte) ([]byte, types.RetCode) {
return nil, types.RetCodeOK
func (app *DummyApplication) Query(query []byte) (result []byte, log string) {
return nil, "Query not supported"
}

+ 2
- 2
example/golang/dummy_test.go View File

@ -44,8 +44,8 @@ func TestStream(t *testing.T) {
switch res := res.(type) {
case types.ResponseAppendTx:
counter += 1
if res.RetCode != types.RetCodeOK {
t.Error("AppendTx failed with ret_code", res.RetCode)
if res.Code != types.RetCodeOK {
t.Error("AppendTx failed with ret_code", res.Code)
}
if counter > numAppendTxs {
t.Fatal("Too many AppendTx responses")


+ 1
- 0
example/js/.gitignore View File

@ -0,0 +1 @@
node_modules

+ 35
- 42
example/js/app.js View File

@ -1,6 +1,9 @@
server = require("./server")
wire = require("./wire")
util = require("util")
var server = require("./server");
var wire = require("js-wire");
var util = require("util");
var msg = require("./msgs");
var types = require("./types");
function CounterApp(){
this.hashCount = 0;
@ -8,75 +11,65 @@ function CounterApp(){
this.serial = false;
};
CounterApp.prototype.echo = function(msg){
return {"response": msg, "ret_code":0}
}
CounterApp.prototype.info = function(){
return {"response": [util.format("hashes:%d, txs:%d", this.hashCount, this.txCount)]}
CounterApp.prototype.info = function(cb) {
return cb(util.format("hashes:%d, txs:%d", this.hashCount, this.txCount));
}
CounterApp.prototype.set_option = function(key, value){
if (key == "serial" && value == "on"){
CounterApp.prototype.set_option = function(cb, key, value) {
if (key == "serial" && value == "on") {
this.serial = true;
}
return {"ret_code":0}
return cb("");
}
CounterApp.prototype.append_tx = function(txBytes){
CounterApp.prototype.append_tx = function(cb, txBytes) {
if (this.serial) {
txByteArray = new Buffer(txBytes)
if (txBytes.length >= 2 && txBytes.slice(0, 2) == "0x") {
txByteArray = wire.hex2bytes(txBytes.slice(2));
var hexString = txBytes.toString("ascii", 2);
var hexBytes = new Buffer(hexString, "hex");
txBytes = hexBytes;
}
r = new msg.buffer(txByteArray)
txValue = wire.decode_big_endian(r, txBytes.length)
var txValue = txBytes.readIntBE(0, txBytes.length);
if (txValue != this.txCount){
return {"ret_code":6}
return cb(types.RetCodeInvalidNonce, "", "Nonce is invalid");
}
}
this.txCount += 1;
return {"ret_code":0} // TODO: return events
return cb(types.RetCodeOK, "", "");
}
CounterApp.prototype.check_tx = function(txBytes){
CounterApp.prototype.check_tx = function(cb, txBytes) {
if (this.serial) {
txByteArray = new Buffer(txBytes)
if (txBytes.length >= 2 && txBytes.slice(0, 2) == "0x") {
txByteArray = wire.hex2bytes(txBytes.slice(2));
var hexString = txBytes.toString("ascii", 2);
var hexBytes = new Buffer(hexString, "hex");
txBytes = hexBytes;
}
r = new msg.buffer(txByteArray)
txValue = wire.decode_big_endian(r, txBytes.length)
var txValue = txBytes.readIntBE(0, txBytes.length);
if (txValue < this.txCount){
return {"ret_code":6}
return cb(types.RetCodeInvalidNonce, "", "Nonce is too low");
}
}
return {"ret_code":0}
this.txCount += 1;
return cb(types.RetCodeOK, "", "");
}
CounterApp.prototype.get_hash = function(){
CounterApp.prototype.get_hash = function(cb) {
this.hashCount += 1;
if (this.txCount == 0){
return {"response": "", "ret_code":0}
return cb("", "Zero tx count; hash is empth");
}
h = wire.encode_big_endian(this.txCount, 8);
h = wire.reverse(h); // TODO
return {"response": h.toString(), "ret_code":0}
}
CounterApp.prototype.add_listener = function(){
return {"ret_code":0}
}
CounterApp.prototype.rm_listener = function(){
return {"ret_code":0}
var buf = new Buffer(8);
buf.writeIntBE(this.txCount, 0, 8);
cb(buf, "");
}
CounterApp.prototype.event = function(){
CounterApp.prototype.query = function(cb) {
return cb("", "Query not yet supporrted");
}
console.log("Counter app in Javascript")
console.log("Counter app in Javascript");
var app = new CounterApp();
var appServer = new server.AppServer(app);
appServer.server.listen(46658)
appServer.server.listen(46658);

+ 83
- 54
example/js/msgs.js View File

@ -1,59 +1,88 @@
wire = require("./wire")
var wire = require("js-wire");
var types = require("./types");
module.exports = {
types : {
0x01 : "echo",
0x02 : "flush",
0x03 : "info",
0x04 : "set_option",
0x21 : "append_tx",
0x22 : "check_tx",
0x23 : "get_hash",
0x24 : "add_listener",
0x25 : "rm_listener",
},
decoder : RequestDecoder,
buffer: BytesBuffer
}
function RequestDecoder(buf){
this.buf= buf
}
var decode_string = wire.decode_string
var readRequestInfo = function(r) { return []; };
var readRequestSetOption = function(r) { return [r.readString(), r.readString()]; };
var readRequestAppendTx = function(r) { return [r.readByteArray()]; };
var readRequestCheckTx = function(r) { return [r.readByteArray()]; };
var readRequestGetHash = function(r) { return []; };
var readRequestQuery = function(r) { return [r.readByteArray()]; };
// return nothing, one thing, or a list of things
RequestDecoder.prototype.echo = function(){ return decode_string(this.buf) };
RequestDecoder.prototype.flush = function(){};
RequestDecoder.prototype.info = function(){};
RequestDecoder.prototype.set_option = function(){ return [decode_string(this.buf), decode_string(this.buf)] };
RequestDecoder.prototype.append_tx = function(){ return decode_string(this.buf)};
RequestDecoder.prototype.check_tx = function(){ return decode_string(this.buf)};
RequestDecoder.prototype.get_hash = function(){ };
RequestDecoder.prototype.add_listener = function(){ }; // TODO
RequestDecoder.prototype.rm_listener = function(){ }; // TODO
// buffered reader with read(n) method
function BytesBuffer(buf){
this.buf = buf
}
BytesBuffer.prototype.read = function(n){
b = this.buf.slice(0, n)
this.buf = this.buf.slice(n)
return b
var runOnce = function(name, f) {
var ran = false;
return function() {
if (ran) {
console.log("Error: response was already written for "+name);
return
} else {
ran = true;
}
return f.apply(this, arguments);
};
};
BytesBuffer.prototype.write = function(buf){
this.buf = Buffer.concat([this.buf, buf]);
};
BytesBuffer.prototype.size = function(){
return this.buf.length
}
BytesBuffer.prototype.peek = function(){
return this.buf[0]
}
var makeWriteResponseInfo = function(w, cb) { return runOnce("info", function(info) {
w.writeUint8(types.ResponseTypeInfo);
w.writeString(info);
cb(w);
});};
var makeWriteResponseSetOption = function(w, cb) { return runOnce("set_option", function(log) {
w.writeUint8(types.ResponseTypeSetOption);
w.writeString(log);
cb(w);
});};
var makeWriteResponseAppendTx = function(w, cb) { return runOnce("append_tx", function(code, result, log) {
w.writeUint8(types.ResponseTypeAppendTx);
w.writeUint8(code);
w.writeByteArray(result);
w.writeString(log);
cb(w);
});};
var makeWriteResponseCheckTx = function(w, cb) { return runOnce("check_tx", function(code, result, log) {
w.writeUint8(types.ResponseTypeCheckTx);
w.writeUint8(code);
w.writeByteArray(result);
w.writeString(log);
cb(w);
});};
var makeWriteResponseGetHash = function(w, cb) { return runOnce("get_hash", function(hash, log) {
w.writeUint8(types.ResponseTypeGetHash);
w.writeByteArray(hash);
w.writeString(log);
cb(w);
});};
var makeWriteResponseQuery = function(w, cb) { return runOnce("query", function(result, log) {
w.writeUint8(types.ResponseTypeQuery);
w.writeByteArray(result);
w.writeString(log);
cb(w);
});};
module.exports = {
types : {
0x01 : "echo",
0x02 : "flush",
0x03 : "info",
0x04 : "set_option",
0x21 : "append_tx",
0x22 : "check_tx",
0x23 : "get_hash",
0x24 : "query",
},
readers : {
"info": readRequestInfo,
"set_option": readRequestSetOption,
"append_tx": readRequestAppendTx,
"check_tx": readRequestCheckTx,
"get_hash": readRequestGetHash,
"query": readRequestQuery,
},
writerGenerators: {
"info": makeWriteResponseInfo,
"set_option": makeWriteResponseSetOption,
"append_tx": makeWriteResponseAppendTx,
"check_tx": makeWriteResponseCheckTx,
"get_hash": makeWriteResponseGetHash,
"query": makeWriteResponseQuery,
},
};

+ 10
- 0
example/js/package.json View File

@ -0,0 +1,10 @@
{
"name": "example",
"version": "0.0.1",
"description": "Example javascript TMSP application",
"main": "index.js",
"dependencies": {
"js-wire": "0.0.2"
}
}

+ 131
- 116
example/js/server.js View File

@ -1,126 +1,141 @@
var net = require("net");
var wire = require("js-wire");
var msg = require("./msgs");
var types = require("./types");
// Load the TCP Library
net = require('net');
msg = require('./msgs');
wire = require("./wire")
var maxWriteBufferLength = 4096; // Any more and flush
// Takes an application and handles tmsp connection
// Takes an application and handles TMSP connection
// which invoke methods on the app
function AppServer(app){
// set the app for the socket handler
this.app = app;
// set the app for the socket handler
this.app = app;
// create a server by providing callback for
// accepting new connection and callbacks for
// connection events ('data', 'end', etc.)
this.createServer()
// create a server by providing callback for
// accepting new connection and callbacks for
// connection events ('data', 'end', etc.)
this.createServer();
}
module.exports = { AppServer: AppServer };
AppServer.prototype.createServer = function() {
var app = this.app;
// Define the socket handler
this.server = net.createServer(function(socket) {
socket.name = socket.remoteAddress + ":" + socket.remotePort;
console.log("new connection from", socket.name);
var conn = new Connection(socket, function(msgBytes, cb) {
var r = new wire.Reader(msgBytes);
// Now we can decode
var typeByte = r.readByte();
var reqType = msg.types[typeByte];
// Special messages.
// NOTE: msgs are length prefixed
if (reqType == "flush") {
var w = new wire.Writer();
w.writeByte(types.ResponseTypeFlush);
conn.writeMessage(w.getBuffer());
conn.flush();
return cb();
} else if (reqType == "echo") {
var message = r.readString();
var w = new wire.Writer();
w.writeByte(types.ResponseTypeEcho);
w.writeString(message);
conn.writeMessage(w.getBuffer());
return cb();
}
// Make callback by wrapping cp
var resCb = msg.writerGenerators[reqType](new wire.Writer(), function(w) {
conn.writeMessage(w.getBuffer());
return cb();
});
// Decode arguments
var args = msg.readers[reqType](r);
args.unshift(resCb);
// Call function
var res = app[reqType].apply(app, args);
if (res != undefined) {
console.log("Message handler shouldn't return anything!");
}
});
});
}
//----------------------------------------
function Connection(socket, msgCb) {
this.socket = socket;
this.recvBuf = new Buffer(0);
this.sendBuf = new Buffer(0);
this.msgCb = msgCb;
this.waitingResult = false;
var conn = this;
// Handle TMSP requests.
socket.on('data', function(data) {
conn.appendData(data);
});
socket.on('end', function() {
console.log("connection ended");
});
}
AppServer.prototype.createServer = function(){
app = this.app
conns = {} // map sockets to their state
// define the socket handler
this.server = net.createServer(function(socket){
socket.name = socket.remoteAddress + ":" + socket.remotePort
console.log("new connection from", socket.name)
var conn = {
recBuf: new msg.buffer(new Buffer(0)),
resBuf: new msg.buffer(new Buffer(0)),
msgLength: 0,
inProgress: false
}
conns[socket] = conn
// Handle tmsp requests.
socket.on('data', function (data) {
if (data.length == 0){
// TODO err
console.log("empty data!")
return
}
conn = conns[socket]
// we received data. append it
conn.recBuf.write(data)
while ( conn.recBuf.size() > 0 ){
if (conn.msgLength == 0){
ll = conn.recBuf.peek();
if (conn.recBuf.size() < 1 + ll){
// don't have enough bytes to read length yet
return
}
conn.msgLength = wire.decode_varint(conn.recBuf)
}
if (conn.recBuf.size() < conn.msgLength) {
// don't have enough to decode the message
return
}
// now we can decode
typeByte = conn.recBuf.read(1);
resTypeByte = typeByte[0] + 0x10
reqType = msg.types[typeByte[0]];
if (reqType == "flush"){
// msgs are length prefixed
conn.resBuf.write(wire.encode(1));
conn.resBuf.write(new Buffer([resTypeByte]))
n = socket.write(conn.resBuf.buf);
conn.msgLength = 0;
conn.resBuf = new msg.buffer(new Buffer(0));
return
}
// decode args
decoder = new msg.decoder(conn.recBuf);
args = decoder[reqType]();
// done decoding
conn.msgLength = 0
var res = function(){
if (args == null){
return app[reqType]();
} else if (Array.isArray(args)){
return app[reqType].apply(app, args);
} else {
return app[reqType](args)
}
}()
var retCode = res["ret_code"]
var res = res["response"]
if (retCode != null && retCode != 0){
console.log("non-zero ret code", retCode)
}
if (reqType == "echo" || reqType == "info"){
enc = Buffer.concat([new Buffer([resTypeByte]), wire.encode(res)]);
// length prefixed
conn.resBuf.write(wire.encode(enc.length));
conn.resBuf.write(enc);
} else {
enc = Buffer.concat([new Buffer([resTypeByte]), wire.encode(retCode), wire.encode(res)]);
conn.resBuf.write(wire.encode(enc.length));
conn.resBuf.write(enc);
}
}
});
socket.on('end', function () {
console.log("connection ended")
});
})
Connection.prototype.appendData = function(bytes) {
var conn = this;
if (bytes.length > 0) {
this.recvBuf = Buffer.concat([this.recvBuf, new Buffer(bytes)]);
}
if (this.waitingResult) {
return;
}
var r = new wire.Reader(this.recvBuf);
var msg;
try {
msg = r.readByteArray();
} catch(e) {
return;
}
this.recvBuf = r.buf.slice(r.offset);
this.waitingResult = true;
this.socket.pause();
//try {
this.msgCb(msg, function() {
// This gets called after msg handler is finished with response.
conn.waitingResult = false;
conn.socket.resume();
if (conn.recvBuf.length > 0) {
conn.appendData("");
}
});
//} catch(e) {
// console.log("FATAL ERROR: ", e);
//}
};
Connection.prototype.writeMessage = function(msgBytes) {
var msgLength = wire.uvarintSize(msgBytes.length);
var buf = new Buffer(1+msgLength+msgBytes.length);
var w = new wire.Writer(buf);
w.writeByteArray(msgBytes); // TODO technically should be writeVarint
this.sendBuf = Buffer.concat([this.sendBuf, w.getBuffer()]);
if (this.sendBuf.length >= maxWriteBufferLength) {
this.flush();
}
};
Connection.prototype.flush = function() {
var n = this.socket.write(this.sendBuf);
this.sendBuf = new Buffer(0);
}
//----------------------------------------
module.exports = { AppServer: AppServer };

+ 27
- 0
example/js/types.js View File

@ -0,0 +1,27 @@
module.exports = {
RetCodeOK: 0,
RetCodeInternalError: 1,
RetCodeUnauthorized: 2,
RetCodeInsufficientFees: 3,
RetCodeUnknownRequest: 4,
RetCodeEncodingError: 5,
RetCodeNonce: 6,
RequestTypeEcho: 0x01,
RequestTypeFlush: 0x02,
RequestTypeInfo: 0x03,
RequestTypeSetOption: 0x04,
RequestTypeAppendTx: 0x21,
RequestTypeCheckTx: 0x22,
RequestTypeGetHash: 0x23,
RequestTypeQuery: 0x24,
ResponseTypeEcho: 0x11,
ResponseTypeFlush: 0x12,
ResponseTypeInfo: 0x13,
ResponseTypeSetOption: 0x14,
ResponseTypeAppendTx: 0x31,
ResponseTypeCheckTx: 0x32,
ResponseTypeGetHash: 0x33,
ResponseTypeQuery: 0x34,
};

+ 0
- 111
example/js/wire.js View File

@ -1,111 +0,0 @@
module.exports = {
decode_string: decode_string,
decode_varint: decode_varint,
decode_big_endian: decode_big_endian,
encode_big_endian: encode_big_endian,
encode: encode,
reverse: reverse,
}
function reverse(buf){
for (var i = 0; i < buf.length/2; i++){
a = buf[i];
b = buf[buf.length-1 - i];
buf[i] = b;
buf[buf.length-1 - i] = a;
}
return buf
}
function uvarint_size(i){
if (i == 0){
return 0
}
for(var j = 1; j < 9; j++) {
if ( i < 1<<j*8 ) {
return j
}
}
return 8
}
function encode_big_endian(i, size){
if (size == 0){
return new Buffer(0);
}
b = encode_big_endian(Math.floor(i/256), size-1);
return Buffer.concat([b, new Buffer([i%256])]);
}
function decode_big_endian(reader, size){
if (size == 0){ return 0 }
firstByte = reader.read(1)[0];
return firstByte*(Math.pow(256, size-1)) + decode_big_endian(reader, size-1)
}
function encode_string(s){
size = encode_varint(s.length);
return Buffer.concat([size, new Buffer(s)])
}
function decode_string(reader){
length = decode_varint(reader);
return reader.read(length).toString()
}
function encode_varint(i){
var negate = false;
if (i < 0){
negate = true;
i = -i;
}
size = uvarint_size(i);
if (size == 0){
return new Buffer([0])
}
big_end = encode_big_endian(i, size);
if (negate){ size += 0xF0 }
var buf = new Buffer([size]);
return Buffer.concat([buf, big_end])
}
function decode_varint(reader){
size = reader.read(1)[0];
if (size == 0 ){
return 0
}
var negate = false;
if (size > 0xF0){ negate = true }
if (negate) { size = size - 0xF0 }
i = decode_big_endian(reader, size);
if (negate) { i = i * -1}
return i
}
function encode_list(l){
var l2 = l.map(encode);
var buf = new Buffer(encode_varint(l2.length));
return Buffer.concat([buf, Buffer.concat(l2)]);
}
function encode(b){
if (b == null){
return Buffer(0)
} else if (typeof b == "number"){
return encode_varint(b)
} else if (typeof b == "string"){
return encode_string(b)
} else if (Array.isArray(b)){
return encode_list(b)
} else{
console.log("UNSUPPORTED TYPE!", typeof b, b)
}
}

+ 1
- 0
example/python/app.py View File

@ -8,6 +8,7 @@ from tmsp.reader import BytesBuffer
class CounterApplication():
def __init__(self):
sys.exit("The python example is out of date. Upgrading the Python examples is currently left as an exercise to you.")
self.hashCount = 0
self.txCount = 0
self.serial = False


+ 1
- 0
example/python3/app.py View File

@ -8,6 +8,7 @@ from tmsp.reader import BytesBuffer
class CounterApplication():
def __init__(self):
sys.exit("The python example is out of date. Upgrading the Python examples is currently left as an exercise to you.")
self.hashCount = 0
self.txCount = 0
self.serial = False


+ 11
- 21
server/server.go View File

@ -99,37 +99,27 @@ func handleRequests(mtx *sync.Mutex, app types.Application, closeConn chan error
func handleRequest(app types.Application, req types.Request, responses chan<- types.Response) {
switch req := req.(type) {
case types.RequestEcho:
msg := app.Echo(req.Message)
responses <- types.ResponseEcho{msg}
responses <- types.ResponseEcho{req.Message}
case types.RequestFlush:
responses <- types.ResponseFlush{}
case types.RequestInfo:
data := app.Info()
responses <- types.ResponseInfo{data}
case types.RequestSetOption:
retCode := app.SetOption(req.Key, req.Value)
responses <- types.ResponseSetOption{retCode}
logstr := app.SetOption(req.Key, req.Value)
responses <- types.ResponseSetOption{logstr}
case types.RequestAppendTx:
events, retCode := app.AppendTx(req.TxBytes)
responses <- types.ResponseAppendTx{retCode}
for _, event := range events {
responses <- types.ResponseEvent{event}
}
code, result, logstr := app.AppendTx(req.TxBytes)
responses <- types.ResponseAppendTx{code, result, logstr}
case types.RequestCheckTx:
retCode := app.CheckTx(req.TxBytes)
responses <- types.ResponseCheckTx{retCode}
code, result, logstr := app.CheckTx(req.TxBytes)
responses <- types.ResponseCheckTx{code, result, logstr}
case types.RequestGetHash:
hash, retCode := app.GetHash()
responses <- types.ResponseGetHash{retCode, hash}
case types.RequestAddListener:
retCode := app.AddListener(req.EventKey)
responses <- types.ResponseAddListener{retCode}
case types.RequestRemListener:
retCode := app.RemListener(req.EventKey)
responses <- types.ResponseRemListener{retCode}
hash, logstr := app.GetHash()
responses <- types.ResponseGetHash{hash, logstr}
case types.RequestQuery:
result, retCode := app.Query(req.QueryBytes)
responses <- types.ResponseQuery{retCode, result}
result, logstr := app.Query(req.QueryBytes)
responses <- types.ResponseQuery{result, logstr}
default:
responses <- types.ResponseException{"Unknown request"}
}


+ 5
- 4
tests/test.sh View File

@ -8,10 +8,11 @@ bash tests/test_dummy.sh
# test golang counter
bash tests/test_counter.sh
# test js counter
cd example/js
COUNTER_APP="node app.js" bash $ROOT/tests/test_counter.sh
# test python counter
cd example/python
cd ../python
COUNTER_APP="python app.py" bash $ROOT/tests/test_counter.sh
# test js counter
cd ../js
COUNTER_APP="node app.js" bash $ROOT/tests/test_counter.sh

+ 11
- 8
tests/test_counter.sh View File

@ -1,3 +1,12 @@
#! /bin/bash
function finish {
echo "Cleaning up..."
ps -p $PID > /dev/null
if [[ "$?" == "0" ]]; then
kill -9 $PID
fi
}
trap finish EXIT
# so we can test other languages
if [[ "$COUNTER_APP" == "" ]]; then
@ -55,21 +64,15 @@ fi
HASH1=`echo "$OUTPUT" | tail -n +3 | head -n 1`
HASH2=`echo "$OUTPUT" | tail -n +5 | head -n 1`
if [[ "${HASH1:0:2}" != "01" ]]; then
if [[ "${HASH1: -2}" != "01" ]]; then
echo "Expected hash to lead with 01. Got $HASH1"
exit 1
fi
if [[ "${HASH2:0:2}" != "02" ]]; then
if [[ "${HASH2: -2}" != "02" ]]; then
echo "Expected hash to lead with 02. Got $HASH2"
exit 1
fi
echo "... Pass!"
echo ""
ps -p $PID > /dev/null
if [[ "$?" == "0" ]]; then
kill -9 $PID
fi

+ 8
- 4
tests/test_dummy.sh View File

@ -1,4 +1,12 @@
#! /bin/bash
function finish {
echo "Cleaning up..."
ps -p $PID > /dev/null
if [[ "$?" == "0" ]]; then
kill -9 $PID
fi
}
trap finish EXIT
# Make sure the tmsp cli can connect to the dummy
echo "Dummy test ..."
@ -51,7 +59,3 @@ if [[ "$HASH1" != "$RESULT_HASH" ]]; then
fi
echo "... Pass!"
echo ""
kill $PID
sleep 1

+ 6
- 15
types/application.go View File

@ -2,30 +2,21 @@ package types
type Application interface {
// Echo a message
Echo(message string) string
// Return application info
Info() []string
Info() (info string)
// Set application option (e.g. mode=mempool, mode=consensus)
SetOption(key string, value string) RetCode
SetOption(key string, value string) (log string)
// Append a tx
AppendTx(tx []byte) ([]Event, RetCode)
AppendTx(tx []byte) (code RetCode, result []byte, log string)
// Validate a tx for the mempool
CheckTx(tx []byte) RetCode
CheckTx(tx []byte) (code RetCode, result []byte, log string)
// Return the application Merkle root hash
GetHash() ([]byte, RetCode)
// Add event listener
AddListener(key string) RetCode
// Remove event listener
RemListener(key string) RetCode
GetHash() (hash []byte, log string)
// Query for state
Query(query []byte) ([]byte, RetCode)
Query(query []byte) (result []byte, log string)
}

+ 0
- 6
types/events.go View File

@ -1,6 +0,0 @@
package types
type Event struct {
Key string
Data []byte
}

+ 10
- 14
types/messages.go View File

@ -86,11 +86,6 @@ var _ = wire.RegisterInterface(
//----------------------------------------
type KVPair struct {
Key []byte
Value []byte
}
type ResponseException struct {
Error string
}
@ -103,32 +98,33 @@ type ResponseFlush struct {
}
type ResponseInfo struct {
Data []string
Info string
}
type ResponseSetOption struct {
Error string
Log string
}
type ResponseAppendTx struct {
RetCode
RetData []KVPair
Error string
Code RetCode
Result []byte
Log string
}
type ResponseCheckTx struct {
RetCode
RetData []KVPair
Error string
Code RetCode
Result []byte
Log string
}
type ResponseGetHash struct {
Hash []byte
Log string
}
type ResponseQuery struct {
Result []byte
Error string
Log string
}
type Response interface {


+ 0
- 13
types/retcode.go View File

@ -1,9 +1,5 @@
package types
import (
"errors"
)
type RetCode int
// Reserved return codes
@ -17,15 +13,6 @@ const (
RetCodeBadNonce RetCode = 6
)
func (r RetCode) Error() error {
switch r {
case RetCodeOK:
return nil
default:
return errors.New(r.String())
}
}
//go:generate stringer -type=RetCode
// NOTE: The previous comment generates r.String().


+ 2
- 2
types/retcode_string.go View File

@ -4,9 +4,9 @@ package types
import "fmt"
const _RetCode_name = "RetCodeOKRetCodeInternalErrorRetCodeUnauthorizedRetCodeInsufficientFeesRetCodeUnknownRequestRetCodeEncodingErrorRetCodeInvalidNonce"
const _RetCode_name = "RetCodeOKRetCodeInternalErrorRetCodeUnauthorizedRetCodeInsufficientFeesRetCodeUnknownRequestRetCodeEncodingErrorRetCodeBadNonce"
var _RetCode_index = [...]uint8{0, 9, 29, 48, 71, 92, 112, 131}
var _RetCode_index = [...]uint8{0, 9, 29, 48, 71, 92, 112, 127}
func (i RetCode) String() string {
if i < 0 || i >= RetCode(len(_RetCode_index)-1) {


Loading…
Cancel
Save