From 781cdbb370bb5c4703508f2236d4b3622b096949 Mon Sep 17 00:00:00 2001 From: androlo <andreas@erisindustries.com> Date: Tue, 4 Aug 2015 05:31:11 +0200 Subject: [PATCH] Tendermint update --- Godeps/Godeps.json | 60 +-- .../syndtr/goleveldb/leveldb/table/reader.go | 2 +- .../syndtr/goleveldb/leveldb/table/writer.go | 2 +- .../gosnappy}/snappy/decode.go | 0 .../gosnappy}/snappy/encode.go | 0 .../gosnappy}/snappy/snappy.go | 0 .../gosnappy}/snappy/snappy_test.go | 0 .../src/github.com/tendermint/log15/format.go | 4 +- .../src/github.com/tendermint/log15/logger.go | 10 + .../src/github.com/tendermint/log15/root.go | 5 + .../src/github.com/tendermint/log15/syslog.go | 2 + .../tendermint/tendermint/account/account.go | 14 +- .../tendermint/account/priv_account.go | 24 +- .../tendermint/tendermint/account/priv_key.go | 40 +- .../tendermint/tendermint/account/pub_key.go | 61 +-- .../tendermint/account/signature.go | 16 +- .../tendermint/account/signature_test.go | 14 +- .../tendermint/tendermint/blockchain/pool.go | 52 +- .../tendermint/blockchain/pool_test.go | 8 +- .../tendermint/blockchain/reactor.go | 78 ++- .../tendermint/tendermint/blockchain/store.go | 56 +-- .../tendermint/tendermint/common/bit_array.go | 2 +- .../tendermint/tendermint/common/byteslice.go | 10 + .../tendermint/tendermint/common/errors.go | 27 + .../tendermint/tendermint/common/random.go | 2 +- .../tendermint/common/repeat_timer.go | 5 + .../tendermint/tendermint/common/service.go | 141 ++++++ .../tendermint/common/throttle_timer.go | 5 + .../tendermint/tendermint/common/word.go | 11 +- .../tendermint/config/tendermint/config.go | 22 +- .../config/tendermint_test/config.go | 4 - .../tendermint/consensus/height_vote_set.go | 11 +- .../tendermint/consensus/reactor.go | 145 +++--- .../tendermint/tendermint/consensus/state.go | 159 +++--- .../tendermint/consensus/types/proposal.go | 22 +- .../consensus/types/proposal_test.go | 5 +- .../tendermint/consensus/vote_set.go | 16 +- .../github.com/tendermint/tendermint/db/db.go | 5 +- .../tendermint/tendermint/db/level_db.go | 12 +- .../tendermint/tendermint/events/events.go | 33 +- .../tendermint/tendermint/events/log.go | 7 + .../tendermint/tendermint/mempool/mempool.go | 16 +- .../tendermint/tendermint/mempool/reactor.go | 43 +- .../tendermint/tendermint/merkle/iavl_node.go | 53 +- .../tendermint/merkle/iavl_proof.go | 30 +- .../tendermint/tendermint/merkle/iavl_test.go | 26 +- .../tendermint/tendermint/merkle/iavl_tree.go | 20 +- .../tendermint/merkle/simple_tree.go | 16 +- .../tendermint/tendermint/node/node.go | 63 ++- .../tendermint/tendermint/node/node_test.go | 30 ++ .../tendermint/tendermint/p2p/README.md | 2 +- .../tendermint/tendermint/p2p/addrbook.go | 61 +-- .../tendermint/tendermint/p2p/connection.go | 185 +++---- .../tendermint/tendermint/p2p/listener.go | 64 ++- .../tendermint/tendermint/p2p/netaddress.go | 13 +- .../tendermint/tendermint/p2p/peer.go | 46 +- .../tendermint/tendermint/p2p/pex_reactor.go | 60 +-- .../tendermint/p2p/secret_connection.go | 59 +-- .../tendermint/p2p/secret_connection_test.go | 12 +- .../tendermint/tendermint/p2p/switch.go | 150 +++--- .../tendermint/tendermint/p2p/switch_test.go | 32 +- .../tendermint/tendermint/p2p/upnp/probe.go | 22 +- .../tendermint/tendermint/p2p/upnp/upnp.go | 6 +- .../permission/types/permissions.go | 74 ++- .../tendermint/permission/types/snatives.go | 113 ++++- .../tendermint/tendermint/rpc/core/blocks.go | 2 +- .../tendermint/rpc/core/consensus.go | 4 +- .../tendermint/tendermint/rpc/core/routes.go | 6 +- .../tendermint/tendermint/rpc/core/txs.go | 45 +- .../tendermint/rpc/core/types/responses.go | 16 +- .../tendermint/rpc/server/handlers.go | 293 ++++++----- .../tendermint/rpc/server/http_params.go | 6 - .../tendermint/rpc/server/http_server.go | 10 +- .../tendermint/tendermint/rpc/types/types.go | 23 +- .../tendermint/state/block_cache.go | 45 +- .../tendermint/tendermint/state/common.go | 4 +- .../tendermint/tendermint/state/execution.go | 374 ++++++++------ .../tendermint/tendermint/state/genesis.go | 24 +- .../tendermint/state/permissions_test.go | 468 +++++++++--------- .../tendermint/state/priv_validator.go | 40 +- .../tendermint/tendermint/state/state.go | 109 ++-- .../tendermint/tendermint/state/test.go | 16 +- .../tendermint/tendermint/state/tx_cache.go | 77 +-- .../tendermint/state/tx_cache_test.go | 22 + .../tendermint/tendermint/state/validator.go | 54 +- .../tendermint/state/validator_set_test.go | 14 +- .../tendermint/tendermint/types/block.go | 10 +- .../tendermint/tendermint/types/events.go | 8 +- .../tendermint/tendermint/types/part_set.go | 11 +- .../tendermint/tendermint/types/tx.go | 149 +++--- .../tendermint/tendermint/types/tx_test.go | 64 ++- .../tendermint/tendermint/types/tx_utils.go | 88 +++- .../tendermint/tendermint/types/vote.go | 24 +- .../tendermint/tendermint/vm/gas.go | 1 + .../tendermint/tendermint/vm/native.go | 30 +- .../tendermint/tendermint/vm/snative.go | 104 ++-- .../tendermint/tendermint/vm/stack.go | 2 +- .../tendermint/vm/test/fake_app_state.go | 9 +- .../tendermint/vm/test/log_event_test.go | 2 +- .../tendermint/tendermint/vm/test/vm_test.go | 6 +- .../tendermint/tendermint/vm/types.go | 20 +- .../github.com/tendermint/tendermint/vm/vm.go | 130 ++--- .../tendermint/{binary => wire}/README.md | 2 +- .../tendermint/{binary => wire}/binary.go | 12 +- .../tendermint/{binary => wire}/byteslice.go | 2 +- .../tendermint/{binary => wire}/codec.go | 11 +- .../tendermint/{binary => wire}/int.go | 2 +- .../tendermint/{binary => wire}/int_test.go | 2 +- .../tendermint/{binary => wire}/log.go | 2 +- .../tendermint/{binary => wire}/reflect.go | 100 ++-- .../{binary => wire}/reflect_test.go | 51 +- .../tendermint/{binary => wire}/string.go | 2 +- .../tendermint/{binary => wire}/time.go | 2 +- .../tendermint/{binary => wire}/util.go | 14 +- api.md | 49 +- erisdb/codec.go | 10 +- erisdb/erisdbss/http.go | 4 +- erisdb/erisdbss/server_manager.go | 4 +- erisdb/methods.go | 1 - erisdb/pipe/accounts.go | 9 +- erisdb/pipe/consensus.go | 4 +- erisdb/pipe/namereg.go | 4 +- erisdb/pipe/pipe.go | 8 +- erisdb/pipe/transactor.go | 29 +- erisdb/serve.go | 4 +- test/mock/mock_web_api_test.go | 3 +- test/mock/pipe.go | 4 +- test/testdata/filters/testdata_filters.go | 32 +- test/testdata/helpers.go | 6 +- test/testdata/testdata/testdata.go | 38 +- 130 files changed, 2792 insertions(+), 2217 deletions(-) rename Godeps/_workspace/src/github.com/{google/go-snappy => syndtr/gosnappy}/snappy/decode.go (100%) rename Godeps/_workspace/src/github.com/{google/go-snappy => syndtr/gosnappy}/snappy/encode.go (100%) rename Godeps/_workspace/src/github.com/{google/go-snappy => syndtr/gosnappy}/snappy/snappy.go (100%) rename Godeps/_workspace/src/github.com/{google/go-snappy => syndtr/gosnappy}/snappy/snappy_test.go (100%) create mode 100644 Godeps/_workspace/src/github.com/tendermint/tendermint/common/service.go create mode 100644 Godeps/_workspace/src/github.com/tendermint/tendermint/events/log.go create mode 100644 Godeps/_workspace/src/github.com/tendermint/tendermint/node/node_test.go create mode 100644 Godeps/_workspace/src/github.com/tendermint/tendermint/state/tx_cache_test.go rename Godeps/_workspace/src/github.com/tendermint/tendermint/{binary => wire}/README.md (99%) rename Godeps/_workspace/src/github.com/tendermint/tendermint/{binary => wire}/binary.go (92%) rename Godeps/_workspace/src/github.com/tendermint/tendermint/{binary => wire}/byteslice.go (98%) rename Godeps/_workspace/src/github.com/tendermint/tendermint/{binary => wire}/codec.go (94%) rename Godeps/_workspace/src/github.com/tendermint/tendermint/{binary => wire}/int.go (99%) rename Godeps/_workspace/src/github.com/tendermint/tendermint/{binary => wire}/int_test.go (99%) rename Godeps/_workspace/src/github.com/tendermint/tendermint/{binary => wire}/log.go (96%) rename Godeps/_workspace/src/github.com/tendermint/tendermint/{binary => wire}/reflect.go (90%) rename Godeps/_workspace/src/github.com/tendermint/tendermint/{binary => wire}/reflect_test.go (88%) rename Godeps/_workspace/src/github.com/tendermint/tendermint/{binary => wire}/string.go (97%) rename Godeps/_workspace/src/github.com/tendermint/tendermint/{binary => wire}/time.go (94%) rename Godeps/_workspace/src/github.com/tendermint/tendermint/{binary => wire}/util.go (87%) diff --git a/Godeps/Godeps.json b/Godeps/Godeps.json index c1ef66ea..54eeae2b 100644 --- a/Godeps/Godeps.json +++ b/Godeps/Godeps.json @@ -24,10 +24,6 @@ "Comment": "v1.0rc1-104-g1a7ab6e", "Rev": "1a7ab6e4d5fdc72d6df30ef562102ae6e0d18518" }, - { - "ImportPath": "github.com/google/go-snappy/snappy", - "Rev": "eaa750b9bf4dcb7cb20454be850613b66cda3273" - }, { "ImportPath": "github.com/gorilla/websocket", "Rev": "a3ec486e6a7a41858210b0fc5d7b5df593b3c4a3" @@ -81,98 +77,102 @@ "ImportPath": "github.com/syndtr/goleveldb/leveldb", "Rev": "a06509502ca32565bdf74afc1e573050023f261c" }, + { + "ImportPath": "github.com/syndtr/gosnappy/snappy", + "Rev": "156a073208e131d7d2e212cb749feae7c339e846" + }, { "ImportPath": "github.com/tendermint/ed25519", "Rev": "533fb6548e2071076888eda3c38749d707ba49bc" }, { "ImportPath": "github.com/tendermint/log15", - "Comment": "v2.3-33-g105a1be", - "Rev": "105a1beefe3379227a0d61733a29fd2c34f7080c" + "Comment": "v2.3-36-gc65281b", + "Rev": "c65281bb703b7612f60558e75b07c434c06e2636" }, { "ImportPath": "github.com/tendermint/tendermint/account", - "Rev": "84705caefb2a288c29447a0506b227ce05363a93" + "Rev": "4ee387d0770ed379e2d524f7077938517b38cd7c" }, { "ImportPath": "github.com/tendermint/tendermint/alert", - "Rev": "84705caefb2a288c29447a0506b227ce05363a93" - }, - { - "ImportPath": "github.com/tendermint/tendermint/binary", - "Rev": "84705caefb2a288c29447a0506b227ce05363a93" + "Rev": "4ee387d0770ed379e2d524f7077938517b38cd7c" }, { "ImportPath": "github.com/tendermint/tendermint/blockchain", - "Rev": "84705caefb2a288c29447a0506b227ce05363a93" + "Rev": "4ee387d0770ed379e2d524f7077938517b38cd7c" }, { "ImportPath": "github.com/tendermint/tendermint/common", - "Rev": "84705caefb2a288c29447a0506b227ce05363a93" + "Rev": "4ee387d0770ed379e2d524f7077938517b38cd7c" }, { "ImportPath": "github.com/tendermint/tendermint/config", - "Rev": "84705caefb2a288c29447a0506b227ce05363a93" + "Rev": "4ee387d0770ed379e2d524f7077938517b38cd7c" }, { "ImportPath": "github.com/tendermint/tendermint/consensus", - "Rev": "84705caefb2a288c29447a0506b227ce05363a93" + "Rev": "4ee387d0770ed379e2d524f7077938517b38cd7c" }, { "ImportPath": "github.com/tendermint/tendermint/db", - "Rev": "84705caefb2a288c29447a0506b227ce05363a93" + "Rev": "4ee387d0770ed379e2d524f7077938517b38cd7c" }, { "ImportPath": "github.com/tendermint/tendermint/events", - "Rev": "84705caefb2a288c29447a0506b227ce05363a93" + "Rev": "4ee387d0770ed379e2d524f7077938517b38cd7c" }, { "ImportPath": "github.com/tendermint/tendermint/logger", - "Rev": "84705caefb2a288c29447a0506b227ce05363a93" + "Rev": "4ee387d0770ed379e2d524f7077938517b38cd7c" }, { "ImportPath": "github.com/tendermint/tendermint/mempool", - "Rev": "84705caefb2a288c29447a0506b227ce05363a93" + "Rev": "4ee387d0770ed379e2d524f7077938517b38cd7c" }, { "ImportPath": "github.com/tendermint/tendermint/merkle", - "Rev": "84705caefb2a288c29447a0506b227ce05363a93" + "Rev": "4ee387d0770ed379e2d524f7077938517b38cd7c" }, { "ImportPath": "github.com/tendermint/tendermint/node", - "Rev": "84705caefb2a288c29447a0506b227ce05363a93" + "Rev": "4ee387d0770ed379e2d524f7077938517b38cd7c" }, { "ImportPath": "github.com/tendermint/tendermint/p2p", - "Rev": "84705caefb2a288c29447a0506b227ce05363a93" + "Rev": "4ee387d0770ed379e2d524f7077938517b38cd7c" }, { "ImportPath": "github.com/tendermint/tendermint/permission/types", - "Rev": "84705caefb2a288c29447a0506b227ce05363a93" + "Rev": "4ee387d0770ed379e2d524f7077938517b38cd7c" }, { "ImportPath": "github.com/tendermint/tendermint/rpc/core", - "Rev": "84705caefb2a288c29447a0506b227ce05363a93" + "Rev": "4ee387d0770ed379e2d524f7077938517b38cd7c" }, { "ImportPath": "github.com/tendermint/tendermint/rpc/server", - "Rev": "84705caefb2a288c29447a0506b227ce05363a93" + "Rev": "4ee387d0770ed379e2d524f7077938517b38cd7c" }, { "ImportPath": "github.com/tendermint/tendermint/rpc/types", - "Rev": "84705caefb2a288c29447a0506b227ce05363a93" + "Rev": "4ee387d0770ed379e2d524f7077938517b38cd7c" }, { "ImportPath": "github.com/tendermint/tendermint/state", - "Rev": "84705caefb2a288c29447a0506b227ce05363a93" + "Rev": "4ee387d0770ed379e2d524f7077938517b38cd7c" }, { "ImportPath": "github.com/tendermint/tendermint/types", - "Rev": "84705caefb2a288c29447a0506b227ce05363a93" + "Rev": "4ee387d0770ed379e2d524f7077938517b38cd7c" }, { "ImportPath": "github.com/tendermint/tendermint/vm", - "Rev": "84705caefb2a288c29447a0506b227ce05363a93" + "Rev": "4ee387d0770ed379e2d524f7077938517b38cd7c" + }, + { + "ImportPath": "github.com/tendermint/tendermint/wire", + "Rev": "4ee387d0770ed379e2d524f7077938517b38cd7c" }, { "ImportPath": "github.com/tommy351/gin-cors", diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/table/reader.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/table/reader.go index 0ed58fb5..f89e6bcd 100644 --- a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/table/reader.go +++ b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/table/reader.go @@ -14,7 +14,7 @@ import ( "strings" "sync" - "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/google/go-snappy/snappy" + "github.com/google/go-snappy/snappy" "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/cache" "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/comparer" diff --git a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/table/writer.go b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/table/writer.go index f656f421..e064e78f 100644 --- a/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/table/writer.go +++ b/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/table/writer.go @@ -12,7 +12,7 @@ import ( "fmt" "io" - "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/google/go-snappy/snappy" + "github.com/google/go-snappy/snappy" "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/comparer" "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/filter" diff --git a/Godeps/_workspace/src/github.com/google/go-snappy/snappy/decode.go b/Godeps/_workspace/src/github.com/syndtr/gosnappy/snappy/decode.go similarity index 100% rename from Godeps/_workspace/src/github.com/google/go-snappy/snappy/decode.go rename to Godeps/_workspace/src/github.com/syndtr/gosnappy/snappy/decode.go diff --git a/Godeps/_workspace/src/github.com/google/go-snappy/snappy/encode.go b/Godeps/_workspace/src/github.com/syndtr/gosnappy/snappy/encode.go similarity index 100% rename from Godeps/_workspace/src/github.com/google/go-snappy/snappy/encode.go rename to Godeps/_workspace/src/github.com/syndtr/gosnappy/snappy/encode.go diff --git a/Godeps/_workspace/src/github.com/google/go-snappy/snappy/snappy.go b/Godeps/_workspace/src/github.com/syndtr/gosnappy/snappy/snappy.go similarity index 100% rename from Godeps/_workspace/src/github.com/google/go-snappy/snappy/snappy.go rename to Godeps/_workspace/src/github.com/syndtr/gosnappy/snappy/snappy.go diff --git a/Godeps/_workspace/src/github.com/google/go-snappy/snappy/snappy_test.go b/Godeps/_workspace/src/github.com/syndtr/gosnappy/snappy/snappy_test.go similarity index 100% rename from Godeps/_workspace/src/github.com/google/go-snappy/snappy/snappy_test.go rename to Godeps/_workspace/src/github.com/syndtr/gosnappy/snappy/snappy_test.go diff --git a/Godeps/_workspace/src/github.com/tendermint/log15/format.go b/Godeps/_workspace/src/github.com/tendermint/log15/format.go index 6ea8c81b..740433b3 100644 --- a/Godeps/_workspace/src/github.com/tendermint/log15/format.go +++ b/Godeps/_workspace/src/github.com/tendermint/log15/format.go @@ -52,8 +52,10 @@ func TerminalFormat() Format { color = 31 case LvlWarn: color = 33 - case LvlInfo: + case LvlNotice: color = 32 + case LvlInfo: + color = 34 case LvlDebug: color = 36 } diff --git a/Godeps/_workspace/src/github.com/tendermint/log15/logger.go b/Godeps/_workspace/src/github.com/tendermint/log15/logger.go index dcd7cf8d..325448d2 100644 --- a/Godeps/_workspace/src/github.com/tendermint/log15/logger.go +++ b/Godeps/_workspace/src/github.com/tendermint/log15/logger.go @@ -17,6 +17,7 @@ const ( LvlCrit Lvl = iota LvlError LvlWarn + LvlNotice LvlInfo LvlDebug ) @@ -28,6 +29,8 @@ func (l Lvl) String() string { return "dbug" case LvlInfo: return "info" + case LvlNotice: + return "notice" case LvlWarn: return "warn" case LvlError: @@ -47,6 +50,8 @@ func LvlFromString(lvlString string) (Lvl, error) { return LvlDebug, nil case "info": return LvlInfo, nil + case "notice", "note": + return LvlNotice, nil case "warn": return LvlWarn, nil case "error", "eror": @@ -85,6 +90,7 @@ type Logger interface { // Log a message at the given level with context key/value pairs Debug(msg string, ctx ...interface{}) Info(msg string, ctx ...interface{}) + Notice(msg string, ctx ...interface{}) Warn(msg string, ctx ...interface{}) Error(msg string, ctx ...interface{}) Crit(msg string, ctx ...interface{}) @@ -133,6 +139,10 @@ func (l *logger) Info(msg string, ctx ...interface{}) { l.write(msg, LvlInfo, ctx) } +func (l *logger) Notice(msg string, ctx ...interface{}) { + l.write(msg, LvlNotice, ctx) +} + func (l *logger) Warn(msg string, ctx ...interface{}) { l.write(msg, LvlWarn, ctx) } diff --git a/Godeps/_workspace/src/github.com/tendermint/log15/root.go b/Godeps/_workspace/src/github.com/tendermint/log15/root.go index 0c442ace..7034447a 100644 --- a/Godeps/_workspace/src/github.com/tendermint/log15/root.go +++ b/Godeps/_workspace/src/github.com/tendermint/log15/root.go @@ -51,6 +51,11 @@ func Info(msg string, ctx ...interface{}) { root.write(msg, LvlInfo, ctx) } +// Notice is a convenient alias for Root().Notice +func Notice(msg string, ctx ...interface{}) { + root.write(msg, LvlNotice, ctx) +} + // Warn is a convenient alias for Root().Warn func Warn(msg string, ctx ...interface{}) { root.write(msg, LvlWarn, ctx) diff --git a/Godeps/_workspace/src/github.com/tendermint/log15/syslog.go b/Godeps/_workspace/src/github.com/tendermint/log15/syslog.go index 36c12b11..4b16e2b2 100644 --- a/Godeps/_workspace/src/github.com/tendermint/log15/syslog.go +++ b/Godeps/_workspace/src/github.com/tendermint/log15/syslog.go @@ -34,6 +34,8 @@ func sharedSyslog(fmtr Format, sysWr *syslog.Writer, err error) (Handler, error) syslogFn = sysWr.Err case LvlWarn: syslogFn = sysWr.Warning + case LvlNotice: + syslogFn = sysWr.Notice case LvlInfo: syslogFn = sysWr.Info case LvlDebug: diff --git a/Godeps/_workspace/src/github.com/tendermint/tendermint/account/account.go b/Godeps/_workspace/src/github.com/tendermint/tendermint/account/account.go index 637417cd..d69be6e7 100644 --- a/Godeps/_workspace/src/github.com/tendermint/tendermint/account/account.go +++ b/Godeps/_workspace/src/github.com/tendermint/tendermint/account/account.go @@ -5,9 +5,10 @@ import ( "fmt" "io" - "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/binary" + . "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/common" "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/merkle" ptypes "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/permission/types" + "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/wire" ) // Signable is an interface for all signable things. @@ -21,8 +22,7 @@ func SignBytes(chainID string, o Signable) []byte { buf, n, err := new(bytes.Buffer), new(int64), new(error) o.WriteSignBytes(chainID, buf, n, err) if *err != nil { - // SOMETHING HAS GONE HORRIBLY WRONG - panic(err) + PanicCrisis(err) } return buf.Bytes() } @@ -36,7 +36,7 @@ func HashSignBytes(chainID string, o Signable) []byte { // Account resides in the application state, and is mutated by transactions // on the blockchain. -// Serialized by binary.[read|write]Reflect +// Serialized by wire.[read|write]Reflect type Account struct { Address []byte `json:"address"` PubKey PubKey `json:"pub_key"` @@ -61,14 +61,14 @@ func (acc *Account) String() string { } func AccountEncoder(o interface{}, w io.Writer, n *int64, err *error) { - binary.WriteBinary(o.(*Account), w, n, err) + wire.WriteBinary(o.(*Account), w, n, err) } func AccountDecoder(r io.Reader, n *int64, err *error) interface{} { - return binary.ReadBinary(&Account{}, r, n, err) + return wire.ReadBinary(&Account{}, r, n, err) } -var AccountCodec = binary.Codec{ +var AccountCodec = wire.Codec{ Encode: AccountEncoder, Decode: AccountDecoder, } diff --git a/Godeps/_workspace/src/github.com/tendermint/tendermint/account/priv_account.go b/Godeps/_workspace/src/github.com/tendermint/tendermint/account/priv_account.go index 36d107b5..42a650e6 100644 --- a/Godeps/_workspace/src/github.com/tendermint/tendermint/account/priv_account.go +++ b/Godeps/_workspace/src/github.com/tendermint/tendermint/account/priv_account.go @@ -2,8 +2,8 @@ package account import ( "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/ed25519" - "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/binary" . "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/common" + "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/wire" ) type PrivAccount struct { @@ -38,8 +38,8 @@ func GenPrivAccount() *PrivAccount { privKeyBytes := new([64]byte) copy(privKeyBytes[:32], CRandBytes(32)) pubKeyBytes := ed25519.MakePublicKey(privKeyBytes) - pubKey := PubKeyEd25519(pubKeyBytes[:]) - privKey := PrivKeyEd25519(privKeyBytes[:]) + pubKey := PubKeyEd25519(*pubKeyBytes) + privKey := PrivKeyEd25519(*privKeyBytes) return &PrivAccount{ Address: pubKey.Address(), PubKey: pubKey, @@ -49,12 +49,12 @@ func GenPrivAccount() *PrivAccount { // Generates a new account with private key from SHA256 hash of a secret func GenPrivAccountFromSecret(secret []byte) *PrivAccount { - privKey32 := binary.BinarySha256(secret) // Not Ripemd160 because we want 32 bytes. + privKey32 := wire.BinarySha256(secret) // Not Ripemd160 because we want 32 bytes. privKeyBytes := new([64]byte) copy(privKeyBytes[:32], privKey32) pubKeyBytes := ed25519.MakePublicKey(privKeyBytes) - pubKey := PubKeyEd25519(pubKeyBytes[:]) - privKey := PrivKeyEd25519(privKeyBytes[:]) + pubKey := PubKeyEd25519(*pubKeyBytes) + privKey := PrivKeyEd25519(*privKeyBytes) return &PrivAccount{ Address: pubKey.Address(), PubKey: pubKey, @@ -62,15 +62,13 @@ func GenPrivAccountFromSecret(secret []byte) *PrivAccount { } } -func GenPrivAccountFromPrivKeyBytes(privKeyBytes []byte) *PrivAccount { +func GenPrivAccountFromPrivKeyBytes(privKeyBytes *[64]byte) *PrivAccount { if len(privKeyBytes) != 64 { - panic(Fmt("Expected 64 bytes but got %v", len(privKeyBytes))) + PanicSanity(Fmt("Expected 64 bytes but got %v", len(privKeyBytes))) } - privKeyBytes64 := [64]byte{} - copy(privKeyBytes64[:], privKeyBytes) - pubKeyBytes := ed25519.MakePublicKey(&privKeyBytes64) - pubKey := PubKeyEd25519(pubKeyBytes[:]) - privKey := PrivKeyEd25519(privKeyBytes) + pubKeyBytes := ed25519.MakePublicKey(privKeyBytes) + pubKey := PubKeyEd25519(*pubKeyBytes) + privKey := PrivKeyEd25519(*privKeyBytes) return &PrivAccount{ Address: pubKey.Address(), PubKey: pubKey, diff --git a/Godeps/_workspace/src/github.com/tendermint/tendermint/account/priv_key.go b/Godeps/_workspace/src/github.com/tendermint/tendermint/account/priv_key.go index 80d54bba..3597060b 100644 --- a/Godeps/_workspace/src/github.com/tendermint/tendermint/account/priv_key.go +++ b/Godeps/_workspace/src/github.com/tendermint/tendermint/account/priv_key.go @@ -3,8 +3,8 @@ package account import ( "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/ed25519" "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/ed25519/extra25519" - "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/binary" . "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/common" + "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/wire" ) // PrivKey is part of PrivAccount and state.PrivValidator. @@ -18,36 +18,32 @@ const ( PrivKeyTypeEd25519 = byte(0x01) ) -// for binary.readReflect -var _ = binary.RegisterInterface( +// for wire.readReflect +var _ = wire.RegisterInterface( struct{ PrivKey }{}, - binary.ConcreteType{PrivKeyEd25519{}, PrivKeyTypeEd25519}, + wire.ConcreteType{PrivKeyEd25519{}, PrivKeyTypeEd25519}, ) //------------------------------------- // Implements PrivKey -type PrivKeyEd25519 []byte +type PrivKeyEd25519 [64]byte func (key PrivKeyEd25519) Sign(msg []byte) Signature { - pubKey := key.PubKey().(PubKeyEd25519) - keyBytes := new([64]byte) - copy(keyBytes[:32], key[:]) - copy(keyBytes[32:], pubKey[:]) - signatureBytes := ed25519.Sign(keyBytes, msg) - return SignatureEd25519(signatureBytes[:]) + privKeyBytes := [64]byte(key) + signatureBytes := ed25519.Sign(&privKeyBytes, msg) + return SignatureEd25519(*signatureBytes) } func (privKey PrivKeyEd25519) PubKey() PubKey { - privKeyBytes := new([64]byte) - copy(privKeyBytes[:], privKey[:]) - return PubKeyEd25519(ed25519.MakePublicKey(privKeyBytes)[:]) + privKeyBytes := [64]byte(privKey) + return PubKeyEd25519(*ed25519.MakePublicKey(&privKeyBytes)) } func (privKey PrivKeyEd25519) ToCurve25519() *[32]byte { - keyEd25519, keyCurve25519 := new([64]byte), new([32]byte) - copy(keyEd25519[:], privKey) - extra25519.PrivateKeyToCurve25519(keyCurve25519, keyEd25519) + keyCurve25519 := new([32]byte) + privKeyBytes := [64]byte(privKey) + extra25519.PrivateKeyToCurve25519(keyCurve25519, &privKeyBytes) return keyCurve25519 } @@ -57,16 +53,18 @@ func (privKey PrivKeyEd25519) String() string { // Deterministically generates new priv-key bytes from key. func (key PrivKeyEd25519) Generate(index int) PrivKeyEd25519 { - newBytes := binary.BinarySha256(struct { - PrivKey []byte + newBytes := wire.BinarySha256(struct { + PrivKey [64]byte Index int }{key, index}) - return PrivKeyEd25519(newBytes) + var newKey [64]byte + copy(newKey[:], newBytes) + return PrivKeyEd25519(newKey) } func GenPrivKeyEd25519() PrivKeyEd25519 { privKeyBytes := new([64]byte) copy(privKeyBytes[:32], CRandBytes(32)) ed25519.MakePublicKey(privKeyBytes) - return PrivKeyEd25519(privKeyBytes[:]) + return PrivKeyEd25519(*privKeyBytes) } diff --git a/Godeps/_workspace/src/github.com/tendermint/tendermint/account/pub_key.go b/Godeps/_workspace/src/github.com/tendermint/tendermint/account/pub_key.go index 28eabe1f..c4bdc328 100644 --- a/Godeps/_workspace/src/github.com/tendermint/tendermint/account/pub_key.go +++ b/Godeps/_workspace/src/github.com/tendermint/tendermint/account/pub_key.go @@ -2,17 +2,16 @@ package account import ( "bytes" - "errors" "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/ed25519" "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/ed25519/extra25519" - "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/binary" . "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/common" + "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/wire" + "github.com/eris-ltd/eris-db/Godeps/_workspace/src/golang.org/x/crypto/ripemd160" ) // PubKey is part of Account and Validator. type PubKey interface { - IsNil() bool Address() []byte VerifyBytes(msg []byte, sig Signature) bool } @@ -22,21 +21,33 @@ const ( PubKeyTypeEd25519 = byte(0x01) ) -// for binary.readReflect -var _ = binary.RegisterInterface( +// for wire.readReflect +var _ = wire.RegisterInterface( struct{ PubKey }{}, - binary.ConcreteType{PubKeyEd25519{}, PubKeyTypeEd25519}, + wire.ConcreteType{PubKeyEd25519{}, PubKeyTypeEd25519}, ) //------------------------------------- // Implements PubKey -type PubKeyEd25519 []byte +type PubKeyEd25519 [32]byte -func (pubKey PubKeyEd25519) IsNil() bool { return false } - -// TODO: Or should this just be BinaryRipemd160(key)? (The difference is the TypeByte.) -func (pubKey PubKeyEd25519) Address() []byte { return binary.BinaryRipemd160(pubKey) } +// TODO: Slicing the array gives us length prefixing but loses the type byte. +// Revisit if we add more pubkey types. +// For now, we artificially append the type byte in front to give us backwards +// compatibility for when the pubkey wasn't fixed length array +func (pubKey PubKeyEd25519) Address() []byte { + w, n, err := new(bytes.Buffer), new(int64), new(error) + wire.WriteBinary(pubKey[:], w, n, err) + if *err != nil { + PanicCrisis(*err) + } + // append type byte + encodedPubkey := append([]byte{1}, w.Bytes()...) + hasher := ripemd160.New() + hasher.Write(encodedPubkey) // does not error + return hasher.Sum(nil) +} // TODO: Consider returning a reason for failure, or logging a runtime type mismatch. func (pubKey PubKeyEd25519) VerifyBytes(msg []byte, sig_ Signature) bool { @@ -44,45 +55,35 @@ func (pubKey PubKeyEd25519) VerifyBytes(msg []byte, sig_ Signature) bool { if !ok { return false } - pubKeyBytes := new([32]byte) - copy(pubKeyBytes[:], pubKey) - sigBytes := new([64]byte) - copy(sigBytes[:], sig) - return ed25519.Verify(pubKeyBytes, msg, sigBytes) + pubKeyBytes := [32]byte(pubKey) + sigBytes := [64]byte(sig) + return ed25519.Verify(&pubKeyBytes, msg, &sigBytes) } // For use with golang/crypto/nacl/box // If error, returns nil. func (pubKey PubKeyEd25519) ToCurve25519() *[32]byte { - keyEd25519, keyCurve25519 := new([32]byte), new([32]byte) - copy(keyEd25519[:], pubKey) - ok := extra25519.PublicKeyToCurve25519(keyCurve25519, keyEd25519) + keyCurve25519, pubKeyBytes := new([32]byte), [32]byte(pubKey) + ok := extra25519.PublicKeyToCurve25519(keyCurve25519, &pubKeyBytes) if !ok { return nil } return keyCurve25519 } -func (pubKey PubKeyEd25519) ValidateBasic() error { - if len(pubKey) != ed25519.PublicKeySize { - return errors.New("Invalid PubKeyEd25519 key size") - } - return nil -} - func (pubKey PubKeyEd25519) String() string { - return Fmt("PubKeyEd25519{%X}", []byte(pubKey)) + return Fmt("PubKeyEd25519{%X}", pubKey[:]) } // Must return the full bytes in hex. // Used for map keying, etc. func (pubKey PubKeyEd25519) KeyString() string { - return Fmt("%X", []byte(pubKey)) + return Fmt("%X", pubKey[:]) } func (pubKey PubKeyEd25519) Equals(other PubKey) bool { - if _, ok := other.(PubKeyEd25519); ok { - return bytes.Equal(pubKey, other.(PubKeyEd25519)) + if otherEd, ok := other.(PubKeyEd25519); ok { + return bytes.Equal(pubKey[:], otherEd[:]) } else { return false } diff --git a/Godeps/_workspace/src/github.com/tendermint/tendermint/account/signature.go b/Godeps/_workspace/src/github.com/tendermint/tendermint/account/signature.go index 0e0e18d4..2c0b816c 100644 --- a/Godeps/_workspace/src/github.com/tendermint/tendermint/account/signature.go +++ b/Godeps/_workspace/src/github.com/tendermint/tendermint/account/signature.go @@ -3,12 +3,14 @@ package account import ( "fmt" - "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/binary" . "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/common" + "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/wire" ) // Signature is a part of Txs and consensus Votes. type Signature interface { + IsZero() bool + String() string } // Types of Signature implementations @@ -16,19 +18,17 @@ const ( SignatureTypeEd25519 = byte(0x01) ) -// for binary.readReflect -var _ = binary.RegisterInterface( +// for wire.readReflect +var _ = wire.RegisterInterface( struct{ Signature }{}, - binary.ConcreteType{SignatureEd25519{}, SignatureTypeEd25519}, + wire.ConcreteType{SignatureEd25519{}, SignatureTypeEd25519}, ) //------------------------------------- // Implements Signature -type SignatureEd25519 []byte - -func (sig SignatureEd25519) IsNil() bool { return false } +type SignatureEd25519 [64]byte func (sig SignatureEd25519) IsZero() bool { return len(sig) == 0 } -func (sig SignatureEd25519) String() string { return fmt.Sprintf("/%X.../", Fingerprint(sig)) } +func (sig SignatureEd25519) String() string { return fmt.Sprintf("/%X.../", Fingerprint(sig[:])) } diff --git a/Godeps/_workspace/src/github.com/tendermint/tendermint/account/signature_test.go b/Godeps/_workspace/src/github.com/tendermint/tendermint/account/signature_test.go index edd87450..8c08dde8 100644 --- a/Godeps/_workspace/src/github.com/tendermint/tendermint/account/signature_test.go +++ b/Godeps/_workspace/src/github.com/tendermint/tendermint/account/signature_test.go @@ -5,8 +5,8 @@ import ( "testing" "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/ed25519" - "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/binary" . "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/common" + "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/wire" ) func TestSignAndValidate(t *testing.T) { @@ -25,7 +25,9 @@ func TestSignAndValidate(t *testing.T) { } // Mutate the signature, just one bit. - sig.(SignatureEd25519)[0] ^= byte(0x01) + sigEd := sig.(SignatureEd25519) + sigEd[0] ^= byte(0x01) + sig = Signature(sigEd) if pubKey.VerifyBytes(msg, sig) { t.Errorf("Account message signature verification should have failed but passed instead") @@ -43,20 +45,20 @@ func TestBinaryDecode(t *testing.T) { t.Logf("msg: %X, sig: %X", msg, sig) buf, n, err := new(bytes.Buffer), new(int64), new(error) - binary.WriteBinary(sig, buf, n, err) + wire.WriteBinary(sig, buf, n, err) if *err != nil { t.Fatalf("Failed to write Signature: %v", err) } - if len(buf.Bytes()) != ed25519.SignatureSize+3 { - // 1 byte TypeByte, 2 bytes length, 64 bytes signature bytes + if len(buf.Bytes()) != ed25519.SignatureSize+1 { + // 1 byte TypeByte, 64 bytes signature bytes t.Fatalf("Unexpected signature write size: %v", len(buf.Bytes())) } if buf.Bytes()[0] != SignatureTypeEd25519 { t.Fatalf("Unexpected signature type byte") } - sig2, ok := binary.ReadBinary(SignatureEd25519{}, buf, n, err).(SignatureEd25519) + sig2, ok := wire.ReadBinary(SignatureEd25519{}, buf, n, err).(SignatureEd25519) if !ok || *err != nil { t.Fatalf("Failed to read Signature: %v", err) } diff --git a/Godeps/_workspace/src/github.com/tendermint/tendermint/blockchain/pool.go b/Godeps/_workspace/src/github.com/tendermint/tendermint/blockchain/pool.go index 9d42f204..95b33b88 100644 --- a/Godeps/_workspace/src/github.com/tendermint/tendermint/blockchain/pool.go +++ b/Godeps/_workspace/src/github.com/tendermint/tendermint/blockchain/pool.go @@ -2,7 +2,6 @@ package blockchain import ( "sync" - "sync/atomic" "time" . "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/common" @@ -34,6 +33,8 @@ var ( */ type BlockPool struct { + BaseService + // block requests requestsMtx sync.Mutex requests map[int]*bpRequest @@ -48,12 +49,10 @@ type BlockPool struct { requestsCh chan<- BlockRequest timeoutsCh chan<- string repeater *RepeatTimer - - running int32 // atomic } func NewBlockPool(start int, requestsCh chan<- BlockRequest, timeoutsCh chan<- string) *BlockPool { - return &BlockPool{ + bp := &BlockPool{ peers: make(map[string]*bpPeer), requests: make(map[int]*bpRequest), @@ -63,35 +62,28 @@ func NewBlockPool(start int, requestsCh chan<- BlockRequest, timeoutsCh chan<- s requestsCh: requestsCh, timeoutsCh: timeoutsCh, - repeater: NewRepeatTimer("", requestIntervalMS*time.Millisecond), - - running: 0, + repeater: nil, } + bp.BaseService = *NewBaseService(log, "BlockPool", bp) + return bp } -func (pool *BlockPool) Start() { - if atomic.CompareAndSwapInt32(&pool.running, 0, 1) { - log.Info("Starting BlockPool") - go pool.run() - } -} - -func (pool *BlockPool) Stop() { - if atomic.CompareAndSwapInt32(&pool.running, 1, 0) { - log.Info("Stopping BlockPool") - pool.repeater.Stop() - } +func (pool *BlockPool) OnStart() { + pool.BaseService.OnStart() + pool.repeater = NewRepeatTimer("", requestIntervalMS*time.Millisecond) + go pool.run() } -func (pool *BlockPool) IsRunning() bool { - return atomic.LoadInt32(&pool.running) == 1 +func (pool *BlockPool) OnStop() { + pool.BaseService.OnStop() + pool.repeater.Stop() } // Run spawns requests as needed. func (pool *BlockPool) run() { RUN_LOOP: for { - if atomic.LoadInt32(&pool.running) == 0 { + if !pool.IsRunning() { break RUN_LOOP } _, numPending, _ := pool.GetStatus() @@ -136,11 +128,9 @@ func (pool *BlockPool) PopRequest() { pool.requestsMtx.Lock() // Lock defer pool.requestsMtx.Unlock() - // SANITY CHECK if r := pool.requests[pool.height]; r == nil || r.block == nil { - panic("PopRequest() requires a valid block") + PanicSanity("PopRequest() requires a valid block") } - // SANITY CHECK END delete(pool.requests, pool.height) pool.height++ @@ -153,11 +143,9 @@ func (pool *BlockPool) RedoRequest(height int) { defer pool.requestsMtx.Unlock() request := pool.requests[height] - // SANITY CHECK if request.block == nil { - panic("Expected block to be non-nil") + PanicSanity("Expected block to be non-nil") } - // SANITY CHECK END // TODO: record this malfeasance // maybe punish peer on switch (an invalid block!) pool.RemovePeer(request.peerId) // Lock on peersMtx. @@ -301,14 +289,14 @@ func (pool *BlockPool) makeNextRequest() { } func (pool *BlockPool) sendRequest(height int, peerId string) { - if atomic.LoadInt32(&pool.running) == 0 { + if !pool.IsRunning() { return } pool.requestsCh <- BlockRequest{height, peerId} } func (pool *BlockPool) sendTimeout(peerId string) { - if atomic.LoadInt32(&pool.running) == 0 { + if !pool.IsRunning() { return } pool.timeoutsCh <- peerId @@ -354,12 +342,12 @@ func requestRoutine(pool *BlockPool, height int) { PICK_LOOP: for { if !pool.IsRunning() { - log.Debug("BlockPool not running. Stopping requestRoutine", "height", height) + log.Info("BlockPool not running. Stopping requestRoutine", "height", height) return } peer = pool.pickIncrAvailablePeer(height) if peer == nil { - //log.Debug("No peers available", "height", height) + //log.Info("No peers available", "height", height) time.Sleep(requestIntervalMS * time.Millisecond) continue PICK_LOOP } diff --git a/Godeps/_workspace/src/github.com/tendermint/tendermint/blockchain/pool_test.go b/Godeps/_workspace/src/github.com/tendermint/tendermint/blockchain/pool_test.go index 7e8f2f04..33840b49 100644 --- a/Godeps/_workspace/src/github.com/tendermint/tendermint/blockchain/pool_test.go +++ b/Godeps/_workspace/src/github.com/tendermint/tendermint/blockchain/pool_test.go @@ -60,7 +60,7 @@ func TestBasic(t *testing.T) { case peerId := <-timeoutsCh: t.Errorf("timeout: %v", peerId) case request := <-requestsCh: - log.Debug("TEST: Pulled new BlockRequest", "request", request) + log.Info("TEST: Pulled new BlockRequest", "request", request) if request.Height == 300 { return // Done! } @@ -68,7 +68,7 @@ func TestBasic(t *testing.T) { go func() { block := &types.Block{Header: &types.Header{Height: request.Height}} pool.AddBlock(block, request.PeerId) - log.Debug("TEST: Added block", "block", request.Height, "peer", request.PeerId) + log.Info("TEST: Added block", "block", request.Height, "peer", request.PeerId) }() } } @@ -112,7 +112,7 @@ func TestTimeout(t *testing.T) { for { select { case peerId := <-timeoutsCh: - log.Debug("Timeout", "peerId", peerId) + log.Info("Timeout", "peerId", peerId) if _, ok := timedOut[peerId]; !ok { counter++ if counter == len(peers) { @@ -120,7 +120,7 @@ func TestTimeout(t *testing.T) { } } case request := <-requestsCh: - log.Debug("TEST: Pulled new BlockRequest", "request", request) + log.Info("TEST: Pulled new BlockRequest", "request", request) } } diff --git a/Godeps/_workspace/src/github.com/tendermint/tendermint/blockchain/reactor.go b/Godeps/_workspace/src/github.com/tendermint/tendermint/blockchain/reactor.go index 40d55e04..c9cfc5b7 100644 --- a/Godeps/_workspace/src/github.com/tendermint/tendermint/blockchain/reactor.go +++ b/Godeps/_workspace/src/github.com/tendermint/tendermint/blockchain/reactor.go @@ -5,15 +5,14 @@ import ( "errors" "fmt" "reflect" - "sync/atomic" "time" - "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/binary" . "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/common" "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/events" "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/p2p" sm "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/state" "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/types" + "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/wire" ) const ( @@ -39,6 +38,8 @@ type consensusReactor interface { // BlockchainReactor handles long-term catchup syncing. type BlockchainReactor struct { + p2p.BaseReactor + sw *p2p.Switch state *sm.State store *BlockStore @@ -47,19 +48,15 @@ type BlockchainReactor struct { requestsCh chan BlockRequest timeoutsCh chan string lastBlock *types.Block - quit chan struct{} - running uint32 evsw events.Fireable } func NewBlockchainReactor(state *sm.State, store *BlockStore, sync bool) *BlockchainReactor { - // SANITY CHECK if state.LastBlockHeight != store.Height() && state.LastBlockHeight != store.Height()-1 { // XXX double check this logic. - panic(Fmt("state (%v) and store (%v) height mismatch", state.LastBlockHeight, store.Height())) + PanicSanity(Fmt("state (%v) and store (%v) height mismatch", state.LastBlockHeight, store.Height())) } - // SANITY CHECK END requestsCh := make(chan BlockRequest, defaultChannelCapacity) timeoutsCh := make(chan string, defaultChannelCapacity) pool := NewBlockPool( @@ -74,31 +71,22 @@ func NewBlockchainReactor(state *sm.State, store *BlockStore, sync bool) *Blockc sync: sync, requestsCh: requestsCh, timeoutsCh: timeoutsCh, - quit: make(chan struct{}), - running: uint32(0), } + bcR.BaseReactor = *p2p.NewBaseReactor(log, "BlockchainReactor", bcR) return bcR } -// Implements Reactor -func (bcR *BlockchainReactor) Start(sw *p2p.Switch) { - if atomic.CompareAndSwapUint32(&bcR.running, 0, 1) { - log.Info("Starting BlockchainReactor") - bcR.sw = sw - if bcR.sync { - bcR.pool.Start() - go bcR.poolRoutine() - } +func (bcR *BlockchainReactor) OnStart() { + bcR.BaseReactor.OnStart() + if bcR.sync { + bcR.pool.Start() + go bcR.poolRoutine() } } -// Implements Reactor -func (bcR *BlockchainReactor) Stop() { - if atomic.CompareAndSwapUint32(&bcR.running, 1, 0) { - log.Info("Stopping BlockchainReactor") - close(bcR.quit) - bcR.pool.Stop() - } +func (bcR *BlockchainReactor) OnStop() { + bcR.BaseReactor.OnStop() + bcR.pool.Stop() } // Implements Reactor @@ -132,7 +120,7 @@ func (bcR *BlockchainReactor) Receive(chId byte, src *p2p.Peer, msgBytes []byte) return } - log.Info("Received message", "msg", msg) + log.Notice("Received message", "msg", msg) switch msg := msg.(type) { case *bcBlockRequestMessage: @@ -177,7 +165,7 @@ FOR_LOOP: for { select { case request := <-bcR.requestsCh: // chan BlockRequest - peer := bcR.sw.Peers().Get(request.PeerId) + peer := bcR.Switch.Peers().Get(request.PeerId) if peer == nil { // We can't assign the request. continue FOR_LOOP @@ -191,17 +179,17 @@ FOR_LOOP: } case peerId := <-bcR.timeoutsCh: // chan string // Peer timed out. - peer := bcR.sw.Peers().Get(peerId) + peer := bcR.Switch.Peers().Get(peerId) if peer != nil { - bcR.sw.StopPeerForError(peer, errors.New("BlockchainReactor Timeout")) + bcR.Switch.StopPeerForError(peer, errors.New("BlockchainReactor Timeout")) } case _ = <-statusUpdateTicker.C: // ask for status updates go bcR.BroadcastStatusRequest() case _ = <-switchToConsensusTicker.C: height, numPending, numUnassigned := bcR.pool.GetStatus() - outbound, inbound, _ := bcR.sw.NumPeers() - log.Debug("Consensus ticker", "numUnassigned", numUnassigned, "numPending", numPending, + outbound, inbound, _ := bcR.Switch.NumPeers() + log.Info("Consensus ticker", "numUnassigned", numUnassigned, "numPending", numPending, "total", len(bcR.pool.requests), "outbound", outbound, "inbound", inbound) // NOTE: this condition is very strict right now. may need to weaken // If all `maxPendingRequests` requests are unassigned @@ -210,10 +198,10 @@ FOR_LOOP: allUnassigned := numPending == numUnassigned enoughPeers := outbound+inbound >= 3 if maxPending && allUnassigned && enoughPeers { - log.Info("Time to switch to consensus reactor!", "height", height) + log.Notice("Time to switch to consensus reactor!", "height", height) bcR.pool.Stop() - conR := bcR.sw.Reactor("CONSENSUS").(consensusReactor) + conR := bcR.Switch.Reactor("CONSENSUS").(consensusReactor) conR.SwitchToConsensus(bcR.state) break FOR_LOOP @@ -224,7 +212,7 @@ FOR_LOOP: for i := 0; i < 10; i++ { // See if there are any blocks to sync. first, second := bcR.pool.PeekTwoBlocks() - //log.Debug("TrySync peeked", "first", first, "second", second) + //log.Info("TrySync peeked", "first", first, "second", second) if first == nil || second == nil { // We need both to sync the first block. break SYNC_LOOP @@ -235,7 +223,7 @@ FOR_LOOP: err := bcR.state.BondedValidators.VerifyValidation( bcR.state.ChainID, first.Hash(), firstPartsHeader, first.Height, second.LastValidation) if err != nil { - log.Debug("error in validation", "error", err) + log.Info("error in validation", "error", err) bcR.pool.RedoRequest(first.Height) break SYNC_LOOP } else { @@ -243,26 +231,26 @@ FOR_LOOP: err := sm.ExecBlock(bcR.state, first, firstPartsHeader) if err != nil { // TODO This is bad, are we zombie? - panic(Fmt("Failed to process committed block: %v", err)) + PanicQ(Fmt("Failed to process committed block: %v", err)) } bcR.store.SaveBlock(first, firstParts, second.LastValidation) bcR.state.Save() } } continue FOR_LOOP - case <-bcR.quit: + case <-bcR.Quit: break FOR_LOOP } } } func (bcR *BlockchainReactor) BroadcastStatusResponse() error { - bcR.sw.Broadcast(BlockchainChannel, &bcStatusResponseMessage{bcR.store.Height()}) + bcR.Switch.Broadcast(BlockchainChannel, &bcStatusResponseMessage{bcR.store.Height()}) return nil } func (bcR *BlockchainReactor) BroadcastStatusRequest() error { - bcR.sw.Broadcast(BlockchainChannel, &bcStatusRequestMessage{bcR.store.Height()}) + bcR.Switch.Broadcast(BlockchainChannel, &bcStatusRequestMessage{bcR.store.Height()}) return nil } @@ -283,19 +271,19 @@ const ( type BlockchainMessage interface{} -var _ = binary.RegisterInterface( +var _ = wire.RegisterInterface( struct{ BlockchainMessage }{}, - binary.ConcreteType{&bcBlockRequestMessage{}, msgTypeBlockRequest}, - binary.ConcreteType{&bcBlockResponseMessage{}, msgTypeBlockResponse}, - binary.ConcreteType{&bcStatusResponseMessage{}, msgTypeStatusResponse}, - binary.ConcreteType{&bcStatusRequestMessage{}, msgTypeStatusRequest}, + wire.ConcreteType{&bcBlockRequestMessage{}, msgTypeBlockRequest}, + wire.ConcreteType{&bcBlockResponseMessage{}, msgTypeBlockResponse}, + wire.ConcreteType{&bcStatusResponseMessage{}, msgTypeStatusResponse}, + wire.ConcreteType{&bcStatusRequestMessage{}, msgTypeStatusRequest}, ) func DecodeMessage(bz []byte) (msgType byte, msg BlockchainMessage, err error) { msgType = bz[0] n := new(int64) r := bytes.NewReader(bz) - msg = binary.ReadBinary(struct{ BlockchainMessage }{}, r, n, &err).(struct{ BlockchainMessage }).BlockchainMessage + msg = wire.ReadBinary(struct{ BlockchainMessage }{}, r, n, &err).(struct{ BlockchainMessage }).BlockchainMessage return } diff --git a/Godeps/_workspace/src/github.com/tendermint/tendermint/blockchain/store.go b/Godeps/_workspace/src/github.com/tendermint/tendermint/blockchain/store.go index 33e92d3a..d56b606d 100644 --- a/Godeps/_workspace/src/github.com/tendermint/tendermint/blockchain/store.go +++ b/Godeps/_workspace/src/github.com/tendermint/tendermint/blockchain/store.go @@ -6,10 +6,10 @@ import ( "fmt" "io" - "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/binary" . "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/common" dbm "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/db" "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/types" + "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/wire" ) /* @@ -59,20 +59,18 @@ func (bs *BlockStore) LoadBlock(height int) *types.Block { if r == nil { return nil } - meta := binary.ReadBinary(&types.BlockMeta{}, r, &n, &err).(*types.BlockMeta) + meta := wire.ReadBinary(&types.BlockMeta{}, r, &n, &err).(*types.BlockMeta) if err != nil { - // SOMETHING HAS GONE HORRIBLY WRONG - panic(Fmt("Error reading block meta: %v", err)) + PanicCrisis(Fmt("Error reading block meta: %v", err)) } bytez := []byte{} for i := 0; i < meta.PartsHeader.Total; i++ { part := bs.LoadBlockPart(height, i) bytez = append(bytez, part.Bytes...) } - block := binary.ReadBinary(&types.Block{}, bytes.NewReader(bytez), &n, &err).(*types.Block) + block := wire.ReadBinary(&types.Block{}, bytes.NewReader(bytez), &n, &err).(*types.Block) if err != nil { - // SOMETHING HAS GONE HORRIBLY WRONG - panic(Fmt("Error reading block: %v", err)) + PanicCrisis(Fmt("Error reading block: %v", err)) } return block } @@ -84,10 +82,9 @@ func (bs *BlockStore) LoadBlockPart(height int, index int) *types.Part { if r == nil { return nil } - part := binary.ReadBinary(&types.Part{}, r, &n, &err).(*types.Part) + part := wire.ReadBinary(&types.Part{}, r, &n, &err).(*types.Part) if err != nil { - // SOMETHING HAS GONE HORRIBLY WRONG - panic(Fmt("Error reading block part: %v", err)) + PanicCrisis(Fmt("Error reading block part: %v", err)) } return part } @@ -99,10 +96,9 @@ func (bs *BlockStore) LoadBlockMeta(height int) *types.BlockMeta { if r == nil { return nil } - meta := binary.ReadBinary(&types.BlockMeta{}, r, &n, &err).(*types.BlockMeta) + meta := wire.ReadBinary(&types.BlockMeta{}, r, &n, &err).(*types.BlockMeta) if err != nil { - // SOMETHING HAS GONE HORRIBLY WRONG - panic(Fmt("Error reading block meta: %v", err)) + PanicCrisis(Fmt("Error reading block meta: %v", err)) } return meta } @@ -116,10 +112,9 @@ func (bs *BlockStore) LoadBlockValidation(height int) *types.Validation { if r == nil { return nil } - validation := binary.ReadBinary(&types.Validation{}, r, &n, &err).(*types.Validation) + validation := wire.ReadBinary(&types.Validation{}, r, &n, &err).(*types.Validation) if err != nil { - // SOMETHING HAS GONE HORRIBLY WRONG - panic(Fmt("Error reading validation: %v", err)) + PanicCrisis(Fmt("Error reading validation: %v", err)) } return validation } @@ -132,10 +127,9 @@ func (bs *BlockStore) LoadSeenValidation(height int) *types.Validation { if r == nil { return nil } - validation := binary.ReadBinary(&types.Validation{}, r, &n, &err).(*types.Validation) + validation := wire.ReadBinary(&types.Validation{}, r, &n, &err).(*types.Validation) if err != nil { - // SOMETHING HAS GONE HORRIBLY WRONG - panic(Fmt("Error reading validation: %v", err)) + PanicCrisis(Fmt("Error reading validation: %v", err)) } return validation } @@ -148,17 +142,15 @@ func (bs *BlockStore) LoadSeenValidation(height int) *types.Validation { func (bs *BlockStore) SaveBlock(block *types.Block, blockParts *types.PartSet, seenValidation *types.Validation) { height := block.Height if height != bs.height+1 { - // SANITY CHECK - panic(Fmt("BlockStore can only save contiguous blocks. Wanted %v, got %v", bs.height+1, height)) + PanicSanity(Fmt("BlockStore can only save contiguous blocks. Wanted %v, got %v", bs.height+1, height)) } if !blockParts.IsComplete() { - // SANITY CHECK - panic(Fmt("BlockStore can only save complete block part sets")) + PanicSanity(Fmt("BlockStore can only save complete block part sets")) } // Save block meta meta := types.NewBlockMeta(block, blockParts) - metaBytes := binary.BinaryBytes(meta) + metaBytes := wire.BinaryBytes(meta) bs.db.Set(calcBlockMetaKey(height), metaBytes) // Save block parts @@ -167,11 +159,11 @@ func (bs *BlockStore) SaveBlock(block *types.Block, blockParts *types.PartSet, s } // Save block validation (duplicate and separate from the Block) - blockValidationBytes := binary.BinaryBytes(block.LastValidation) + blockValidationBytes := wire.BinaryBytes(block.LastValidation) bs.db.Set(calcBlockValidationKey(height-1), blockValidationBytes) // Save seen validation (seen +2/3 precommits for block) - seenValidationBytes := binary.BinaryBytes(seenValidation) + seenValidationBytes := wire.BinaryBytes(seenValidation) bs.db.Set(calcSeenValidationKey(height), seenValidationBytes) // Save new BlockStoreStateJSON descriptor @@ -182,12 +174,10 @@ func (bs *BlockStore) SaveBlock(block *types.Block, blockParts *types.PartSet, s } func (bs *BlockStore) saveBlockPart(height int, index int, part *types.Part) { - // SANITY CHECK if height != bs.height+1 { - panic(Fmt("BlockStore can only save contiguous blocks. Wanted %v, got %v", bs.height+1, height)) + PanicSanity(Fmt("BlockStore can only save contiguous blocks. Wanted %v, got %v", bs.height+1, height)) } - // SANITY CHECK END - partBytes := binary.BinaryBytes(part) + partBytes := wire.BinaryBytes(part) bs.db.Set(calcBlockPartKey(height, index), partBytes) } @@ -220,8 +210,7 @@ type BlockStoreStateJSON struct { func (bsj BlockStoreStateJSON) Save(db dbm.DB) { bytes, err := json.Marshal(bsj) if err != nil { - // SANITY CHECK - panic(Fmt("Could not marshal state bytes: %v", err)) + PanicSanity(Fmt("Could not marshal state bytes: %v", err)) } db.Set(blockStoreKey, bytes) } @@ -236,8 +225,7 @@ func LoadBlockStoreStateJSON(db dbm.DB) BlockStoreStateJSON { bsj := BlockStoreStateJSON{} err := json.Unmarshal(bytes, &bsj) if err != nil { - // SOMETHING HAS GONE HORRIBLY WRONG - panic(Fmt("Could not unmarshal bytes: %X", bytes)) + PanicCrisis(Fmt("Could not unmarshal bytes: %X", bytes)) } return bsj } diff --git a/Godeps/_workspace/src/github.com/tendermint/tendermint/common/bit_array.go b/Godeps/_workspace/src/github.com/tendermint/tendermint/common/bit_array.go index 320b629e..dc006f0e 100644 --- a/Godeps/_workspace/src/github.com/tendermint/tendermint/common/bit_array.go +++ b/Godeps/_workspace/src/github.com/tendermint/tendermint/common/bit_array.go @@ -209,7 +209,7 @@ func (bA *BitArray) PickRandom() (int, bool) { return 64*elemIdx + bitIdx, true } } - panic("should not happen") + PanicSanity("should not happen") } } else { // Special case for last elem, to ignore straggler bits diff --git a/Godeps/_workspace/src/github.com/tendermint/tendermint/common/byteslice.go b/Godeps/_workspace/src/github.com/tendermint/tendermint/common/byteslice.go index da42db81..be828f06 100644 --- a/Godeps/_workspace/src/github.com/tendermint/tendermint/common/byteslice.go +++ b/Godeps/_workspace/src/github.com/tendermint/tendermint/common/byteslice.go @@ -1,5 +1,9 @@ package common +import ( + "bytes" +) + func Fingerprint(slice []byte) []byte { fingerprint := make([]byte, 6) copy(fingerprint, slice) @@ -32,3 +36,9 @@ func LeftPadBytes(slice []byte, l int) []byte { copy(padded[l-len(slice):], slice) return padded } + +func TrimmedString(b []byte) string { + trimSet := string([]byte{0}) + return string(bytes.TrimLeft(b, trimSet)) + +} diff --git a/Godeps/_workspace/src/github.com/tendermint/tendermint/common/errors.go b/Godeps/_workspace/src/github.com/tendermint/tendermint/common/errors.go index a3312e97..e168a75b 100644 --- a/Godeps/_workspace/src/github.com/tendermint/tendermint/common/errors.go +++ b/Godeps/_workspace/src/github.com/tendermint/tendermint/common/errors.go @@ -16,3 +16,30 @@ func (se StackError) String() string { func (se StackError) Error() string { return se.String() } + +//-------------------------------------------------------------------------------------------------- +// panic wrappers + +// A panic resulting from a sanity check means there is a programmer error +// and some gaurantee is not satisfied. +func PanicSanity(v interface{}) { + panic(Fmt("Paniced on a Sanity Check: %v", v)) +} + +// A panic here means something has gone horribly wrong, in the form of data corruption or +// failure of the operating system. In a correct/healthy system, these should never fire. +// If they do, it's indicative of a much more serious problem. +func PanicCrisis(v interface{}) { + panic(Fmt("Paniced on a Crisis: %v", v)) +} + +// Indicates a failure of consensus. Someone was malicious or something has +// gone horribly wrong. These should really boot us into an "emergency-recover" mode +func PanicConsensus(v interface{}) { + panic(Fmt("Paniced on a Consensus Failure: %v", v)) +} + +// For those times when we're not sure if we should panic +func PanicQ(v interface{}) { + panic(Fmt("Paniced questionably: %v", v)) +} diff --git a/Godeps/_workspace/src/github.com/tendermint/tendermint/common/random.go b/Godeps/_workspace/src/github.com/tendermint/tendermint/common/random.go index e1d6046d..64560115 100644 --- a/Godeps/_workspace/src/github.com/tendermint/tendermint/common/random.go +++ b/Godeps/_workspace/src/github.com/tendermint/tendermint/common/random.go @@ -134,7 +134,7 @@ func CRandBytes(numBytes int) []byte { b := make([]byte, numBytes) _, err := crand.Read(b) if err != nil { - panic(err) + PanicCrisis(err) } return b } diff --git a/Godeps/_workspace/src/github.com/tendermint/tendermint/common/repeat_timer.go b/Godeps/_workspace/src/github.com/tendermint/tendermint/common/repeat_timer.go index 2822b968..e2aa18ea 100644 --- a/Godeps/_workspace/src/github.com/tendermint/tendermint/common/repeat_timer.go +++ b/Godeps/_workspace/src/github.com/tendermint/tendermint/common/repeat_timer.go @@ -53,7 +53,12 @@ func (t *RepeatTimer) Reset() { go t.fireRoutine(t.ticker) } +// For ease of .Stop()'ing services before .Start()'ing them, +// we ignore .Stop()'s on nil RepeatTimers. func (t *RepeatTimer) Stop() bool { + if t == nil { + return false + } t.mtx.Lock() // Lock defer t.mtx.Unlock() diff --git a/Godeps/_workspace/src/github.com/tendermint/tendermint/common/service.go b/Godeps/_workspace/src/github.com/tendermint/tendermint/common/service.go new file mode 100644 index 00000000..fd6f8546 --- /dev/null +++ b/Godeps/_workspace/src/github.com/tendermint/tendermint/common/service.go @@ -0,0 +1,141 @@ +/* + +Classical-inheritance-style service declarations. +Services can be started, then stopped. +Users can override the OnStart/OnStop methods. +These methods are guaranteed to be called at most once. +Caller must ensure that Start() and Stop() are not called concurrently. +It is ok to call Stop() without calling Start() first. +Services cannot be re-started unless otherwise documented. + +Typical usage: + +type FooService struct { + BaseService + // private fields +} + +func NewFooService() *FooService { + fs := &FooService{ + // init + } + fs.BaseService = *NewBaseService(log, "FooService", fs) + return fs +} + +func (fs *FooService) OnStart() { + fs.BaseService.OnStart() // Always call the overridden method. + // initialize private fields + // start subroutines, etc. +} + +func (fs *FooService) OnStop() { + fs.BaseService.OnStop() // Always call the overridden method. + // close/destroy private fields + // stop subroutines, etc. +} + +*/ +package common + +import "sync/atomic" +import "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/log15" + +type Service interface { + Start() bool + OnStart() + + Stop() bool + OnStop() + + IsRunning() bool + + String() string +} + +type BaseService struct { + log log15.Logger + name string + started uint32 // atomic + stopped uint32 // atomic + + // The "subclass" of BaseService + impl Service +} + +func NewBaseService(log log15.Logger, name string, impl Service) *BaseService { + return &BaseService{ + log: log, + name: name, + impl: impl, + } +} + +// Implements Servce +func (bs *BaseService) Start() bool { + if atomic.CompareAndSwapUint32(&bs.started, 0, 1) { + if atomic.LoadUint32(&bs.stopped) == 1 { + bs.log.Warn(Fmt("Not starting %v -- already stopped", bs.name), "impl", bs.impl) + return false + } else { + bs.log.Notice(Fmt("Starting %v", bs.name), "impl", bs.impl) + } + bs.impl.OnStart() + return true + } else { + bs.log.Info(Fmt("Not starting %v -- already started", bs.name), "impl", bs.impl) + return false + } +} + +// Implements Service +func (bs *BaseService) OnStart() {} + +// Implements Service +func (bs *BaseService) Stop() bool { + if atomic.CompareAndSwapUint32(&bs.stopped, 0, 1) { + bs.log.Notice(Fmt("Stopping %v", bs.name), "impl", bs.impl) + bs.impl.OnStop() + return true + } else { + bs.log.Notice(Fmt("Not stopping %v", bs.name), "impl", bs.impl) + return false + } +} + +// Implements Service +func (bs *BaseService) OnStop() {} + +// Implements Service +func (bs *BaseService) IsRunning() bool { + return atomic.LoadUint32(&bs.started) == 1 && atomic.LoadUint32(&bs.stopped) == 0 +} + +// Implements Servce +func (bs *BaseService) String() string { + return bs.name +} + +//---------------------------------------- + +type QuitService struct { + BaseService + Quit chan struct{} +} + +func NewQuitService(log log15.Logger, name string, impl Service) *QuitService { + return &QuitService{ + BaseService: *NewBaseService(log, name, impl), + Quit: nil, + } +} + +// NOTE: when overriding OnStart, must call .QuitService.OnStart(). +func (qs *QuitService) OnStart() { + qs.Quit = make(chan struct{}) +} + +// NOTE: when overriding OnStop, must call .QuitService.OnStop(). +func (qs *QuitService) OnStop() { + close(qs.Quit) +} diff --git a/Godeps/_workspace/src/github.com/tendermint/tendermint/common/throttle_timer.go b/Godeps/_workspace/src/github.com/tendermint/tendermint/common/throttle_timer.go index c1c012a0..0b40a60c 100644 --- a/Godeps/_workspace/src/github.com/tendermint/tendermint/common/throttle_timer.go +++ b/Godeps/_workspace/src/github.com/tendermint/tendermint/common/throttle_timer.go @@ -46,7 +46,12 @@ func (t *ThrottleTimer) Set() { } } +// For ease of .Stop()'ing services before .Start()'ing them, +// we ignore .Stop()'s on nil ThrottleTimers func (t *ThrottleTimer) Stop() bool { + if t == nil { + return false + } close(t.quit) return t.timer.Stop() } diff --git a/Godeps/_workspace/src/github.com/tendermint/tendermint/common/word.go b/Godeps/_workspace/src/github.com/tendermint/tendermint/common/word.go index 39e4dbb1..4072482b 100644 --- a/Godeps/_workspace/src/github.com/tendermint/tendermint/common/word.go +++ b/Godeps/_workspace/src/github.com/tendermint/tendermint/common/word.go @@ -12,11 +12,12 @@ var ( type Word256 [32]byte -func (w Word256) String() string { return string(w[:]) } -func (w Word256) Copy() Word256 { return w } -func (w Word256) Bytes() []byte { return w[:] } // copied. -func (w Word256) Prefix(n int) []byte { return w[:n] } -func (w Word256) Postfix(n int) []byte { return w[32-n:] } +func (w Word256) String() string { return string(w[:]) } +func (w Word256) TrimmedString() string { return TrimmedString(w.Bytes()) } +func (w Word256) Copy() Word256 { return w } +func (w Word256) Bytes() []byte { return w[:] } // copied. +func (w Word256) Prefix(n int) []byte { return w[:n] } +func (w Word256) Postfix(n int) []byte { return w[32-n:] } func (w Word256) IsZero() bool { accum := byte(0) for _, byt := range w { diff --git a/Godeps/_workspace/src/github.com/tendermint/tendermint/config/tendermint/config.go b/Godeps/_workspace/src/github.com/tendermint/tendermint/config/tendermint/config.go index 885d6c29..802a27cd 100644 --- a/Godeps/_workspace/src/github.com/tendermint/tendermint/config/tendermint/config.go +++ b/Godeps/_workspace/src/github.com/tendermint/tendermint/config/tendermint/config.go @@ -57,7 +57,7 @@ func GetConfig(rootDir string) cfg.Config { if mapConfig.IsSet("version") { Exit("Cannot set 'version' via config.toml") } - mapConfig.SetDefault("chain_id", "tendermint_testnet_7") + mapConfig.SetDefault("chain_id", "tendermint_testnet_9") mapConfig.SetDefault("version", "0.5.0") // JAE: encrypted p2p! mapConfig.SetDefault("genesis_file", rootDir+"/genesis.json") mapConfig.SetDefault("moniker", "anonymous") @@ -98,24 +98,20 @@ func defaultConfig(moniker string) (defaultConfig string) { } var defaultGenesis = `{ - "chain_id": "tendermint_testnet_7", + "chain_id": "tendermint_testnet_9", "accounts": [ { - "address": "F81CB9ED0A868BD961C4F5BBC0E39B763B89FCB6", + "address": "9FCBA7F840A0BFEBBE755E853C9947270A912D04", "amount": 690000000000 }, { - "address": "0000000000000000000000000000000000000002", - "amount": 565000000000 - }, - { - "address": "9E54C9ECA9A3FD5D4496696818DA17A9E17F69DA", - "amount": 525000000000 - }, + "address": "A88A61069B6660F30F65E8786AFDD4F1D8F625E9", + "amount": 1000000 + }, { - "address": "86ADF455E215711B6D8D8ED7F626C5AD3F349D2C", - "amount": 110000000000 - } + "address": "EE2EE9247973B4AFC3867CFE5F415410AC251B61", + "amount": 1000000 + } ], "validators": [ { diff --git a/Godeps/_workspace/src/github.com/tendermint/tendermint/config/tendermint_test/config.go b/Godeps/_workspace/src/github.com/tendermint/tendermint/config/tendermint_test/config.go index 6a99de08..f3eb7316 100644 --- a/Godeps/_workspace/src/github.com/tendermint/tendermint/config/tendermint_test/config.go +++ b/Godeps/_workspace/src/github.com/tendermint/tendermint/config/tendermint_test/config.go @@ -31,7 +31,6 @@ func initTMRoot(rootDir string) { configFilePath := path.Join(rootDir, "config.toml") genesisFilePath := path.Join(rootDir, "genesis.json") - privValFilePath := path.Join(rootDir, "priv_validator.json") // Write default config file if missing. if !FileExists(configFilePath) { @@ -42,9 +41,6 @@ func initTMRoot(rootDir string) { if !FileExists(genesisFilePath) { MustWriteFile(genesisFilePath, []byte(defaultGenesis)) } - if !FileExists(privValFilePath) { - MustWriteFile(privValFilePath, []byte(privValFilePath)) - } } func GetConfig(rootDir string) cfg.Config { diff --git a/Godeps/_workspace/src/github.com/tendermint/tendermint/consensus/height_vote_set.go b/Godeps/_workspace/src/github.com/tendermint/tendermint/consensus/height_vote_set.go index 01ea9b15..691c8d74 100644 --- a/Godeps/_workspace/src/github.com/tendermint/tendermint/consensus/height_vote_set.go +++ b/Godeps/_workspace/src/github.com/tendermint/tendermint/consensus/height_vote_set.go @@ -63,7 +63,7 @@ func (hvs *HeightVoteSet) SetRound(round int) { hvs.mtx.Lock() defer hvs.mtx.Unlock() if hvs.round != 0 && (round < hvs.round+1) { - panic("SetRound() must increment hvs.round") + PanicSanity("SetRound() must increment hvs.round") } for r := hvs.round + 1; r <= round; r++ { if _, ok := hvs.roundVoteSets[r]; ok { @@ -76,9 +76,9 @@ func (hvs *HeightVoteSet) SetRound(round int) { func (hvs *HeightVoteSet) addRound(round int) { if _, ok := hvs.roundVoteSets[round]; ok { - panic("addRound() for an existing round") + PanicSanity("addRound() for an existing round") } - log.Debug("addRound(round)", "round", round) + log.Info("addRound(round)", "round", round) prevotes := NewVoteSet(hvs.height, round, types.VoteTypePrevote, hvs.valSet) precommits := NewVoteSet(hvs.height, round, types.VoteTypePrecommit, hvs.valSet) hvs.roundVoteSets[round] = RoundVoteSet{ @@ -135,7 +135,7 @@ func (hvs *HeightVoteSet) POLRound() int { } func (hvs *HeightVoteSet) getVoteSet(round int, type_ byte) *VoteSet { - log.Debug("getVoteSet(round)", "round", round, "type", type_) + log.Info("getVoteSet(round)", "round", round, "type", type_) rvs, ok := hvs.roundVoteSets[round] if !ok { return nil @@ -146,7 +146,8 @@ func (hvs *HeightVoteSet) getVoteSet(round int, type_ byte) *VoteSet { case types.VoteTypePrecommit: return rvs.Precommits default: - panic(Fmt("Unexpected vote type %X", type_)) + PanicSanity(Fmt("Unexpected vote type %X", type_)) + return nil } } diff --git a/Godeps/_workspace/src/github.com/tendermint/tendermint/consensus/reactor.go b/Godeps/_workspace/src/github.com/tendermint/tendermint/consensus/reactor.go index 98c13380..b1157ef7 100644 --- a/Godeps/_workspace/src/github.com/tendermint/tendermint/consensus/reactor.go +++ b/Godeps/_workspace/src/github.com/tendermint/tendermint/consensus/reactor.go @@ -6,10 +6,8 @@ import ( "fmt" "reflect" "sync" - "sync/atomic" "time" - "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/binary" bc "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/blockchain" . "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/common" . "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/consensus/types" @@ -17,6 +15,7 @@ import ( "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/p2p" sm "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/state" "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/types" + "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/wire" ) const ( @@ -32,50 +31,47 @@ const ( //----------------------------------------------------------------------------- type ConsensusReactor struct { - sw *p2p.Switch - running uint32 - quit chan struct{} + p2p.BaseReactor blockStore *bc.BlockStore conS *ConsensusState fastSync bool - - evsw events.Fireable + evsw events.Fireable } func NewConsensusReactor(consensusState *ConsensusState, blockStore *bc.BlockStore, fastSync bool) *ConsensusReactor { conR := &ConsensusReactor{ - quit: make(chan struct{}), blockStore: blockStore, conS: consensusState, fastSync: fastSync, } + conR.BaseReactor = *p2p.NewBaseReactor(log, "ConsensusReactor", conR) return conR } -// Implements Reactor -func (conR *ConsensusReactor) Start(sw *p2p.Switch) { - if atomic.CompareAndSwapUint32(&conR.running, 0, 1) { - log.Info("Starting ConsensusReactor", "fastSync", conR.fastSync) - conR.sw = sw - if !conR.fastSync { - conR.conS.Start() - } - go conR.broadcastNewRoundStepRoutine() +func (conR *ConsensusReactor) OnStart() { + log.Notice("ConsensusReactor ", "fastSync", conR.fastSync) + conR.BaseReactor.OnStart() + if !conR.fastSync { + conR.conS.Start() } + go conR.broadcastNewRoundStepRoutine() } -// Implements Reactor -func (conR *ConsensusReactor) Stop() { - if atomic.CompareAndSwapUint32(&conR.running, 1, 0) { - log.Info("Stopping ConsensusReactor") - conR.conS.Stop() - close(conR.quit) - } +func (conR *ConsensusReactor) OnStop() { + conR.BaseReactor.OnStop() + conR.conS.Stop() } -func (conR *ConsensusReactor) IsRunning() bool { - return atomic.LoadUint32(&conR.running) == 1 +// Switch from the fast_sync to the consensus: +// reset the state, turn off fast_sync, start the consensus-state-machine +func (conR *ConsensusReactor) SwitchToConsensus(state *sm.State) { + log.Notice("SwitchToConsensus") + // NOTE: The line below causes broadcastNewRoundStepRoutine() to + // broadcast a NewRoundStepMessage. + conR.conS.updateToState(state, false) + conR.fastSync = false + conR.conS.Start() } // Implements Reactor @@ -133,8 +129,8 @@ func (conR *ConsensusReactor) RemovePeer(peer *p2p.Peer, reason interface{}) { // Implements Reactor // NOTE: We process these messages even when we're fast_syncing. func (conR *ConsensusReactor) Receive(chId byte, peer *p2p.Peer, msgBytes []byte) { - log.Debug("Receive", "channel", chId, "peer", peer, "bytes", msgBytes) if !conR.IsRunning() { + log.Debug("Receive", "channel", chId, "peer", peer, "bytes", msgBytes) return } @@ -146,7 +142,7 @@ func (conR *ConsensusReactor) Receive(chId byte, peer *p2p.Peer, msgBytes []byte log.Warn("Error decoding message", "channel", chId, "peer", peer, "msg", msg, "error", err, "bytes", msgBytes) return } - log.Debug("Receive", "channel", chId, "peer", peer, "msg", msg, "rsHeight", rs.Height) //, "bytes", msgBytes) + log.Debug("Receive", "channel", chId, "peer", peer, "msg", msg, "rsHeight", rs.Height) switch chId { case StateChannel: @@ -249,10 +245,10 @@ func (conR *ConsensusReactor) broadcastHasVoteMessage(vote *types.Vote, index in Type: vote.Type, Index: index, } - conR.sw.Broadcast(StateChannel, msg) + conR.Switch.Broadcast(StateChannel, msg) /* // TODO: Make this broadcast more selective. - for _, peer := range conR.sw.Peers().List() { + for _, peer := range conR.Switch.Peers().List() { ps := peer.Data.Get(PeerStateKey).(*PeerState) prs := ps.GetRoundState() if prs.Height == vote.Height { @@ -272,17 +268,6 @@ func (conR *ConsensusReactor) SetPrivValidator(priv *sm.PrivValidator) { conR.conS.SetPrivValidator(priv) } -// Switch from the fast_sync to the consensus: -// reset the state, turn off fast_sync, start the consensus-state-machine -func (conR *ConsensusReactor) SwitchToConsensus(state *sm.State) { - log.Info("SwitchToConsensus") - // NOTE: The line below causes broadcastNewRoundStepRoutine() to - // broadcast a NewRoundStepMessage. - conR.conS.updateToState(state, false) - conR.fastSync = false - conR.conS.Start() -} - // implements events.Eventable func (conR *ConsensusReactor) SetFireable(evsw events.Fireable) { conR.evsw = evsw @@ -317,16 +302,16 @@ func (conR *ConsensusReactor) broadcastNewRoundStepRoutine() { var rs *RoundState select { case rs = <-conR.conS.NewStepCh(): - case <-conR.quit: + case <-conR.Quit: return } nrsMsg, csMsg := makeRoundStepMessages(rs) if nrsMsg != nil { - conR.sw.Broadcast(StateChannel, nrsMsg) + conR.Switch.Broadcast(StateChannel, nrsMsg) } if csMsg != nil { - conR.sw.Broadcast(StateChannel, csMsg) + conR.Switch.Broadcast(StateChannel, csMsg) } } } @@ -349,7 +334,7 @@ OUTER_LOOP: for { // Manage disconnects from self or peer. if !peer.IsRunning() || !conR.IsRunning() { - log.Info(Fmt("Stopping gossipDataRoutine for %v.", peer)) + log.Notice(Fmt("Stopping gossipDataRoutine for %v.", peer)) return } rs := conR.conS.GetRoundState() @@ -357,7 +342,7 @@ OUTER_LOOP: // Send proposal Block parts? if rs.ProposalBlockParts.HasHeader(prs.ProposalBlockPartsHeader) { - //log.Debug("ProposalBlockParts matched", "blockParts", prs.ProposalBlockParts) + //log.Info("ProposalBlockParts matched", "blockParts", prs.ProposalBlockParts) if index, ok := rs.ProposalBlockParts.BitArray().Sub(prs.ProposalBlockParts.Copy()).PickRandom(); ok { part := rs.ProposalBlockParts.GetPart(index) msg := &BlockPartMessage{ @@ -373,12 +358,12 @@ OUTER_LOOP: // If the peer is on a previous height, help catch up. if (0 < prs.Height) && (prs.Height < rs.Height) { - //log.Debug("Data catchup", "height", rs.Height, "peerHeight", prs.Height, "peerProposalBlockParts", prs.ProposalBlockParts) + //log.Info("Data catchup", "height", rs.Height, "peerHeight", prs.Height, "peerProposalBlockParts", prs.ProposalBlockParts) if index, ok := prs.ProposalBlockParts.Not().PickRandom(); ok { // Ensure that the peer's PartSetHeader is correct blockMeta := conR.blockStore.LoadBlockMeta(prs.Height) if !blockMeta.PartsHeader.Equals(prs.ProposalBlockPartsHeader) { - log.Debug("Peer ProposalBlockPartsHeader mismatch, sleeping", + log.Info("Peer ProposalBlockPartsHeader mismatch, sleeping", "peerHeight", prs.Height, "blockPartsHeader", blockMeta.PartsHeader, "peerBlockPartsHeader", prs.ProposalBlockPartsHeader) time.Sleep(peerGossipSleepDuration) continue OUTER_LOOP @@ -401,7 +386,7 @@ OUTER_LOOP: ps.SetHasProposalBlockPart(prs.Height, prs.Round, index) continue OUTER_LOOP } else { - //log.Debug("No parts to send in catch-up, sleeping") + //log.Info("No parts to send in catch-up, sleeping") time.Sleep(peerGossipSleepDuration) continue OUTER_LOOP } @@ -409,7 +394,7 @@ OUTER_LOOP: // If height and round don't match, sleep. if (rs.Height != prs.Height) || (rs.Round != prs.Round) { - //log.Debug("Peer Height|Round mismatch, sleeping", "peerHeight", prs.Height, "peerRound", prs.Round, "peer", peer) + //log.Info("Peer Height|Round mismatch, sleeping", "peerHeight", prs.Height, "peerRound", prs.Round, "peer", peer) time.Sleep(peerGossipSleepDuration) continue OUTER_LOOP } @@ -458,7 +443,7 @@ OUTER_LOOP: for { // Manage disconnects from self or peer. if !peer.IsRunning() || !conR.IsRunning() { - log.Info(Fmt("Stopping gossipVotesRoutine for %v.", peer)) + log.Notice(Fmt("Stopping gossipVotesRoutine for %v.", peer)) return } rs := conR.conS.GetRoundState() @@ -479,35 +464,35 @@ OUTER_LOOP: // If there are lastCommits to send... if prs.Step == RoundStepNewHeight { if ps.PickSendVote(rs.LastCommit) { - log.Debug("Picked rs.LastCommit to send") + log.Info("Picked rs.LastCommit to send") continue OUTER_LOOP } } // If there are prevotes to send... if rs.Round == prs.Round && prs.Step <= RoundStepPrevote { if ps.PickSendVote(rs.Votes.Prevotes(rs.Round)) { - log.Debug("Picked rs.Prevotes(rs.Round) to send") + log.Info("Picked rs.Prevotes(rs.Round) to send") continue OUTER_LOOP } } // If there are precommits to send... if rs.Round == prs.Round && prs.Step <= RoundStepPrecommit { if ps.PickSendVote(rs.Votes.Precommits(rs.Round)) { - log.Debug("Picked rs.Precommits(rs.Round) to send") + log.Info("Picked rs.Precommits(rs.Round) to send") continue OUTER_LOOP } } // If there are prevotes to send for the last round... if rs.Round == prs.Round+1 && prs.Step <= RoundStepPrevote { if ps.PickSendVote(rs.Votes.Prevotes(prs.Round)) { - log.Debug("Picked rs.Prevotes(prs.Round) to send") + log.Info("Picked rs.Prevotes(prs.Round) to send") continue OUTER_LOOP } } // If there are precommits to send for the last round... if rs.Round == prs.Round+1 && prs.Step <= RoundStepPrecommit { if ps.PickSendVote(rs.Votes.Precommits(prs.Round)) { - log.Debug("Picked rs.Precommits(prs.Round) to send") + log.Info("Picked rs.Precommits(prs.Round) to send") continue OUTER_LOOP } } @@ -515,7 +500,7 @@ OUTER_LOOP: if 0 <= prs.ProposalPOLRound { if polPrevotes := rs.Votes.Prevotes(prs.ProposalPOLRound); polPrevotes != nil { if ps.PickSendVote(polPrevotes) { - log.Debug("Picked rs.Prevotes(prs.ProposalPOLRound) to send") + log.Info("Picked rs.Prevotes(prs.ProposalPOLRound) to send") continue OUTER_LOOP } } @@ -526,7 +511,7 @@ OUTER_LOOP: // If peer is lagging by height 1, send LastCommit. if prs.Height != 0 && rs.Height == prs.Height+1 { if ps.PickSendVote(rs.LastCommit) { - log.Debug("Picked rs.LastCommit to send") + log.Info("Picked rs.LastCommit to send") continue OUTER_LOOP } } @@ -537,9 +522,9 @@ OUTER_LOOP: // Load the block validation for prs.Height, // which contains precommit signatures for prs.Height. validation := conR.blockStore.LoadBlockValidation(prs.Height) - log.Debug("Loaded BlockValidation for catch-up", "height", prs.Height, "validation", validation) + log.Info("Loaded BlockValidation for catch-up", "height", prs.Height, "validation", validation) if ps.PickSendVote(validation) { - log.Debug("Picked Catchup validation to send") + log.Info("Picked Catchup validation to send") continue OUTER_LOOP } } @@ -547,7 +532,7 @@ OUTER_LOOP: if sleeping == 0 { // We sent nothing. Sleep... sleeping = 1 - log.Debug("No votes to send, sleeping", "peer", peer, + log.Info("No votes to send, sleeping", "peer", peer, "localPV", rs.Votes.Prevotes(rs.Round).BitArray(), "peerPV", prs.Prevotes, "localPC", rs.Votes.Precommits(rs.Round).BitArray(), "peerPC", prs.Precommits) } else if sleeping == 2 { @@ -686,7 +671,7 @@ func (ps *PeerState) getVoteBitArray(height, round int, type_ byte) *BitArray { case types.VoteTypePrecommit: return ps.Precommits default: - panic(Fmt("Unexpected vote type %X", type_)) + PanicSanity(Fmt("Unexpected vote type %X", type_)) } } if ps.CatchupCommitRound == round { @@ -696,7 +681,7 @@ func (ps *PeerState) getVoteBitArray(height, round int, type_ byte) *BitArray { case types.VoteTypePrecommit: return ps.CatchupCommit default: - panic(Fmt("Unexpected vote type %X", type_)) + PanicSanity(Fmt("Unexpected vote type %X", type_)) } } return nil @@ -709,7 +694,7 @@ func (ps *PeerState) getVoteBitArray(height, round int, type_ byte) *BitArray { case types.VoteTypePrecommit: return ps.LastCommit default: - panic(Fmt("Unexpected vote type %X", type_)) + PanicSanity(Fmt("Unexpected vote type %X", type_)) } } return nil @@ -723,7 +708,7 @@ func (ps *PeerState) ensureCatchupCommitRound(height, round int, numValidators i return } if ps.CatchupCommitRound != -1 && ps.CatchupCommitRound != round { - panic(Fmt("Conflicting CatchupCommitRound. Height: %v, Orig: %v, New: %v", height, ps.CatchupCommitRound, round)) + PanicSanity(Fmt("Conflicting CatchupCommitRound. Height: %v, Orig: %v, New: %v", height, ps.CatchupCommitRound, round)) } if ps.CatchupCommitRound == round { return // Nothing to do! @@ -775,7 +760,7 @@ func (ps *PeerState) SetHasVote(vote *types.Vote, index int) { func (ps *PeerState) setHasVote(height int, round int, type_ byte, index int) { log := log.New("peer", ps.Peer.Key, "peerRound", ps.Round, "height", height, "round", round) if type_ != types.VoteTypePrevote && type_ != types.VoteTypePrecommit { - panic("Invalid vote type") // SANITY + PanicSanity("Invalid vote type") } if ps.Height == height { @@ -783,23 +768,23 @@ func (ps *PeerState) setHasVote(height int, round int, type_ byte, index int) { switch type_ { case types.VoteTypePrevote: ps.Prevotes.SetIndex(index, true) - log.Debug("SetHasVote(round-match)", "prevotes", ps.Prevotes, "index", index) + log.Info("SetHasVote(round-match)", "prevotes", ps.Prevotes, "index", index) case types.VoteTypePrecommit: ps.Precommits.SetIndex(index, true) - log.Debug("SetHasVote(round-match)", "precommits", ps.Precommits, "index", index) + log.Info("SetHasVote(round-match)", "precommits", ps.Precommits, "index", index) } } else if ps.CatchupCommitRound == round { switch type_ { case types.VoteTypePrevote: case types.VoteTypePrecommit: ps.CatchupCommit.SetIndex(index, true) - log.Debug("SetHasVote(CatchupCommit)", "precommits", ps.Precommits, "index", index) + log.Info("SetHasVote(CatchupCommit)", "precommits", ps.Precommits, "index", index) } } else if ps.ProposalPOLRound == round { switch type_ { case types.VoteTypePrevote: ps.ProposalPOL.SetIndex(index, true) - log.Debug("SetHasVote(ProposalPOL)", "prevotes", ps.Prevotes, "index", index) + log.Info("SetHasVote(ProposalPOL)", "prevotes", ps.Prevotes, "index", index) case types.VoteTypePrecommit: } } @@ -809,7 +794,7 @@ func (ps *PeerState) setHasVote(height int, round int, type_ byte, index int) { case types.VoteTypePrevote: case types.VoteTypePrecommit: ps.LastCommit.SetIndex(index, true) - log.Debug("setHasVote(LastCommit)", "lastCommit", ps.LastCommit, "index", index) + log.Info("setHasVote(LastCommit)", "lastCommit", ps.LastCommit, "index", index) } } } else { @@ -924,15 +909,15 @@ const ( type ConsensusMessage interface{} -var _ = binary.RegisterInterface( +var _ = wire.RegisterInterface( struct{ ConsensusMessage }{}, - binary.ConcreteType{&NewRoundStepMessage{}, msgTypeNewRoundStep}, - binary.ConcreteType{&CommitStepMessage{}, msgTypeCommitStep}, - binary.ConcreteType{&ProposalMessage{}, msgTypeProposal}, - binary.ConcreteType{&ProposalPOLMessage{}, msgTypeProposalPOL}, - binary.ConcreteType{&BlockPartMessage{}, msgTypeBlockPart}, - binary.ConcreteType{&VoteMessage{}, msgTypeVote}, - binary.ConcreteType{&HasVoteMessage{}, msgTypeHasVote}, + wire.ConcreteType{&NewRoundStepMessage{}, msgTypeNewRoundStep}, + wire.ConcreteType{&CommitStepMessage{}, msgTypeCommitStep}, + wire.ConcreteType{&ProposalMessage{}, msgTypeProposal}, + wire.ConcreteType{&ProposalPOLMessage{}, msgTypeProposalPOL}, + wire.ConcreteType{&BlockPartMessage{}, msgTypeBlockPart}, + wire.ConcreteType{&VoteMessage{}, msgTypeVote}, + wire.ConcreteType{&HasVoteMessage{}, msgTypeHasVote}, ) // TODO: check for unnecessary extra bytes at the end. @@ -940,7 +925,7 @@ func DecodeMessage(bz []byte) (msgType byte, msg ConsensusMessage, err error) { msgType = bz[0] n := new(int64) r := bytes.NewReader(bz) - msg = binary.ReadBinary(struct{ ConsensusMessage }{}, r, n, &err).(struct{ ConsensusMessage }).ConsensusMessage + msg = wire.ReadBinary(struct{ ConsensusMessage }{}, r, n, &err).(struct{ ConsensusMessage }).ConsensusMessage return } diff --git a/Godeps/_workspace/src/github.com/tendermint/tendermint/consensus/state.go b/Godeps/_workspace/src/github.com/tendermint/tendermint/consensus/state.go index 0174d54d..c9286772 100644 --- a/Godeps/_workspace/src/github.com/tendermint/tendermint/consensus/state.go +++ b/Godeps/_workspace/src/github.com/tendermint/tendermint/consensus/state.go @@ -155,11 +155,9 @@ import ( "errors" "fmt" "sync" - "sync/atomic" "time" - "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/account" - "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/binary" + acm "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/account" bc "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/blockchain" . "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/common" . "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/consensus/types" @@ -167,6 +165,7 @@ import ( mempl "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/mempool" sm "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/state" "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/types" + "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/wire" ) var ( @@ -285,9 +284,7 @@ func (rs *RoundState) StringShort() string { // Tracks consensus state across block heights and rounds. type ConsensusState struct { - started uint32 - stopped uint32 - quit chan struct{} + BaseService blockStore *bc.BlockStore mempoolReactor *mempl.MempoolReactor @@ -306,7 +303,6 @@ type ConsensusState struct { func NewConsensusState(state *sm.State, blockStore *bc.BlockStore, mempoolReactor *mempl.MempoolReactor) *ConsensusState { cs := &ConsensusState{ - quit: make(chan struct{}), blockStore: blockStore, mempoolReactor: mempoolReactor, newStepCh: make(chan *RoundState, 10), @@ -316,6 +312,7 @@ func NewConsensusState(state *sm.State, blockStore *bc.BlockStore, mempoolReacto // We do that upon Start(). cs.maybeRebond() cs.reconstructLastCommit(state) + cs.BaseService = *NewBaseService(log, "ConsensusState", cs) return cs } @@ -333,11 +330,11 @@ func (cs *ConsensusState) reconstructLastCommit(state *sm.State) { } added, _, err := lastPrecommits.AddByIndex(idx, precommit) if !added || err != nil { - panic(Fmt("Failed to reconstruct LastCommit: %v", err)) + PanicCrisis(Fmt("Failed to reconstruct LastCommit: %v", err)) } } if !lastPrecommits.HasTwoThirdsMajority() { - panic("Failed to reconstruct LastCommit: Does not have +2/3 maj") + PanicSanity("Failed to reconstruct LastCommit: Does not have +2/3 maj") } cs.LastCommit = lastPrecommits } @@ -363,16 +360,19 @@ func (cs *ConsensusState) NewStepCh() chan *RoundState { return cs.newStepCh } -func (cs *ConsensusState) Start() { - if atomic.CompareAndSwapUint32(&cs.started, 0, 1) { - log.Info("Starting ConsensusState") - cs.scheduleRound0(cs.Height) - } +func (cs *ConsensusState) OnStart() { + cs.BaseService.OnStart() + cs.scheduleRound0(cs.Height) +} + +func (cs *ConsensusState) OnStop() { + // It's mostly asynchronous so, there's not much to stop. + cs.BaseService.OnStop() } // EnterNewRound(height, 0) at cs.StartTime. func (cs *ConsensusState) scheduleRound0(height int) { - //log.Debug("scheduleRound0", "now", time.Now(), "startTime", cs.StartTime) + //log.Info("scheduleRound0", "now", time.Now(), "startTime", cs.StartTime) sleepDuration := cs.StartTime.Sub(time.Now()) go func() { if 0 < sleepDuration { @@ -382,34 +382,25 @@ func (cs *ConsensusState) scheduleRound0(height int) { }() } -func (cs *ConsensusState) Stop() { - if atomic.CompareAndSwapUint32(&cs.stopped, 0, 1) { - log.Info("Stopping ConsensusState") - close(cs.quit) - } -} - // Updates ConsensusState and increments height to match that of state. // The round becomes 0 and cs.Step becomes RoundStepNewHeight. func (cs *ConsensusState) updateToState(state *sm.State, contiguous bool) { - // SANITY CHECK if contiguous && 0 < cs.Height && cs.Height != state.LastBlockHeight { - panic(Fmt("updateToState() expected state height of %v but found %v", + PanicSanity(Fmt("updateToState() expected state height of %v but found %v", cs.Height, state.LastBlockHeight)) } if cs.state != nil && cs.state.LastBlockHeight+1 != cs.Height { // This might happen when someone else is mutating cs.state. // Someone forgot to pass in state.Copy() somewhere?! - panic(Fmt("Inconsistent cs.state.LastBlockHeight+1 %v vs cs.Height %v", + PanicSanity(Fmt("Inconsistent cs.state.LastBlockHeight+1 %v vs cs.Height %v", cs.state.LastBlockHeight+1, cs.Height)) } - // END SANITY CHECK // If state isn't further out than cs.state, just ignore. // This happens when SwitchToConsensus() is called in the reactor. // We don't want to reset e.g. the Votes. if cs.state != nil && (state.LastBlockHeight <= cs.state.LastBlockHeight) { - log.Info("Ignoring updateToState()", "newHeight", state.LastBlockHeight+1, "oldHeight", cs.state.LastBlockHeight+1) + log.Notice("Ignoring updateToState()", "newHeight", state.LastBlockHeight+1, "oldHeight", cs.state.LastBlockHeight+1) return } @@ -419,7 +410,7 @@ func (cs *ConsensusState) updateToState(state *sm.State, contiguous bool) { lastPrecommits := (*VoteSet)(nil) if contiguous && cs.Votes != nil { if !cs.Votes.Precommits(cs.Round).HasTwoThirdsMajority() { - panic("updateToState(state, true) called but last Precommit round didn't have +2/3") + PanicSanity("updateToState(state, true) called but last Precommit round didn't have +2/3") } lastPrecommits = cs.Votes.Precommits(cs.Round) } @@ -474,7 +465,7 @@ func (cs *ConsensusState) maybeRebond() { log.Error("Failed to broadcast RebondTx", "height", cs.Height, "round", cs.Round, "tx", rebondTx, "error", err) } else { - log.Info("Signed and broadcast RebondTx", + log.Notice("Signed and broadcast RebondTx", "height", cs.Height, "round", cs.Round, "tx", rebondTx) } } else { @@ -498,13 +489,13 @@ func (cs *ConsensusState) EnterNewRound(height int, round int) { cs.mtx.Lock() defer cs.mtx.Unlock() if cs.Height != height || round < cs.Round || (cs.Round == round && cs.Step != RoundStepNewHeight) { - log.Debug(Fmt("EnterNewRound(%v/%v): Invalid args. Current step: %v/%v/%v", height, round, cs.Height, cs.Round, cs.Step)) + log.Info(Fmt("EnterNewRound(%v/%v): Invalid args. Current step: %v/%v/%v", height, round, cs.Height, cs.Round, cs.Step)) return } if now := time.Now(); cs.StartTime.After(now) { log.Warn("Need to set a buffer and log.Warn() here for sanity.", "startTime", cs.StartTime, "now", now) } - log.Info(Fmt("EnterNewRound(%v/%v). Current: %v/%v/%v", height, round, cs.Height, cs.Round, cs.Step)) + log.Notice(Fmt("EnterNewRound(%v/%v). Current: %v/%v/%v", height, round, cs.Height, cs.Round, cs.Step)) // Increment validators if necessary validators := cs.Validators @@ -537,10 +528,10 @@ func (cs *ConsensusState) EnterPropose(height int, round int) { cs.mtx.Lock() defer cs.mtx.Unlock() if cs.Height != height || round < cs.Round || (cs.Round == round && RoundStepPropose <= cs.Step) { - log.Debug(Fmt("EnterPropose(%v/%v): Invalid args. Current step: %v/%v/%v", height, round, cs.Height, cs.Round, cs.Step)) + log.Info(Fmt("EnterPropose(%v/%v): Invalid args. Current step: %v/%v/%v", height, round, cs.Height, cs.Round, cs.Step)) return } - log.Debug(Fmt("EnterPropose(%v/%v). Current: %v/%v/%v", height, round, cs.Height, cs.Round, cs.Step)) + log.Info(Fmt("EnterPropose(%v/%v). Current: %v/%v/%v", height, round, cs.Height, cs.Round, cs.Step)) defer func() { // Done EnterPropose: @@ -566,9 +557,9 @@ func (cs *ConsensusState) EnterPropose(height int, round int) { } if !bytes.Equal(cs.Validators.Proposer().Address, cs.privValidator.Address) { - log.Debug("EnterPropose: Not our turn to propose", "proposer", cs.Validators.Proposer().Address, "privValidator", cs.privValidator) + log.Info("EnterPropose: Not our turn to propose", "proposer", cs.Validators.Proposer().Address, "privValidator", cs.privValidator) } else { - log.Debug("EnterPropose: Our turn to propose", "proposer", cs.Validators.Proposer().Address, "privValidator", cs.privValidator) + log.Info("EnterPropose: Our turn to propose", "proposer", cs.Validators.Proposer().Address, "privValidator", cs.privValidator) cs.decideProposal(height, round) } } @@ -591,8 +582,8 @@ func (cs *ConsensusState) decideProposal(height int, round int) { proposal := NewProposal(height, round, blockParts.Header(), cs.Votes.POLRound()) err := cs.privValidator.SignProposal(cs.state.ChainID, proposal) if err == nil { - log.Info("Signed and set proposal", "height", height, "round", round, "proposal", proposal) - log.Debug(Fmt("Signed and set proposal block: %v", block)) + log.Notice("Signed and set proposal", "height", height, "round", round, "proposal", proposal) + log.Info(Fmt("Signed and set proposal block: %v", block)) // Set fields cs.Proposal = proposal cs.ProposalBlock = block @@ -670,10 +661,10 @@ func (cs *ConsensusState) EnterPrevote(height int, round int) { cs.mtx.Lock() defer cs.mtx.Unlock() if cs.Height != height || round < cs.Round || (cs.Round == round && RoundStepPrevote <= cs.Step) { - log.Debug(Fmt("EnterPrevote(%v/%v): Invalid args. Current step: %v/%v/%v", height, round, cs.Height, cs.Round, cs.Step)) + log.Info(Fmt("EnterPrevote(%v/%v): Invalid args. Current step: %v/%v/%v", height, round, cs.Height, cs.Round, cs.Step)) return } - log.Debug(Fmt("EnterPrevote(%v/%v). Current: %v/%v/%v", height, round, cs.Height, cs.Round, cs.Step)) + log.Info(Fmt("EnterPrevote(%v/%v). Current: %v/%v/%v", height, round, cs.Height, cs.Round, cs.Step)) // Sign and broadcast vote as necessary cs.doPrevote(height, round) @@ -691,7 +682,7 @@ func (cs *ConsensusState) EnterPrevote(height int, round int) { func (cs *ConsensusState) doPrevote(height int, round int) { // If a block is locked, prevote that. if cs.LockedBlock != nil { - log.Debug("EnterPrevote: Block was locked") + log.Info("EnterPrevote: Block was locked") cs.signAddVote(types.VoteTypePrevote, cs.LockedBlock.Hash(), cs.LockedBlockParts.Header()) return } @@ -722,13 +713,13 @@ func (cs *ConsensusState) EnterPrevoteWait(height int, round int) { cs.mtx.Lock() defer cs.mtx.Unlock() if cs.Height != height || round < cs.Round || (cs.Round == round && RoundStepPrevoteWait <= cs.Step) { - log.Debug(Fmt("EnterPrevoteWait(%v/%v): Invalid args. Current step: %v/%v/%v", height, round, cs.Height, cs.Round, cs.Step)) + log.Info(Fmt("EnterPrevoteWait(%v/%v): Invalid args. Current step: %v/%v/%v", height, round, cs.Height, cs.Round, cs.Step)) return } if !cs.Votes.Prevotes(round).HasTwoThirdsAny() { - panic(Fmt("EnterPrevoteWait(%v/%v), but Prevotes does not have any +2/3 votes", height, round)) + PanicSanity(Fmt("EnterPrevoteWait(%v/%v), but Prevotes does not have any +2/3 votes", height, round)) } - log.Debug(Fmt("EnterPrevoteWait(%v/%v). Current: %v/%v/%v", height, round, cs.Height, cs.Round, cs.Step)) + log.Info(Fmt("EnterPrevoteWait(%v/%v). Current: %v/%v/%v", height, round, cs.Height, cs.Round, cs.Step)) // Done EnterPrevoteWait: cs.Round = round @@ -752,10 +743,10 @@ func (cs *ConsensusState) EnterPrecommit(height int, round int) { cs.mtx.Lock() defer cs.mtx.Unlock() if cs.Height != height || round < cs.Round || (cs.Round == round && RoundStepPrecommit <= cs.Step) { - log.Debug(Fmt("EnterPrecommit(%v/%v): Invalid args. Current step: %v/%v/%v", height, round, cs.Height, cs.Round, cs.Step)) + log.Info(Fmt("EnterPrecommit(%v/%v): Invalid args. Current step: %v/%v/%v", height, round, cs.Height, cs.Round, cs.Step)) return } - log.Debug(Fmt("EnterPrecommit(%v/%v). Current: %v/%v/%v", height, round, cs.Height, cs.Round, cs.Step)) + log.Info(Fmt("EnterPrecommit(%v/%v). Current: %v/%v/%v", height, round, cs.Height, cs.Round, cs.Step)) defer func() { // Done EnterPrecommit: @@ -773,10 +764,10 @@ func (cs *ConsensusState) EnterPrecommit(height int, round int) { // If we don't have two thirds of prevotes, just precommit locked block or nil if !ok { if cs.LockedBlock != nil { - log.Debug("EnterPrecommit: No +2/3 prevotes during EnterPrecommit. Precommitting lock.") + log.Info("EnterPrecommit: No +2/3 prevotes during EnterPrecommit. Precommitting lock.") cs.signAddVote(types.VoteTypePrecommit, cs.LockedBlock.Hash(), cs.LockedBlockParts.Header()) } else { - log.Debug("EnterPrecommit: No +2/3 prevotes during EnterPrecommit. Precommitting nil.") + log.Info("EnterPrecommit: No +2/3 prevotes during EnterPrecommit. Precommitting nil.") cs.signAddVote(types.VoteTypePrecommit, nil, types.PartSetHeader{}) } return @@ -785,9 +776,9 @@ func (cs *ConsensusState) EnterPrecommit(height int, round int) { // +2/3 prevoted nil. Unlock and precommit nil. if len(hash) == 0 { if cs.LockedBlock == nil { - log.Debug("EnterPrecommit: +2/3 prevoted for nil.") + log.Info("EnterPrecommit: +2/3 prevoted for nil.") } else { - log.Debug("EnterPrecommit: +2/3 prevoted for nil. Unlocking") + log.Info("EnterPrecommit: +2/3 prevoted for nil. Unlocking") cs.LockedRound = 0 cs.LockedBlock = nil cs.LockedBlockParts = nil @@ -800,17 +791,17 @@ func (cs *ConsensusState) EnterPrecommit(height int, round int) { // If +2/3 prevoted for already locked block, precommit it. if cs.LockedBlock.HashesTo(hash) { - log.Debug("EnterPrecommit: +2/3 prevoted locked block.") + log.Info("EnterPrecommit: +2/3 prevoted locked block.") cs.signAddVote(types.VoteTypePrecommit, hash, partsHeader) return } // If +2/3 prevoted for proposal block, stage and precommit it if cs.ProposalBlock.HashesTo(hash) { - log.Debug("EnterPrecommit: +2/3 prevoted proposal block.") + log.Info("EnterPrecommit: +2/3 prevoted proposal block.") // Validate the block. if err := cs.stageBlock(cs.ProposalBlock, cs.ProposalBlockParts); err != nil { - panic(Fmt("EnterPrecommit: +2/3 prevoted for an invalid block: %v", err)) + PanicConsensus(Fmt("EnterPrecommit: +2/3 prevoted for an invalid block: %v", err)) } cs.LockedRound = round cs.LockedBlock = cs.ProposalBlock @@ -823,7 +814,7 @@ func (cs *ConsensusState) EnterPrecommit(height int, round int) { // Unlock and precommit nil. // The +2/3 prevotes for this round is the POL for our unlock. if cs.Votes.POLRound() < round { - panic(Fmt("This POLRound shold be %v but got %", round, cs.Votes.POLRound())) + PanicSanity(Fmt("This POLRound shold be %v but got %", round, cs.Votes.POLRound())) } cs.LockedRound = 0 cs.LockedBlock = nil @@ -841,13 +832,13 @@ func (cs *ConsensusState) EnterPrecommitWait(height int, round int) { cs.mtx.Lock() defer cs.mtx.Unlock() if cs.Height != height || round < cs.Round || (cs.Round == round && RoundStepPrecommitWait <= cs.Step) { - log.Debug(Fmt("EnterPrecommitWait(%v/%v): Invalid args. Current step: %v/%v/%v", height, round, cs.Height, cs.Round, cs.Step)) + log.Info(Fmt("EnterPrecommitWait(%v/%v): Invalid args. Current step: %v/%v/%v", height, round, cs.Height, cs.Round, cs.Step)) return } if !cs.Votes.Precommits(round).HasTwoThirdsAny() { - panic(Fmt("EnterPrecommitWait(%v/%v), but Precommits does not have any +2/3 votes", height, round)) + PanicSanity(Fmt("EnterPrecommitWait(%v/%v), but Precommits does not have any +2/3 votes", height, round)) } - log.Debug(Fmt("EnterPrecommitWait(%v/%v). Current: %v/%v/%v", height, round, cs.Height, cs.Round, cs.Step)) + log.Info(Fmt("EnterPrecommitWait(%v/%v). Current: %v/%v/%v", height, round, cs.Height, cs.Round, cs.Step)) // Done EnterPrecommitWait: cs.Round = round @@ -870,10 +861,10 @@ func (cs *ConsensusState) EnterCommit(height int) { cs.mtx.Lock() defer cs.mtx.Unlock() if cs.Height != height || RoundStepCommit <= cs.Step { - log.Debug(Fmt("EnterCommit(%v): Invalid args. Current step: %v/%v/%v", height, cs.Height, cs.Round, cs.Step)) + log.Info(Fmt("EnterCommit(%v): Invalid args. Current step: %v/%v/%v", height, cs.Height, cs.Round, cs.Step)) return } - log.Debug(Fmt("EnterCommit(%v). Current: %v/%v/%v", height, cs.Height, cs.Round, cs.Step)) + log.Info(Fmt("EnterCommit(%v). Current: %v/%v/%v", height, cs.Height, cs.Round, cs.Step)) defer func() { // Done Entercommit: @@ -885,12 +876,10 @@ func (cs *ConsensusState) EnterCommit(height int) { cs.tryFinalizeCommit(height) }() - // SANITY CHECK hash, partsHeader, ok := cs.Votes.Precommits(cs.Round).TwoThirdsMajority() if !ok { - panic("RunActionCommit() expects +2/3 precommits") + PanicSanity("RunActionCommit() expects +2/3 precommits") } - // END SANITY CHECK // The Locked* fields no longer matter. // Move them over to ProposalBlock if they match the commit hash, @@ -922,11 +911,9 @@ func (cs *ConsensusState) EnterCommit(height int) { // If we have the block AND +2/3 commits for it, finalize. func (cs *ConsensusState) tryFinalizeCommit(height int) { - // SANITY CHECK if cs.Height != height { - panic(Fmt("tryFinalizeCommit() cs.Height: %v vs height: %v", cs.Height, height)) + PanicSanity(Fmt("tryFinalizeCommit() cs.Height: %v vs height: %v", cs.Height, height)) } - // END SANITY CHECK hash, _, ok := cs.Votes.Precommits(cs.Round).TwoThirdsMajority() if !ok || len(hash) == 0 { @@ -944,28 +931,26 @@ func (cs *ConsensusState) FinalizeCommit(height int) { defer cs.mtx.Unlock() if cs.Height != height || cs.Step != RoundStepCommit { - log.Debug(Fmt("FinalizeCommit(%v): Invalid args. Current step: %v/%v/%v", height, cs.Height, cs.Round, cs.Step)) + log.Info(Fmt("FinalizeCommit(%v): Invalid args. Current step: %v/%v/%v", height, cs.Height, cs.Round, cs.Step)) return } hash, header, ok := cs.Votes.Precommits(cs.Round).TwoThirdsMajority() - // SANITY CHECK if !ok { - panic(Fmt("Cannot FinalizeCommit, commit does not have two thirds majority")) + PanicSanity(Fmt("Cannot FinalizeCommit, commit does not have two thirds majority")) } if !cs.ProposalBlockParts.HasHeader(header) { - panic(Fmt("Expected ProposalBlockParts header to be commit header")) + PanicSanity(Fmt("Expected ProposalBlockParts header to be commit header")) } if !cs.ProposalBlock.HashesTo(hash) { - panic(Fmt("Cannot FinalizeCommit, ProposalBlock does not hash to commit hash")) + PanicSanity(Fmt("Cannot FinalizeCommit, ProposalBlock does not hash to commit hash")) } if err := cs.stageBlock(cs.ProposalBlock, cs.ProposalBlockParts); err != nil { - panic(Fmt("+2/3 committed an invalid block: %v", err)) + PanicConsensus(Fmt("+2/3 committed an invalid block: %v", err)) } - // END SANITY CHECK - log.Debug(Fmt("Finalizing commit of block: %v", cs.ProposalBlock)) + log.Info(Fmt("Finalizing commit of block: %v", cs.ProposalBlock)) // We have the block, so stage/save/commit-vote. cs.saveBlock(cs.ProposalBlock, cs.ProposalBlockParts, cs.Votes.Precommits(cs.Round)) // Increment height. @@ -1011,7 +996,7 @@ func (cs *ConsensusState) SetProposal(proposal *Proposal) error { } // Verify signature - if !cs.Validators.Proposer().PubKey.VerifyBytes(account.SignBytes(cs.state.ChainID, proposal), proposal.Signature) { + if !cs.Validators.Proposer().PubKey.VerifyBytes(acm.SignBytes(cs.state.ChainID, proposal), proposal.Signature) { return ErrInvalidProposalSignature } @@ -1043,8 +1028,8 @@ func (cs *ConsensusState) AddProposalBlockPart(height int, part *types.Part) (ad // Added and completed! var n int64 var err error - cs.ProposalBlock = binary.ReadBinary(&types.Block{}, cs.ProposalBlockParts.GetReader(), &n, &err).(*types.Block) - log.Debug("Received complete proposal", "hash", cs.ProposalBlock.Hash()) + cs.ProposalBlock = wire.ReadBinary(&types.Block{}, cs.ProposalBlockParts.GetReader(), &n, &err).(*types.Block) + log.Info("Received complete proposal", "hash", cs.ProposalBlock.Hash()) if cs.Step == RoundStepPropose && cs.isProposalComplete() { // Move onto the next step go cs.EnterPrevote(height, cs.Round) @@ -1067,13 +1052,13 @@ func (cs *ConsensusState) AddVote(address []byte, vote *types.Vote, peerKey stri //----------------------------------------------------------------------------- func (cs *ConsensusState) addVote(address []byte, vote *types.Vote, peerKey string) (added bool, index int, err error) { - log.Debug("addVote", "voteHeight", vote.Height, "voteType", vote.Type, "csHeight", cs.Height) + log.Info("addVote", "voteHeight", vote.Height, "voteType", vote.Type, "csHeight", cs.Height) // A precommit for the previous height? if vote.Height+1 == cs.Height && vote.Type == types.VoteTypePrecommit { added, index, err = cs.LastCommit.AddByAddress(address, vote) if added { - log.Debug(Fmt("Added to lastPrecommits: %v", cs.LastCommit.StringShort())) + log.Info(Fmt("Added to lastPrecommits: %v", cs.LastCommit.StringShort())) } return } @@ -1086,7 +1071,7 @@ func (cs *ConsensusState) addVote(address []byte, vote *types.Vote, peerKey stri switch vote.Type { case types.VoteTypePrevote: prevotes := cs.Votes.Prevotes(vote.Round) - log.Debug(Fmt("Added to prevotes: %v", prevotes.StringShort())) + log.Info(Fmt("Added to prevotes: %v", prevotes.StringShort())) // First, unlock if prevotes is a valid POL. // >> lockRound < POLRound <= unlockOrChangeLockRound (see spec) // NOTE: If (lockRound < POLRound) but !(POLRound <= unlockOrChangeLockRound), @@ -1095,7 +1080,7 @@ func (cs *ConsensusState) addVote(address []byte, vote *types.Vote, peerKey stri if (cs.LockedBlock != nil) && (cs.LockedRound < vote.Round) && (vote.Round <= cs.Round) { hash, _, ok := prevotes.TwoThirdsMajority() if ok && !cs.LockedBlock.HashesTo(hash) { - log.Info("Unlocking because of POL.", "lockedRound", cs.LockedRound, "POLRound", vote.Round) + log.Notice("Unlocking because of POL.", "lockedRound", cs.LockedRound, "POLRound", vote.Round) cs.LockedRound = 0 cs.LockedBlock = nil cs.LockedBlockParts = nil @@ -1122,7 +1107,7 @@ func (cs *ConsensusState) addVote(address []byte, vote *types.Vote, peerKey stri } case types.VoteTypePrecommit: precommits := cs.Votes.Precommits(vote.Round) - log.Debug(Fmt("Added to precommit: %v", precommits.StringShort())) + log.Info(Fmt("Added to precommit: %v", precommits.StringShort())) if cs.Round <= vote.Round && precommits.HasTwoThirdsAny() { go func() { hash, _, ok := precommits.TwoThirdsMajority() @@ -1141,7 +1126,7 @@ func (cs *ConsensusState) addVote(address []byte, vote *types.Vote, peerKey stri }() } default: - panic(Fmt("Unexpected vote type %X", vote.Type)) // Should not happen. + PanicSanity(Fmt("Unexpected vote type %X", vote.Type)) // Should not happen. } } // Either duplicate, or error upon cs.Votes.AddByAddress() @@ -1149,13 +1134,13 @@ func (cs *ConsensusState) addVote(address []byte, vote *types.Vote, peerKey stri } // Height mismatch, bad peer? - log.Debug("Vote ignored and not added", "voteHeight", vote.Height, "csHeight", cs.Height) + log.Info("Vote ignored and not added", "voteHeight", vote.Height, "csHeight", cs.Height) return } func (cs *ConsensusState) stageBlock(block *types.Block, blockParts *types.PartSet) error { if block == nil { - panic("Cannot stage nil block") + PanicSanity("Cannot stage nil block") } // Already staged? @@ -1196,7 +1181,7 @@ func (cs *ConsensusState) signAddVote(type_ byte, hash []byte, header types.Part err := cs.privValidator.SignVote(cs.state.ChainID, vote) if err == nil { _, _, err := cs.addVote(cs.privValidator.Address, vote, "") - log.Info("Signed and added vote", "height", cs.Height, "round", cs.Round, "vote", vote, "error", err) + log.Notice("Signed and added vote", "height", cs.Height, "round", cs.Round, "vote", vote, "error", err) return vote } else { log.Warn("Error signing vote", "height", cs.Height, "round", cs.Round, "vote", vote, "error", err) @@ -1209,7 +1194,7 @@ func (cs *ConsensusState) saveBlock(block *types.Block, blockParts *types.PartSe // The proposal must be valid. if err := cs.stageBlock(block, blockParts); err != nil { - panic(Fmt("saveBlock() an invalid block: %v", err)) + PanicSanity(Fmt("saveBlock() an invalid block: %v", err)) } // Save to blockStore. @@ -1236,3 +1221,7 @@ func (cs *ConsensusState) saveBlock(block *types.Block, blockParts *types.PartSe func (cs *ConsensusState) SetFireable(evsw events.Fireable) { cs.evsw = evsw } + +func (cs *ConsensusState) String() string { + return Fmt("ConsensusState(H:%v R:%v S:%v", cs.Height, cs.Round, cs.Step) +} diff --git a/Godeps/_workspace/src/github.com/tendermint/tendermint/consensus/types/proposal.go b/Godeps/_workspace/src/github.com/tendermint/tendermint/consensus/types/proposal.go index 54e04138..5e9c5089 100644 --- a/Godeps/_workspace/src/github.com/tendermint/tendermint/consensus/types/proposal.go +++ b/Godeps/_workspace/src/github.com/tendermint/tendermint/consensus/types/proposal.go @@ -5,10 +5,10 @@ import ( "fmt" "io" - "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/account" - "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/binary" + acm "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/account" . "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/common" "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/types" + "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/wire" ) var ( @@ -17,11 +17,11 @@ var ( ) type Proposal struct { - Height int `json:"height"` - Round int `json:"round"` - BlockPartsHeader types.PartSetHeader `json:"block_parts_header"` - POLRound int `json:"pol_round"` // -1 if null. - Signature account.SignatureEd25519 `json:"signature"` + Height int `json:"height"` + Round int `json:"round"` + BlockPartsHeader types.PartSetHeader `json:"block_parts_header"` + POLRound int `json:"pol_round"` // -1 if null. + Signature acm.SignatureEd25519 `json:"signature"` } func NewProposal(height int, round int, blockPartsHeader types.PartSetHeader, polRound int) *Proposal { @@ -39,9 +39,9 @@ func (p *Proposal) String() string { } func (p *Proposal) WriteSignBytes(chainID string, w io.Writer, n *int64, err *error) { - binary.WriteTo([]byte(Fmt(`{"chain_id":"%s"`, chainID)), w, n, err) - binary.WriteTo([]byte(`,"proposal":{"block_parts_header":`), w, n, err) + wire.WriteTo([]byte(Fmt(`{"chain_id":"%s"`, chainID)), w, n, err) + wire.WriteTo([]byte(`,"proposal":{"block_parts_header":`), w, n, err) p.BlockPartsHeader.WriteSignBytes(w, n, err) - binary.WriteTo([]byte(Fmt(`,"height":%v,"pol_round":%v`, p.Height, p.POLRound)), w, n, err) - binary.WriteTo([]byte(Fmt(`,"round":%v}}`, p.Round)), w, n, err) + wire.WriteTo([]byte(Fmt(`,"height":%v,"pol_round":%v`, p.Height, p.POLRound)), w, n, err) + wire.WriteTo([]byte(Fmt(`,"round":%v}}`, p.Round)), w, n, err) } diff --git a/Godeps/_workspace/src/github.com/tendermint/tendermint/consensus/types/proposal_test.go b/Godeps/_workspace/src/github.com/tendermint/tendermint/consensus/types/proposal_test.go index a9f435c8..ccba09ad 100644 --- a/Godeps/_workspace/src/github.com/tendermint/tendermint/consensus/types/proposal_test.go +++ b/Godeps/_workspace/src/github.com/tendermint/tendermint/consensus/types/proposal_test.go @@ -3,7 +3,7 @@ package consensus import ( "testing" - "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/account" + acm "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/account" . "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/common" _ "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/config/tendermint_test" "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/types" @@ -15,9 +15,8 @@ func TestProposalSignable(t *testing.T) { Round: 23456, BlockPartsHeader: types.PartSetHeader{111, []byte("blockparts")}, POLRound: -1, - Signature: nil, } - signBytes := account.SignBytes(config.GetString("chain_id"), proposal) + signBytes := acm.SignBytes(config.GetString("chain_id"), proposal) signStr := string(signBytes) expected := Fmt(`{"chain_id":"%s","proposal":{"block_parts_header":{"hash":"626C6F636B7061727473","total":111},"height":12345,"pol_round":-1,"round":23456}}`, diff --git a/Godeps/_workspace/src/github.com/tendermint/tendermint/consensus/vote_set.go b/Godeps/_workspace/src/github.com/tendermint/tendermint/consensus/vote_set.go index 075817bb..aebcd643 100644 --- a/Godeps/_workspace/src/github.com/tendermint/tendermint/consensus/vote_set.go +++ b/Godeps/_workspace/src/github.com/tendermint/tendermint/consensus/vote_set.go @@ -6,11 +6,11 @@ import ( "strings" "sync" - "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/account" - "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/binary" + acm "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/account" . "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/common" sm "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/state" "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/types" + "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/wire" ) // VoteSet helps collect signatures from validators at each height+round @@ -37,7 +37,7 @@ type VoteSet struct { // Constructs a new VoteSet struct used to accumulate votes for given height/round. func NewVoteSet(height int, round int, type_ byte, valSet *sm.ValidatorSet) *VoteSet { if height == 0 { - panic("Cannot make VoteSet for height == 0, doesn't make sense.") + PanicSanity("Cannot make VoteSet for height == 0, doesn't make sense.") } return &VoteSet{ height: height, @@ -131,7 +131,7 @@ func (voteSet *VoteSet) addVote(val *sm.Validator, valIndex int, vote *types.Vot } // Check signature. - if !val.PubKey.VerifyBytes(account.SignBytes(config.GetString("chain_id"), vote), vote.Signature) { + if !val.PubKey.VerifyBytes(acm.SignBytes(config.GetString("chain_id"), vote), vote.Signature) { // Bad signature. return false, 0, types.ErrVoteInvalidSignature } @@ -151,7 +151,7 @@ func (voteSet *VoteSet) addVote(val *sm.Validator, valIndex int, vote *types.Vot // Add vote. voteSet.votes[valIndex] = vote voteSet.votesBitArray.SetIndex(valIndex, true) - blockKey := string(vote.BlockHash) + string(binary.BinaryBytes(vote.BlockParts)) + blockKey := string(vote.BlockHash) + string(wire.BinaryBytes(vote.BlockParts)) totalBlockHashVotes := voteSet.votesByBlock[blockKey] + val.VotingPower voteSet.votesByBlock[blockKey] = totalBlockHashVotes voteSet.totalVotes += val.VotingPower @@ -187,7 +187,7 @@ func (voteSet *VoteSet) GetByAddress(address []byte) *types.Vote { defer voteSet.mtx.Unlock() valIndex, val := voteSet.valSet.GetByAddress(address) if val == nil { - panic("GetByAddress(address) returned nil") + PanicSanity("GetByAddress(address) returned nil") } return voteSet.votes[valIndex] } @@ -273,12 +273,12 @@ func (voteSet *VoteSet) StringShort() string { func (voteSet *VoteSet) MakeValidation() *types.Validation { if voteSet.type_ != types.VoteTypePrecommit { - panic("Cannot MakeValidation() unless VoteSet.Type is types.VoteTypePrecommit") + PanicSanity("Cannot MakeValidation() unless VoteSet.Type is types.VoteTypePrecommit") } voteSet.mtx.Lock() defer voteSet.mtx.Unlock() if len(voteSet.maj23Hash) == 0 { - panic("Cannot MakeValidation() unless a blockhash has +2/3") + PanicSanity("Cannot MakeValidation() unless a blockhash has +2/3") } precommits := make([]*types.Vote, voteSet.valSet.Size()) voteSet.valSet.Iterate(func(valIndex int, val *sm.Validator) bool { diff --git a/Godeps/_workspace/src/github.com/tendermint/tendermint/db/db.go b/Godeps/_workspace/src/github.com/tendermint/tendermint/db/db.go index f27e4c21..1e4933cf 100644 --- a/Godeps/_workspace/src/github.com/tendermint/tendermint/db/db.go +++ b/Godeps/_workspace/src/github.com/tendermint/tendermint/db/db.go @@ -39,11 +39,12 @@ func GetDB(name string) DB { case DBBackendLevelDB: db, err := NewLevelDB(path.Join(config.GetString("db_dir"), name+".db")) if err != nil { - panic(err) + PanicCrisis(err) } dbs.Set(name, db) return db default: - panic(Fmt("Unknown DB backend: %v", config.GetString("db_backend"))) + PanicSanity(Fmt("Unknown DB backend: %v", config.GetString("db_backend"))) } + return nil } diff --git a/Godeps/_workspace/src/github.com/tendermint/tendermint/db/level_db.go b/Godeps/_workspace/src/github.com/tendermint/tendermint/db/level_db.go index 0bf65f42..66cf9190 100644 --- a/Godeps/_workspace/src/github.com/tendermint/tendermint/db/level_db.go +++ b/Godeps/_workspace/src/github.com/tendermint/tendermint/db/level_db.go @@ -6,6 +6,8 @@ import ( "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/errors" "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/opt" "path" + + . "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/common" ) type LevelDB struct { @@ -28,7 +30,7 @@ func (db *LevelDB) Get(key []byte) []byte { if err == errors.ErrNotFound { return nil } else { - panic(err) + PanicCrisis(err) } } return res @@ -37,28 +39,28 @@ func (db *LevelDB) Get(key []byte) []byte { func (db *LevelDB) Set(key []byte, value []byte) { err := db.db.Put(key, value, nil) if err != nil { - panic(err) + PanicCrisis(err) } } func (db *LevelDB) SetSync(key []byte, value []byte) { err := db.db.Put(key, value, &opt.WriteOptions{Sync: true}) if err != nil { - panic(err) + PanicCrisis(err) } } func (db *LevelDB) Delete(key []byte) { err := db.db.Delete(key, nil) if err != nil { - panic(err) + PanicCrisis(err) } } func (db *LevelDB) DeleteSync(key []byte) { err := db.db.Delete(key, &opt.WriteOptions{Sync: true}) if err != nil { - panic(err) + PanicCrisis(err) } } diff --git a/Godeps/_workspace/src/github.com/tendermint/tendermint/events/events.go b/Godeps/_workspace/src/github.com/tendermint/tendermint/events/events.go index 13aca2da..07ef12b9 100644 --- a/Godeps/_workspace/src/github.com/tendermint/tendermint/events/events.go +++ b/Godeps/_workspace/src/github.com/tendermint/tendermint/events/events.go @@ -2,7 +2,8 @@ package events import ( "sync" - "sync/atomic" + + . "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/common" ) // reactors and other modules should export @@ -17,27 +18,29 @@ type Fireable interface { } type EventSwitch struct { + BaseService + mtx sync.RWMutex eventCells map[string]*eventCell listeners map[string]*eventListener - running uint32 - quit chan struct{} } -func (evsw *EventSwitch) Start() { - if atomic.CompareAndSwapUint32(&evsw.running, 0, 1) { - evsw.eventCells = make(map[string]*eventCell) - evsw.listeners = make(map[string]*eventListener) - evsw.quit = make(chan struct{}) - } +func NewEventSwitch() *EventSwitch { + evsw := &EventSwitch{} + evsw.BaseService = *NewBaseService(log, "EventSwitch", evsw) + return evsw } -func (evsw *EventSwitch) Stop() { - if atomic.CompareAndSwapUint32(&evsw.running, 1, 0) { - evsw.eventCells = nil - evsw.listeners = nil - close(evsw.quit) - } +func (evsw *EventSwitch) OnStart() { + evsw.BaseService.OnStart() + evsw.eventCells = make(map[string]*eventCell) + evsw.listeners = make(map[string]*eventListener) +} + +func (evsw *EventSwitch) OnStop() { + evsw.BaseService.OnStop() + evsw.eventCells = nil + evsw.listeners = nil } func (evsw *EventSwitch) AddListenerForEvent(listenerId, event string, cb eventCallback) { diff --git a/Godeps/_workspace/src/github.com/tendermint/tendermint/events/log.go b/Godeps/_workspace/src/github.com/tendermint/tendermint/events/log.go new file mode 100644 index 00000000..232ef667 --- /dev/null +++ b/Godeps/_workspace/src/github.com/tendermint/tendermint/events/log.go @@ -0,0 +1,7 @@ +package events + +import ( + "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/logger" +) + +var log = logger.New("module", "events") diff --git a/Godeps/_workspace/src/github.com/tendermint/tendermint/mempool/mempool.go b/Godeps/_workspace/src/github.com/tendermint/tendermint/mempool/mempool.go index 2fa6999c..c1b580f4 100644 --- a/Godeps/_workspace/src/github.com/tendermint/tendermint/mempool/mempool.go +++ b/Godeps/_workspace/src/github.com/tendermint/tendermint/mempool/mempool.go @@ -43,10 +43,10 @@ func (mem *Mempool) AddTx(tx types.Tx) (err error) { defer mem.mtx.Unlock() err = sm.ExecTx(mem.cache, tx, false, nil) if err != nil { - log.Debug("AddTx() error", "tx", tx, "error", err) + log.Info("AddTx() error", "tx", tx, "error", err) return err } else { - log.Debug("AddTx() success", "tx", tx) + log.Info("AddTx() success", "tx", tx) mem.txs = append(mem.txs, tx) return nil } @@ -55,7 +55,7 @@ func (mem *Mempool) AddTx(tx types.Tx) (err error) { func (mem *Mempool) GetProposalTxs() []types.Tx { mem.mtx.Lock() defer mem.mtx.Unlock() - log.Debug("GetProposalTxs:", "txs", mem.txs) + log.Info("GetProposalTxs:", "txs", mem.txs) return mem.txs } @@ -80,10 +80,10 @@ func (mem *Mempool) ResetForBlockAndState(block *types.Block, state *sm.State) { for _, tx := range mem.txs { txID := types.TxID(state.ChainID, tx) if _, ok := blockTxsMap[string(txID)]; ok { - log.Debug("Filter out, already committed", "tx", tx, "txID", txID) + log.Info("Filter out, already committed", "tx", tx, "txID", txID) continue } else { - log.Debug("Filter in, still new", "tx", tx, "txID", txID) + log.Info("Filter in, still new", "tx", tx, "txID", txID) txs = append(txs, tx) } } @@ -93,15 +93,15 @@ func (mem *Mempool) ResetForBlockAndState(block *types.Block, state *sm.State) { for _, tx := range txs { err := sm.ExecTx(mem.cache, tx, false, nil) if err == nil { - log.Debug("Filter in, valid", "tx", tx) + log.Info("Filter in, valid", "tx", tx) validTxs = append(validTxs, tx) } else { // tx is no longer valid. - log.Debug("Filter out, no longer valid", "tx", tx, "error", err) + log.Info("Filter out, no longer valid", "tx", tx, "error", err) } } // We're done! - log.Debug("New txs", "txs", validTxs, "oldTxs", mem.txs) + log.Info("New txs", "txs", validTxs, "oldTxs", mem.txs) mem.txs = validTxs } diff --git a/Godeps/_workspace/src/github.com/tendermint/tendermint/mempool/reactor.go b/Godeps/_workspace/src/github.com/tendermint/tendermint/mempool/reactor.go index 570c4d08..6db40539 100644 --- a/Godeps/_workspace/src/github.com/tendermint/tendermint/mempool/reactor.go +++ b/Godeps/_workspace/src/github.com/tendermint/tendermint/mempool/reactor.go @@ -4,13 +4,12 @@ import ( "bytes" "fmt" "reflect" - "sync/atomic" - "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/binary" . "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/common" "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/events" "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/p2p" "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/types" + "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/wire" ) var ( @@ -19,11 +18,9 @@ var ( // MempoolReactor handles mempool tx broadcasting amongst peers. type MempoolReactor struct { - sw *p2p.Switch - quit chan struct{} - started uint32 - stopped uint32 + p2p.BaseReactor + sw *p2p.Switch Mempool *Mempool evsw events.Fireable @@ -31,27 +28,15 @@ type MempoolReactor struct { func NewMempoolReactor(mempool *Mempool) *MempoolReactor { memR := &MempoolReactor{ - quit: make(chan struct{}), Mempool: mempool, } + memR.BaseReactor = *p2p.NewBaseReactor(log, "MempoolReactor", memR) return memR } -// Implements Reactor -func (memR *MempoolReactor) Start(sw *p2p.Switch) { - if atomic.CompareAndSwapUint32(&memR.started, 0, 1) { - memR.sw = sw - log.Info("Starting MempoolReactor") - } -} +// func (memR *MempoolReactor) OnStart() { memR.BaseReactor.OnStart() } -// Implements Reactor -func (memR *MempoolReactor) Stop() { - if atomic.CompareAndSwapUint32(&memR.stopped, 0, 1) { - log.Info("Stopping MempoolReactor") - close(memR.quit) - } -} +// func (memR *MempoolReactor) OnStop() { memR.BaseReactor.OnStop() } // Implements Reactor func (memR *MempoolReactor) GetChannels() []*p2p.ChannelDescriptor { @@ -78,22 +63,22 @@ func (memR *MempoolReactor) Receive(chId byte, src *p2p.Peer, msgBytes []byte) { log.Warn("Error decoding message", "error", err) return } - log.Info("MempoolReactor received message", "msg", msg) + log.Notice("MempoolReactor received message", "msg", msg) switch msg := msg.(type) { case *TxMessage: err := memR.Mempool.AddTx(msg.Tx) if err != nil { // Bad, seen, or conflicting tx. - log.Debug("Could not add tx", "tx", msg.Tx) + log.Info("Could not add tx", "tx", msg.Tx) return } else { - log.Debug("Added valid tx", "tx", msg.Tx) + log.Info("Added valid tx", "tx", msg.Tx) } // Share tx. // We use a simple shotgun approach for now. // TODO: improve efficiency - for _, peer := range memR.sw.Peers().List() { + for _, peer := range memR.Switch.Peers().List() { if peer.Key == src.Key { continue } @@ -111,7 +96,7 @@ func (memR *MempoolReactor) BroadcastTx(tx types.Tx) error { return err } msg := &TxMessage{Tx: tx} - memR.sw.Broadcast(MempoolChannel, msg) + memR.Switch.Broadcast(MempoolChannel, msg) return nil } @@ -129,16 +114,16 @@ const ( type MempoolMessage interface{} -var _ = binary.RegisterInterface( +var _ = wire.RegisterInterface( struct{ MempoolMessage }{}, - binary.ConcreteType{&TxMessage{}, msgTypeTx}, + wire.ConcreteType{&TxMessage{}, msgTypeTx}, ) func DecodeMessage(bz []byte) (msgType byte, msg MempoolMessage, err error) { msgType = bz[0] n := new(int64) r := bytes.NewReader(bz) - msg = binary.ReadBinary(struct{ MempoolMessage }{}, r, n, &err).(struct{ MempoolMessage }).MempoolMessage + msg = wire.ReadBinary(struct{ MempoolMessage }{}, r, n, &err).(struct{ MempoolMessage }).MempoolMessage return } diff --git a/Godeps/_workspace/src/github.com/tendermint/tendermint/merkle/iavl_node.go b/Godeps/_workspace/src/github.com/tendermint/tendermint/merkle/iavl_node.go index 1e71bb1c..884842a6 100644 --- a/Godeps/_workspace/src/github.com/tendermint/tendermint/merkle/iavl_node.go +++ b/Godeps/_workspace/src/github.com/tendermint/tendermint/merkle/iavl_node.go @@ -5,7 +5,8 @@ import ( "github.com/eris-ltd/eris-db/Godeps/_workspace/src/code.google.com/p/go.crypto/ripemd160" "io" - "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/binary" + . "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/common" + "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/wire" ) // Node @@ -38,8 +39,8 @@ func ReadIAVLNode(t *IAVLTree, r io.Reader, n *int64, err *error) *IAVLNode { node := &IAVLNode{} // node header - node.height = binary.ReadInt8(r, n, err) - node.size = binary.ReadVarint(r, n, err) + node.height = wire.ReadInt8(r, n, err) + node.size = wire.ReadVarint(r, n, err) node.key = decodeByteSlice(t.keyCodec, r, n, err) if node.height == 0 { @@ -47,18 +48,15 @@ func ReadIAVLNode(t *IAVLTree, r io.Reader, n *int64, err *error) *IAVLNode { node.value = decodeByteSlice(t.valueCodec, r, n, err) } else { // children - node.leftHash = binary.ReadByteSlice(r, n, err) - node.rightHash = binary.ReadByteSlice(r, n, err) - } - if *err != nil { - panic(*err) + node.leftHash = wire.ReadByteSlice(r, n, err) + node.rightHash = wire.ReadByteSlice(r, n, err) } return node } func (node *IAVLNode) _copy() *IAVLNode { if node.height == 0 { - panic("Why are you copying a value node?") + PanicSanity("Why are you copying a value node?") } return &IAVLNode{ key: node.key, @@ -112,7 +110,8 @@ func (node *IAVLNode) getByIndex(t *IAVLTree, index int) (key interface{}, value if index == 0 { return node.key, node.value } else { - panic("getByIndex asked for invalid index") + PanicSanity("getByIndex asked for invalid index") + return nil, nil } } else { // TODO: could improve this by storing the @@ -136,7 +135,7 @@ func (node *IAVLNode) hashWithCount(t *IAVLTree) ([]byte, int) { buf := new(bytes.Buffer) _, hashCount, err := node.writeHashBytes(t, buf) if err != nil { - panic(err) + PanicCrisis(err) } // fmt.Printf("Wrote IAVL hash bytes: %X\n", buf.Bytes()) hasher.Write(buf.Bytes()) @@ -149,8 +148,8 @@ func (node *IAVLNode) hashWithCount(t *IAVLTree) ([]byte, int) { // NOTE: sets hashes recursively func (node *IAVLNode) writeHashBytes(t *IAVLTree, w io.Writer) (n int64, hashCount int, err error) { // height & size - binary.WriteInt8(node.height, w, &n, &err) - binary.WriteVarint(node.size, w, &n, &err) + wire.WriteInt8(node.height, w, &n, &err) + wire.WriteVarint(node.size, w, &n, &err) // key is not written for inner nodes, unlike writePersistBytes if node.height == 0 { @@ -165,9 +164,9 @@ func (node *IAVLNode) writeHashBytes(t *IAVLTree, w io.Writer) (n int64, hashCou hashCount += leftCount } if node.leftHash == nil { - panic("node.leftHash was nil in writeHashBytes") + PanicSanity("node.leftHash was nil in writeHashBytes") } - binary.WriteByteSlice(node.leftHash, w, &n, &err) + wire.WriteByteSlice(node.leftHash, w, &n, &err) // right if node.rightNode != nil { rightHash, rightCount := node.rightNode.hashWithCount(t) @@ -175,9 +174,9 @@ func (node *IAVLNode) writeHashBytes(t *IAVLTree, w io.Writer) (n int64, hashCou hashCount += rightCount } if node.rightHash == nil { - panic("node.rightHash was nil in writeHashBytes") + PanicSanity("node.rightHash was nil in writeHashBytes") } - binary.WriteByteSlice(node.rightHash, w, &n, &err) + wire.WriteByteSlice(node.rightHash, w, &n, &err) } return } @@ -210,8 +209,8 @@ func (node *IAVLNode) save(t *IAVLTree) []byte { // NOTE: sets hashes recursively func (node *IAVLNode) writePersistBytes(t *IAVLTree, w io.Writer) (n int64, err error) { // node header - binary.WriteInt8(node.height, w, &n, &err) - binary.WriteVarint(node.size, w, &n, &err) + wire.WriteInt8(node.height, w, &n, &err) + wire.WriteVarint(node.size, w, &n, &err) // key (unlike writeHashBytes, key is written for inner nodes) encodeByteSlice(node.key, t.keyCodec, w, &n, &err) @@ -221,14 +220,14 @@ func (node *IAVLNode) writePersistBytes(t *IAVLTree, w io.Writer) (n int64, err } else { // left if node.leftHash == nil { - panic("node.leftHash was nil in writePersistBytes") + PanicSanity("node.leftHash was nil in writePersistBytes") } - binary.WriteByteSlice(node.leftHash, w, &n, &err) + wire.WriteByteSlice(node.leftHash, w, &n, &err) // right if node.rightHash == nil { - panic("node.rightHash was nil in writePersistBytes") + PanicSanity("node.rightHash was nil in writePersistBytes") } - binary.WriteByteSlice(node.rightHash, w, &n, &err) + wire.WriteByteSlice(node.rightHash, w, &n, &err) } return } @@ -440,8 +439,8 @@ func (node *IAVLNode) rmd(t *IAVLTree) *IAVLNode { //-------------------------------------------------------------------------------- // Read a (length prefixed) byteslice then decode the object using the codec -func decodeByteSlice(codec binary.Codec, r io.Reader, n *int64, err *error) interface{} { - bytez := binary.ReadByteSlice(r, n, err) +func decodeByteSlice(codec wire.Codec, r io.Reader, n *int64, err *error) interface{} { + bytez := wire.ReadByteSlice(r, n, err) if *err != nil { return nil } @@ -450,11 +449,11 @@ func decodeByteSlice(codec binary.Codec, r io.Reader, n *int64, err *error) inte } // Encode object using codec, then write a (length prefixed) byteslice. -func encodeByteSlice(o interface{}, codec binary.Codec, w io.Writer, n *int64, err *error) { +func encodeByteSlice(o interface{}, codec wire.Codec, w io.Writer, n *int64, err *error) { buf, n_ := new(bytes.Buffer), new(int64) codec.Encode(o, buf, n_, err) if *err != nil { return } - binary.WriteByteSlice(buf.Bytes(), w, n, err) + wire.WriteByteSlice(buf.Bytes(), w, n, err) } diff --git a/Godeps/_workspace/src/github.com/tendermint/tendermint/merkle/iavl_proof.go b/Godeps/_workspace/src/github.com/tendermint/tendermint/merkle/iavl_proof.go index a2f63197..f86efe46 100644 --- a/Godeps/_workspace/src/github.com/tendermint/tendermint/merkle/iavl_proof.go +++ b/Godeps/_workspace/src/github.com/tendermint/tendermint/merkle/iavl_proof.go @@ -5,8 +5,8 @@ import ( "github.com/eris-ltd/eris-db/Godeps/_workspace/src/code.google.com/p/go.crypto/ripemd160" - "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/binary" . "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/common" + "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/wire" ) type IAVLProof struct { @@ -46,17 +46,17 @@ func (branch IAVLProofInnerNode) Hash(childHash []byte) []byte { hasher := ripemd160.New() buf := new(bytes.Buffer) n, err := int64(0), error(nil) - binary.WriteInt8(branch.Height, buf, &n, &err) - binary.WriteVarint(branch.Size, buf, &n, &err) + wire.WriteInt8(branch.Height, buf, &n, &err) + wire.WriteVarint(branch.Size, buf, &n, &err) if len(branch.Left) == 0 { - binary.WriteByteSlice(childHash, buf, &n, &err) - binary.WriteByteSlice(branch.Right, buf, &n, &err) + wire.WriteByteSlice(childHash, buf, &n, &err) + wire.WriteByteSlice(branch.Right, buf, &n, &err) } else { - binary.WriteByteSlice(branch.Left, buf, &n, &err) - binary.WriteByteSlice(childHash, buf, &n, &err) + wire.WriteByteSlice(branch.Left, buf, &n, &err) + wire.WriteByteSlice(childHash, buf, &n, &err) } if err != nil { - panic(Fmt("Failed to hash IAVLProofInnerNode: %v", err)) + PanicCrisis(Fmt("Failed to hash IAVLProofInnerNode: %v", err)) } // fmt.Printf("InnerNode hash bytes: %X\n", buf.Bytes()) hasher.Write(buf.Bytes()) @@ -72,12 +72,12 @@ func (leaf IAVLProofLeafNode) Hash() []byte { hasher := ripemd160.New() buf := new(bytes.Buffer) n, err := int64(0), error(nil) - binary.WriteInt8(0, buf, &n, &err) - binary.WriteVarint(1, buf, &n, &err) - binary.WriteByteSlice(leaf.KeyBytes, buf, &n, &err) - binary.WriteByteSlice(leaf.ValueBytes, buf, &n, &err) + wire.WriteInt8(0, buf, &n, &err) + wire.WriteVarint(1, buf, &n, &err) + wire.WriteByteSlice(leaf.KeyBytes, buf, &n, &err) + wire.WriteByteSlice(leaf.ValueBytes, buf, &n, &err) if err != nil { - panic(Fmt("Failed to hash IAVLProofLeafNode: %v", err)) + PanicCrisis(Fmt("Failed to hash IAVLProofLeafNode: %v", err)) } // fmt.Printf("LeafNode hash bytes: %X\n", buf.Bytes()) hasher.Write(buf.Bytes()) @@ -91,11 +91,11 @@ func (node *IAVLNode) constructProof(t *IAVLTree, key interface{}, proof *IAVLPr n, err := int64(0), error(nil) t.keyCodec.Encode(node.key, keyBuf, &n, &err) if err != nil { - panic(Fmt("Failed to encode node.key: %v", err)) + PanicCrisis(Fmt("Failed to encode node.key: %v", err)) } t.valueCodec.Encode(node.value, valueBuf, &n, &err) if err != nil { - panic(Fmt("Failed to encode node.value: %v", err)) + PanicCrisis(Fmt("Failed to encode node.value: %v", err)) } leaf := IAVLProofLeafNode{ KeyBytes: keyBuf.Bytes(), diff --git a/Godeps/_workspace/src/github.com/tendermint/tendermint/merkle/iavl_test.go b/Godeps/_workspace/src/github.com/tendermint/tendermint/merkle/iavl_test.go index 48612570..bf97067f 100644 --- a/Godeps/_workspace/src/github.com/tendermint/tendermint/merkle/iavl_test.go +++ b/Godeps/_workspace/src/github.com/tendermint/tendermint/merkle/iavl_test.go @@ -4,10 +4,10 @@ import ( "bytes" "fmt" - "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/binary" . "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/common" . "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/common/test" "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/db" + "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/wire" "runtime" "testing" @@ -43,7 +43,7 @@ func N(l, r interface{}) *IAVLNode { // Setup a deep node func T(n *IAVLNode) *IAVLTree { - t := NewIAVLTree(binary.BasicCodec, binary.BasicCodec, 0, nil) + t := NewIAVLTree(wire.BasicCodec, wire.BasicCodec, 0, nil) n.hashWithCount(t) t.root = n return t @@ -149,7 +149,7 @@ func TestIntegration(t *testing.T) { } records := make([]*record, 400) - var tree *IAVLTree = NewIAVLTree(binary.BasicCodec, binary.BasicCodec, 0, nil) + var tree *IAVLTree = NewIAVLTree(wire.BasicCodec, wire.BasicCodec, 0, nil) randomRecord := func() *record { return &record{randstr(20), randstr(20)} @@ -219,7 +219,7 @@ func TestPersistence(t *testing.T) { } // Construct some tree and save it - t1 := NewIAVLTree(binary.BasicCodec, binary.BasicCodec, 0, db) + t1 := NewIAVLTree(wire.BasicCodec, wire.BasicCodec, 0, db) for key, value := range records { t1.Set(key, value) } @@ -228,7 +228,7 @@ func TestPersistence(t *testing.T) { hash, _ := t1.HashWithCount() // Load a tree - t2 := NewIAVLTree(binary.BasicCodec, binary.BasicCodec, 0, db) + t2 := NewIAVLTree(wire.BasicCodec, wire.BasicCodec, 0, db) t2.Load(hash) for key, value := range records { _, t2value := t2.Get(key) @@ -245,15 +245,15 @@ func testProof(t *testing.T, proof *IAVLProof, keyBytes, valueBytes, rootHash [] return } // Write/Read then verify. - proofBytes := binary.BinaryBytes(proof) + proofBytes := wire.BinaryBytes(proof) n, err := int64(0), error(nil) - proof2 := binary.ReadBinary(&IAVLProof{}, bytes.NewBuffer(proofBytes), &n, &err).(*IAVLProof) + proof2 := wire.ReadBinary(&IAVLProof{}, bytes.NewBuffer(proofBytes), &n, &err).(*IAVLProof) if err != nil { t.Errorf("Failed to read IAVLProof from bytes: %v", err) return } if !proof2.Verify(keyBytes, valueBytes, rootHash) { - // t.Log(Fmt("%X\n%X\n", proofBytes, binary.BinaryBytes(proof2))) + // t.Log(Fmt("%X\n%X\n", proofBytes, wire.BinaryBytes(proof2))) t.Errorf("Invalid proof after write/read. Verification failed.") return } @@ -261,7 +261,7 @@ func testProof(t *testing.T, proof *IAVLProof, keyBytes, valueBytes, rootHash [] for i := 0; i < 5; i++ { badProofBytes := MutateByteSlice(proofBytes) n, err := int64(0), error(nil) - badProof := binary.ReadBinary(&IAVLProof{}, bytes.NewBuffer(badProofBytes), &n, &err).(*IAVLProof) + badProof := wire.ReadBinary(&IAVLProof{}, bytes.NewBuffer(badProofBytes), &n, &err).(*IAVLProof) if err != nil { continue // This is fine. } @@ -273,10 +273,10 @@ func testProof(t *testing.T, proof *IAVLProof, keyBytes, valueBytes, rootHash [] func TestIAVLProof(t *testing.T) { - // Convenient wrapper around binary.BasicCodec. + // Convenient wrapper around wire.BasicCodec. toBytes := func(o interface{}) []byte { buf, n, err := new(bytes.Buffer), int64(0), error(nil) - binary.BasicCodec.Encode(o, buf, &n, &err) + wire.BasicCodec.Encode(o, buf, &n, &err) if err != nil { panic(Fmt("Failed to encode thing: %v", err)) } @@ -285,7 +285,7 @@ func TestIAVLProof(t *testing.T) { // Construct some random tree db := db.NewMemDB() - var tree *IAVLTree = NewIAVLTree(binary.BasicCodec, binary.BasicCodec, 100, db) + var tree *IAVLTree = NewIAVLTree(wire.BasicCodec, wire.BasicCodec, 100, db) for i := 0; i < 1000; i++ { key, value := randstr(20), randstr(20) tree.Set(key, value) @@ -315,7 +315,7 @@ func TestIAVLProof(t *testing.T) { func BenchmarkImmutableAvlTree(b *testing.B) { b.StopTimer() - t := NewIAVLTree(binary.BasicCodec, binary.BasicCodec, 0, nil) + t := NewIAVLTree(wire.BasicCodec, wire.BasicCodec, 0, nil) // 23000ns/op, 43000ops/s // for i := 0; i < 10000000; i++ { for i := 0; i < 1000000; i++ { diff --git a/Godeps/_workspace/src/github.com/tendermint/tendermint/merkle/iavl_tree.go b/Godeps/_workspace/src/github.com/tendermint/tendermint/merkle/iavl_tree.go index 84e548a6..b8177f6a 100644 --- a/Godeps/_workspace/src/github.com/tendermint/tendermint/merkle/iavl_tree.go +++ b/Godeps/_workspace/src/github.com/tendermint/tendermint/merkle/iavl_tree.go @@ -5,9 +5,9 @@ import ( "container/list" "sync" - "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/binary" . "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/common" dbm "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/db" + "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/wire" ) /* @@ -15,13 +15,13 @@ Immutable AVL Tree (wraps the Node root) This tree is not goroutine safe. */ type IAVLTree struct { - keyCodec binary.Codec - valueCodec binary.Codec + keyCodec wire.Codec + valueCodec wire.Codec root *IAVLNode ndb *nodeDB } -func NewIAVLTree(keyCodec, valueCodec binary.Codec, cacheSize int, db dbm.DB) *IAVLTree { +func NewIAVLTree(keyCodec, valueCodec wire.Codec, cacheSize int, db dbm.DB) *IAVLTree { if db == nil { // In-memory IAVLTree return &IAVLTree{ @@ -54,7 +54,7 @@ func (t *IAVLTree) Copy() Tree { // It sets all the hashes recursively, // clears all the leftNode/rightNode values recursively, // and all the .persisted flags get set. - panic("It is unsafe to Copy() an unpersisted tree.") + PanicSanity("It is unsafe to Copy() an unpersisted tree.") } else if t.ndb == nil && t.root.hash == nil { // An in-memory IAVLTree is finalized when the hashes are // calculated. @@ -211,14 +211,14 @@ func (ndb *nodeDB) GetNode(t *IAVLTree, hash []byte) *IAVLNode { buf := ndb.db.Get(hash) if len(buf) == 0 { ndb.db.(*dbm.LevelDB).Print() - panic(Fmt("Value missing for key %X", hash)) + PanicSanity(Fmt("Value missing for key %X", hash)) } r := bytes.NewReader(buf) var n int64 var err error node := ReadIAVLNode(t, r, &n, &err) if err != nil { - panic(Fmt("Error reading IAVLNode. bytes: %X error: %v", buf, err)) + PanicCrisis(Fmt("Error reading IAVLNode. bytes: %X error: %v", buf, err)) } node.hash = hash node.persisted = true @@ -231,10 +231,10 @@ func (ndb *nodeDB) SaveNode(t *IAVLTree, node *IAVLNode) { ndb.mtx.Lock() defer ndb.mtx.Unlock() if node.hash == nil { - panic("Expected to find node.hash, but none found.") + PanicSanity("Expected to find node.hash, but none found.") } if node.persisted { - panic("Shouldn't be calling save on an already persisted node.") + PanicSanity("Shouldn't be calling save on an already persisted node.") } /*if _, ok := ndb.cache[string(node.hash)]; ok { panic("Shouldn't be calling save on an already cached node.") @@ -243,7 +243,7 @@ func (ndb *nodeDB) SaveNode(t *IAVLTree, node *IAVLNode) { buf := bytes.NewBuffer(nil) _, err := node.writePersistBytes(t, buf) if err != nil { - panic(err) + PanicCrisis(err) } ndb.db.Set(node.hash, buf.Bytes()) node.persisted = true diff --git a/Godeps/_workspace/src/github.com/tendermint/tendermint/merkle/simple_tree.go b/Godeps/_workspace/src/github.com/tendermint/tendermint/merkle/simple_tree.go index a37cd701..be2837c8 100644 --- a/Godeps/_workspace/src/github.com/tendermint/tendermint/merkle/simple_tree.go +++ b/Godeps/_workspace/src/github.com/tendermint/tendermint/merkle/simple_tree.go @@ -30,17 +30,18 @@ import ( "github.com/eris-ltd/eris-db/Godeps/_workspace/src/code.google.com/p/go.crypto/ripemd160" - "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/binary" + . "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/common" + "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/wire" ) func SimpleHashFromTwoHashes(left []byte, right []byte) []byte { var n int64 var err error var hasher = ripemd160.New() - binary.WriteByteSlice(left, hasher, &n, &err) - binary.WriteByteSlice(right, hasher, &n, &err) + wire.WriteByteSlice(left, hasher, &n, &err) + wire.WriteByteSlice(right, hasher, &n, &err) if err != nil { - panic(err) + PanicCrisis(err) } return hasher.Sum(nil) } @@ -71,9 +72,9 @@ func SimpleHashFromBinaries(items []interface{}) []byte { // General Convenience func SimpleHashFromBinary(item interface{}) []byte { hasher, n, err := ripemd160.New(), new(int64), new(error) - binary.WriteBinary(item, hasher, n, err) + wire.WriteBinary(item, hasher, n, err) if *err != nil { - panic(err) + PanicCrisis(err) } return hasher.Sum(nil) } @@ -162,7 +163,8 @@ func computeHashFromInnerHashes(index int, total int, leafHash []byte, innerHash } switch total { case 0: - panic("Cannot call computeHashFromInnerHashes() with 0 total") + PanicSanity("Cannot call computeHashFromInnerHashes() with 0 total") + return nil case 1: if len(innerHashes) != 0 { return nil diff --git a/Godeps/_workspace/src/github.com/tendermint/tendermint/node/node.go b/Godeps/_workspace/src/github.com/tendermint/tendermint/node/node.go index b025cb34..246a214b 100644 --- a/Godeps/_workspace/src/github.com/tendermint/tendermint/node/node.go +++ b/Godeps/_workspace/src/github.com/tendermint/tendermint/node/node.go @@ -2,7 +2,6 @@ package node import ( "bytes" - "fmt" "math/rand" "net" "net/http" @@ -12,7 +11,6 @@ import ( "time" acm "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/account" - "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/binary" bc "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/blockchain" . "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/common" "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/consensus" @@ -24,16 +22,11 @@ import ( "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/rpc/server" sm "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/state" "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/types" + "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/wire" ) import _ "net/http/pprof" -func init() { - go func() { - fmt.Println(http.ListenAndServe("0.0.0.0:6060", nil)) - }() -} - type Node struct { sw *p2p.Switch evsw *events.EventSwitch @@ -63,17 +56,19 @@ func NewNode() *Node { state.Save() // write the gendoc to db buf, n, err := new(bytes.Buffer), new(int64), new(error) - binary.WriteJSON(genDoc, buf, n, err) + wire.WriteJSON(genDoc, buf, n, err) stateDB.Set(sm.GenDocKey, buf.Bytes()) if *err != nil { - panic(Fmt("Unable to write gendoc to db: %v", err)) + log.Error("Unable to write gendoc to db", "error", err) + os.Exit(1) } } else { genDocBytes := stateDB.Get(sm.GenDocKey) err := new(error) - binary.ReadJSONPtr(&genDoc, genDocBytes, err) + wire.ReadJSONPtr(&genDoc, genDocBytes, err) if *err != nil { - panic(Fmt("Unable to read gendoc from db: %v", err)) + log.Error("Unable to read gendoc from db", "error", err) + os.Exit(1) } } // add the chainid to the global config @@ -84,41 +79,41 @@ func NewNode() *Node { privValidatorFile := config.GetString("priv_validator_file") if _, err := os.Stat(privValidatorFile); err == nil { privValidator = sm.LoadPrivValidator(privValidatorFile) - log.Info("Loaded PrivValidator", + log.Notice("Loaded PrivValidator", "file", privValidatorFile, "privValidator", privValidator) } else { privValidator = sm.GenPrivValidator() privValidator.SetFile(privValidatorFile) privValidator.Save() - log.Info("Generated PrivValidator", "file", privValidatorFile) + log.Notice("Generated PrivValidator", "file", privValidatorFile) } // Generate node PrivKey privKey := acm.GenPrivKeyEd25519() // Make event switch - eventSwitch := new(events.EventSwitch) + eventSwitch := events.NewEventSwitch() eventSwitch.Start() - // Get PEXReactor + // Make PEXReactor book := p2p.NewAddrBook(config.GetString("addrbook_file")) pexReactor := p2p.NewPEXReactor(book) - // Get BlockchainReactor + // Make BlockchainReactor bcReactor := bc.NewBlockchainReactor(state.Copy(), blockStore, config.GetBool("fast_sync")) - // Get MempoolReactor + // Make MempoolReactor mempool := mempl.NewMempool(state.Copy()) mempoolReactor := mempl.NewMempoolReactor(mempool) - // Get ConsensusReactor + // Make ConsensusReactor consensusState := consensus.NewConsensusState(state.Copy(), blockStore, mempoolReactor) consensusReactor := consensus.NewConsensusReactor(consensusState, blockStore, config.GetBool("fast_sync")) if privValidator != nil { consensusReactor.SetPrivValidator(privValidator) } - // Make Switch + // Make p2p network switch sw := p2p.NewSwitch() sw.AddReactor("PEX", pexReactor) sw.AddReactor("MEMPOOL", mempoolReactor) @@ -147,7 +142,6 @@ func NewNode() *Node { // Call Start() after adding the listeners. func (n *Node) Start() { - log.Info("Starting Node", "chainID", config.GetString("chain_id")) n.book.Start() n.sw.SetNodeInfo(makeNodeInfo(n.sw, n.privKey)) n.sw.SetNodePrivKey(n.privKey) @@ -155,7 +149,7 @@ func (n *Node) Start() { } func (n *Node) Stop() { - log.Info("Stopping Node") + log.Notice("Stopping Node") // TODO: gracefully disconnect from peers. n.sw.Stop() n.book.Stop() @@ -172,7 +166,7 @@ func SetFireable(evsw *events.EventSwitch, eventables ...events.Eventable) { // Add listeners before starting the Node. // The first listener is the primary listener (in NodeInfo) func (n *Node) AddListener(l p2p.Listener) { - log.Info(Fmt("Added %v", l)) + log.Notice(Fmt("Added %v", l)) n.sw.AddListener(l) n.book.AddOurAddress(l.ExternalAddress()) } @@ -200,12 +194,12 @@ func (n *Node) dialSeed(addr *p2p.NetAddress) { //n.book.MarkAttempt(addr) return } else { - log.Info("Connected to seed", "peer", peer) + log.Notice("Connected to seed", "peer", peer) n.book.AddAddress(addr, addr) } } -func (n *Node) StartRPC() net.Listener { +func (n *Node) StartRPC() (net.Listener, error) { core.SetBlockStore(n.blockStore) core.SetConsensusState(n.consensusState) core.SetConsensusReactor(n.consensusReactor) @@ -215,14 +209,12 @@ func (n *Node) StartRPC() net.Listener { core.SetGenDoc(n.genDoc) listenAddr := config.GetString("rpc_laddr") + mux := http.NewServeMux() - rpcserver.RegisterEventsHandler(mux, n.evsw) + wm := rpcserver.NewWebsocketManager(core.Routes, n.evsw) + mux.HandleFunc("/websocket", wm.WebsocketHandler) rpcserver.RegisterRPCFuncs(mux, core.Routes) - listener, err := rpcserver.StartHTTPServer(listenAddr, mux) - if err != nil { - panic(err) - } - return listener + return rpcserver.StartHTTPServer(listenAddr, mux) } func (n *Node) Switch() *p2p.Switch { @@ -270,7 +262,7 @@ func makeNodeInfo(sw *p2p.Switch, privKey acm.PrivKeyEd25519) *types.NodeInfo { _, rpcPortStr, _ := net.SplitHostPort(rpcListenAddr) rpcPort, err := strconv.Atoi(rpcPortStr) if err != nil { - panic(Fmt("Expected numeric RPC.ListenAddr port but got %v", rpcPortStr)) + PanicSanity(Fmt("Expected numeric RPC.ListenAddr port but got %v", rpcPortStr)) } // We assume that the rpcListener has the same ExternalAddress. @@ -291,6 +283,8 @@ func RunNode() { n.AddListener(l) n.Start() + log.Notice("Started node", "nodeInfo", n.sw.NodeInfo()) + // If seedNode is provided by config, dial out. if config.GetString("seeds") != "" { n.DialSeed() @@ -298,7 +292,10 @@ func RunNode() { // Run the RPC server. if config.GetString("rpc_laddr") != "" { - n.StartRPC() + _, err := n.StartRPC() + if err != nil { + PanicCrisis(err) + } } // Sleep forever and then... diff --git a/Godeps/_workspace/src/github.com/tendermint/tendermint/node/node_test.go b/Godeps/_workspace/src/github.com/tendermint/tendermint/node/node_test.go new file mode 100644 index 00000000..aa30a96b --- /dev/null +++ b/Godeps/_workspace/src/github.com/tendermint/tendermint/node/node_test.go @@ -0,0 +1,30 @@ +package node + +import ( + "testing" + "time" + + _ "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/config/tendermint_test" + "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/p2p" +) + +func TestNodeStartStop(t *testing.T) { + // Create & start node + n := NewNode() + l := p2p.NewDefaultListener("tcp", config.GetString("node_laddr"), false) + n.AddListener(l) + n.Start() + log.Notice("Started node", "nodeInfo", n.sw.NodeInfo()) + time.Sleep(time.Second * 2) + ch := make(chan struct{}, 1) + go func() { + n.Stop() + ch <- struct{}{} + }() + ticker := time.NewTicker(time.Second * 5) + select { + case <-ch: + case <-ticker.C: + t.Fatal("timed out waiting for shutdown") + } +} diff --git a/Godeps/_workspace/src/github.com/tendermint/tendermint/p2p/README.md b/Godeps/_workspace/src/github.com/tendermint/tendermint/p2p/README.md index cfbbf5c7..a7324b71 100644 --- a/Godeps/_workspace/src/github.com/tendermint/tendermint/p2p/README.md +++ b/Godeps/_workspace/src/github.com/tendermint/tendermint/p2p/README.md @@ -22,7 +22,7 @@ func (m MConnection) TrySend(chId byte, msg interface{}) bool {} `Send(chId, msg)` is a blocking call that waits until `msg` is successfully queued for the channel with the given id byte `chId`. The message `msg` is serialized -using the `tendermint/binary` submodule's `WriteBinary()` reflection routine. +using the `tendermint/wire` submodule's `WriteBinary()` reflection routine. `TrySend(chId, msg)` is a nonblocking call that returns false if the channel's queue is full. diff --git a/Godeps/_workspace/src/github.com/tendermint/tendermint/p2p/addrbook.go b/Godeps/_workspace/src/github.com/tendermint/tendermint/p2p/addrbook.go index 541faa31..bd6b410d 100644 --- a/Godeps/_workspace/src/github.com/tendermint/tendermint/p2p/addrbook.go +++ b/Godeps/_workspace/src/github.com/tendermint/tendermint/p2p/addrbook.go @@ -12,7 +12,6 @@ import ( "net" "os" "sync" - "sync/atomic" "time" . "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/common" @@ -74,19 +73,17 @@ const ( /* AddrBook - concurrency safe peer address manager */ type AddrBook struct { - filePath string + QuitService mtx sync.Mutex + filePath string rand *rand.Rand key string ourAddrs map[string]*NetAddress addrLookup map[string]*knownAddress // new & old addrNew []map[string]*knownAddress addrOld []map[string]*knownAddress - started uint32 - stopped uint32 wg sync.WaitGroup - quit chan struct{} nOld int nNew int } @@ -98,15 +95,15 @@ const ( // Use Start to begin processing asynchronous address updates. func NewAddrBook(filePath string) *AddrBook { - am := AddrBook{ + am := &AddrBook{ rand: rand.New(rand.NewSource(time.Now().UnixNano())), ourAddrs: make(map[string]*NetAddress), addrLookup: make(map[string]*knownAddress), - quit: make(chan struct{}), filePath: filePath, } am.init() - return &am + am.QuitService = *NewQuitService(log, "AddrBook", am) + return am } // When modifying this, don't forget to update loadFromFile() @@ -124,27 +121,22 @@ func (a *AddrBook) init() { } } -func (a *AddrBook) Start() { - if atomic.CompareAndSwapUint32(&a.started, 0, 1) { - log.Info("Starting AddrBook") - a.loadFromFile(a.filePath) - a.wg.Add(1) - go a.saveRoutine() - } +func (a *AddrBook) OnStart() { + a.QuitService.OnStart() + a.loadFromFile(a.filePath) + a.wg.Add(1) + go a.saveRoutine() } -func (a *AddrBook) Stop() { - if atomic.CompareAndSwapUint32(&a.stopped, 0, 1) { - log.Info("Stopping AddrBook") - close(a.quit) - a.wg.Wait() - } +func (a *AddrBook) OnStop() { + a.QuitService.OnStop() + a.wg.Wait() } func (a *AddrBook) AddOurAddress(addr *NetAddress) { a.mtx.Lock() defer a.mtx.Unlock() - log.Debug("Add our address to book", "addr", addr) + log.Info("Add our address to book", "addr", addr) a.ourAddrs[addr.String()] = addr } @@ -159,7 +151,7 @@ func (a *AddrBook) OurAddresses() []*NetAddress { func (a *AddrBook) AddAddress(addr *NetAddress, src *NetAddress) { a.mtx.Lock() defer a.mtx.Unlock() - log.Debug("Add address to book", "addr", addr, "src", src) + log.Info("Add address to book", "addr", addr, "src", src) a.addAddress(addr, src) } @@ -210,7 +202,7 @@ func (a *AddrBook) PickAddress(newBias int) *NetAddress { } randIndex-- } - panic("Should not happen") + PanicSanity("Should not happen") } else { // pick random New bucket. var bucket map[string]*knownAddress = nil @@ -225,7 +217,7 @@ func (a *AddrBook) PickAddress(newBias int) *NetAddress { } randIndex-- } - panic("Should not happen") + PanicSanity("Should not happen") } return nil } @@ -342,14 +334,14 @@ func (a *AddrBook) loadFromFile(filePath string) bool { // Load addrBookJSON{} r, err := os.Open(filePath) if err != nil { - panic(Fmt("Error opening file %s: %v", filePath, err)) + PanicCrisis(Fmt("Error opening file %s: %v", filePath, err)) } defer r.Close() aJSON := &addrBookJSON{} dec := json.NewDecoder(r) err = dec.Decode(aJSON) if err != nil { - panic(Fmt("Error reading file %s: %v", filePath, err)) + PanicCrisis(Fmt("Error reading file %s: %v", filePath, err)) } // Restore all the fields... @@ -379,16 +371,16 @@ out: for { select { case <-dumpAddressTicker.C: - log.Debug("Saving AddrBook to file", "size", a.Size()) + log.Info("Saving AddrBook to file", "size", a.Size()) a.saveToFile(a.filePath) - case <-a.quit: + case <-a.Quit: break out } } dumpAddressTicker.Stop() a.saveToFile(a.filePath) a.wg.Done() - log.Info("Address handler done") + log.Notice("Address handler done") } func (a *AddrBook) getBucket(bucketType byte, bucketIdx int) map[string]*knownAddress { @@ -398,7 +390,8 @@ func (a *AddrBook) getBucket(bucketType byte, bucketIdx int) map[string]*knownAd case bucketTypeOld: return a.addrOld[bucketIdx] default: - panic("Should not happen") + PanicSanity("Should not happen") + return nil } } @@ -421,7 +414,7 @@ func (a *AddrBook) addToNewBucket(ka *knownAddress, bucketIdx int) bool { // Enforce max addresses. if len(bucket) > newBucketSize { - log.Info("new bucket is full, expiring old ") + log.Notice("new bucket is full, expiring old ") a.expireNew(bucketIdx) } @@ -549,7 +542,7 @@ func (a *AddrBook) addAddress(addr, src *NetAddress) { bucket := a.calcNewBucket(addr, src) a.addToNewBucket(ka, bucket) - log.Info("Added new address", "address", addr, "total", a.size()) + log.Notice("Added new address", "address", addr, "total", a.size()) } // Make space in the new buckets by expiring the really bad entries. @@ -558,7 +551,7 @@ func (a *AddrBook) expireNew(bucketIdx int) { for addrStr, ka := range a.addrNew[bucketIdx] { // If an entry is bad, throw it away if ka.isBad() { - log.Info(Fmt("expiring bad address %v", addrStr)) + log.Notice(Fmt("expiring bad address %v", addrStr)) a.removeFromBucket(ka, bucketTypeNew, bucketIdx) return } diff --git a/Godeps/_workspace/src/github.com/tendermint/tendermint/p2p/connection.go b/Godeps/_workspace/src/github.com/tendermint/tendermint/p2p/connection.go index 55268fa6..fdcb092d 100644 --- a/Godeps/_workspace/src/github.com/tendermint/tendermint/p2p/connection.go +++ b/Godeps/_workspace/src/github.com/tendermint/tendermint/p2p/connection.go @@ -11,8 +11,8 @@ import ( "time" flow "github.com/eris-ltd/eris-db/Godeps/_workspace/src/code.google.com/p/mxk/go1/flowcontrol" - "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/binary" //"github.com/tendermint/log15" . "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/common" + "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/wire" //"github.com/tendermint/log15" ) const ( @@ -22,7 +22,7 @@ const ( flushThrottleMS = 50 idleTimeoutMinutes = 5 updateStatsSeconds = 2 - pingTimeoutMinutes = 2 + pingTimeoutSeconds = 40 defaultSendRate = 51200 // 5Kb/s defaultRecvRate = 51200 // 5Kb/s defaultSendQueueCapacity = 1 @@ -50,7 +50,7 @@ There are two methods for sending messages: `Send(chId, msg)` is a blocking call that waits until `msg` is successfully queued for the channel with the given id byte `chId`, or until the request times out. -The message `msg` is serialized using the `tendermint/binary` submodule's +The message `msg` is serialized using the `tendermint/wire` submodule's `WriteBinary()` reflection routine. `TrySend(chId, msg)` is a nonblocking call that returns false if the channel's @@ -59,26 +59,27 @@ queue is full. Inbound message bytes are handled with an onReceive callback function. */ type MConnection struct { - conn net.Conn - bufReader *bufio.Reader - bufWriter *bufio.Writer - sendMonitor *flow.Monitor - recvMonitor *flow.Monitor - sendRate int64 - recvRate int64 - flushTimer *ThrottleTimer // flush writes as necessary but throttled. - send chan struct{} + BaseService + + conn net.Conn + bufReader *bufio.Reader + bufWriter *bufio.Writer + sendMonitor *flow.Monitor + recvMonitor *flow.Monitor + sendRate int64 + recvRate int64 + send chan struct{} + pong chan struct{} + channels []*Channel + channelsIdx map[byte]*Channel + onReceive receiveCbFunc + onError errorCbFunc + errored uint32 + quit chan struct{} - pingTimer *RepeatTimer // send pings periodically - pong chan struct{} - chStatsTimer *RepeatTimer // update channel stats periodically - channels []*Channel - channelsIdx map[byte]*Channel - onReceive receiveCbFunc - onError errorCbFunc - started uint32 - stopped uint32 - errored uint32 + flushTimer *ThrottleTimer // flush writes as necessary but throttled. + pingTimer *RepeatTimer // send pings periodically + chStatsTimer *RepeatTimer // update channel stats periodically LocalAddress *NetAddress RemoteAddress *NetAddress @@ -87,21 +88,24 @@ type MConnection struct { func NewMConnection(conn net.Conn, chDescs []*ChannelDescriptor, onReceive receiveCbFunc, onError errorCbFunc) *MConnection { mconn := &MConnection{ - conn: conn, - bufReader: bufio.NewReaderSize(conn, minReadBufferSize), - bufWriter: bufio.NewWriterSize(conn, minWriteBufferSize), - sendMonitor: flow.New(0, 0), - recvMonitor: flow.New(0, 0), - sendRate: defaultSendRate, - recvRate: defaultRecvRate, - flushTimer: NewThrottleTimer("flush", flushThrottleMS*time.Millisecond), - send: make(chan struct{}, 1), - quit: make(chan struct{}), - pingTimer: NewRepeatTimer("ping", pingTimeoutMinutes*time.Minute), - pong: make(chan struct{}), - chStatsTimer: NewRepeatTimer("chStats", updateStatsSeconds*time.Second), - onReceive: onReceive, - onError: onError, + conn: conn, + bufReader: bufio.NewReaderSize(conn, minReadBufferSize), + bufWriter: bufio.NewWriterSize(conn, minWriteBufferSize), + sendMonitor: flow.New(0, 0), + recvMonitor: flow.New(0, 0), + sendRate: defaultSendRate, + recvRate: defaultRecvRate, + send: make(chan struct{}, 1), + pong: make(chan struct{}), + onReceive: onReceive, + onError: onError, + + // Initialized in Start() + quit: nil, + flushTimer: nil, + pingTimer: nil, + chStatsTimer: nil, + LocalAddress: NewNetAddress(conn.LocalAddr()), RemoteAddress: NewNetAddress(conn.RemoteAddr()), } @@ -118,32 +122,35 @@ func NewMConnection(conn net.Conn, chDescs []*ChannelDescriptor, onReceive recei mconn.channels = channels mconn.channelsIdx = channelsIdx + mconn.BaseService = *NewBaseService(log, "MConnection", mconn) + return mconn } -// .Start() begins multiplexing packets to and from "channels". -func (c *MConnection) Start() { - if atomic.CompareAndSwapUint32(&c.started, 0, 1) { - log.Debug("Starting MConnection", "connection", c) - go c.sendRoutine() - go c.recvRoutine() - } +func (c *MConnection) OnStart() { + c.BaseService.OnStart() + c.quit = make(chan struct{}) + c.flushTimer = NewThrottleTimer("flush", flushThrottleMS*time.Millisecond) + c.pingTimer = NewRepeatTimer("ping", pingTimeoutSeconds*time.Second) + c.chStatsTimer = NewRepeatTimer("chStats", updateStatsSeconds*time.Second) + go c.sendRoutine() + go c.recvRoutine() } -func (c *MConnection) Stop() { - if atomic.CompareAndSwapUint32(&c.stopped, 0, 1) { - log.Debug("Stopping MConnection", "connection", c) +func (c *MConnection) OnStop() { + c.BaseService.OnStop() + c.flushTimer.Stop() + c.pingTimer.Stop() + c.chStatsTimer.Stop() + if c.quit != nil { close(c.quit) - c.conn.Close() - c.flushTimer.Stop() - c.chStatsTimer.Stop() - c.pingTimer.Stop() - // We can't close pong safely here because - // recvRoutine may write to it after we've stopped. - // Though it doesn't need to get closed at all, - // we close it @ recvRoutine. - // close(c.pong) } + c.conn.Close() + // We can't close pong safely here because + // recvRoutine may write to it after we've stopped. + // Though it doesn't need to get closed at all, + // we close it @ recvRoutine. + // close(c.pong) } func (c *MConnection) String() string { @@ -178,11 +185,11 @@ func (c *MConnection) stopForError(r interface{}) { // Queues a message to be sent to channel. func (c *MConnection) Send(chId byte, msg interface{}) bool { - if atomic.LoadUint32(&c.stopped) == 1 { + if !c.IsRunning() { return false } - log.Debug("Send", "channel", chId, "connection", c, "msg", msg) //, "bytes", binary.BinaryBytes(msg)) + log.Info("Send", "channel", chId, "conn", c, "msg", msg) //, "bytes", wire.BinaryBytes(msg)) // Send message to channel. channel, ok := c.channelsIdx[chId] @@ -191,7 +198,7 @@ func (c *MConnection) Send(chId byte, msg interface{}) bool { return false } - success := channel.sendBytes(binary.BinaryBytes(msg)) + success := channel.sendBytes(wire.BinaryBytes(msg)) if success { // Wake up sendRoutine if necessary select { @@ -199,7 +206,7 @@ func (c *MConnection) Send(chId byte, msg interface{}) bool { default: } } else { - log.Warn("Send failed", "channel", chId, "connection", c, "msg", msg) + log.Warn("Send failed", "channel", chId, "conn", c, "msg", msg) } return success } @@ -207,11 +214,11 @@ func (c *MConnection) Send(chId byte, msg interface{}) bool { // Queues a message to be sent to channel. // Nonblocking, returns true if successful. func (c *MConnection) TrySend(chId byte, msg interface{}) bool { - if atomic.LoadUint32(&c.stopped) == 1 { + if !c.IsRunning() { return false } - log.Debug("TrySend", "channel", chId, "connection", c, "msg", msg) + log.Info("TrySend", "channel", chId, "conn", c, "msg", msg) // Send message to channel. channel, ok := c.channelsIdx[chId] @@ -220,7 +227,7 @@ func (c *MConnection) TrySend(chId byte, msg interface{}) bool { return false } - ok = channel.trySendBytes(binary.BinaryBytes(msg)) + ok = channel.trySendBytes(wire.BinaryBytes(msg)) if ok { // Wake up sendRoutine if necessary select { @@ -233,7 +240,7 @@ func (c *MConnection) TrySend(chId byte, msg interface{}) bool { } func (c *MConnection) CanSend(chId byte) bool { - if atomic.LoadUint32(&c.stopped) == 1 { + if !c.IsRunning() { return false } @@ -263,13 +270,13 @@ FOR_LOOP: channel.updateStats() } case <-c.pingTimer.Ch: - log.Debug("Send Ping") - binary.WriteByte(packetTypePing, c.bufWriter, &n, &err) + log.Info("Send Ping") + wire.WriteByte(packetTypePing, c.bufWriter, &n, &err) c.sendMonitor.Update(int(n)) c.flush() case <-c.pong: - log.Debug("Send Pong") - binary.WriteByte(packetTypePong, c.bufWriter, &n, &err) + log.Info("Send Pong") + wire.WriteByte(packetTypePong, c.bufWriter, &n, &err) c.sendMonitor.Update(int(n)) c.flush() case <-c.quit: @@ -286,11 +293,11 @@ FOR_LOOP: } } - if atomic.LoadUint32(&c.stopped) == 1 { + if !c.IsRunning() { break FOR_LOOP } if err != nil { - log.Warn("Connection failed @ sendRoutine", "connection", c, "error", err) + log.Warn("Connection failed @ sendRoutine", "conn", c, "error", err) c.stopForError(err) break FOR_LOOP } @@ -339,7 +346,7 @@ func (c *MConnection) sendMsgPacket() bool { if leastChannel == nil { return true } else { - // log.Debug("Found a msgPacket to send") + // log.Info("Found a msgPacket to send") } // Make & send a msgPacket from this channel @@ -368,7 +375,7 @@ FOR_LOOP: /* // Peek into bufReader for debugging if numBytes := c.bufReader.Buffered(); numBytes > 0 { - log.Debug("Peek connection buffer", "numBytes", numBytes, "bytes", log15.Lazy{func() []byte { + log.Info("Peek connection buffer", "numBytes", numBytes, "bytes", log15.Lazy{func() []byte { bytes, err := c.bufReader.Peek(MinInt(numBytes, 100)) if err == nil { return bytes @@ -383,11 +390,11 @@ FOR_LOOP: // Read packet type var n int64 var err error - pktType := binary.ReadByte(c.bufReader, &n, &err) + pktType := wire.ReadByte(c.bufReader, &n, &err) c.recvMonitor.Update(int(n)) if err != nil { - if atomic.LoadUint32(&c.stopped) != 1 { - log.Warn("Connection failed @ recvRoutine (reading byte)", "connection", c, "error", err) + if c.IsRunning() { + log.Warn("Connection failed @ recvRoutine (reading byte)", "conn", c, "error", err) c.stopForError(err) } break FOR_LOOP @@ -397,30 +404,30 @@ FOR_LOOP: switch pktType { case packetTypePing: // TODO: prevent abuse, as they cause flush()'s. - log.Debug("Receive Ping") + log.Info("Receive Ping") c.pong <- struct{}{} case packetTypePong: // do nothing - log.Debug("Receive Pong") + log.Info("Receive Pong") case packetTypeMsg: pkt, n, err := msgPacket{}, int64(0), error(nil) - binary.ReadBinaryPtr(&pkt, c.bufReader, &n, &err) + wire.ReadBinaryPtr(&pkt, c.bufReader, &n, &err) c.recvMonitor.Update(int(n)) if err != nil { - if atomic.LoadUint32(&c.stopped) != 1 { - log.Warn("Connection failed @ recvRoutine", "connection", c, "error", err) + if c.IsRunning() { + log.Warn("Connection failed @ recvRoutine", "conn", c, "error", err) c.stopForError(err) } break FOR_LOOP } channel, ok := c.channelsIdx[pkt.ChannelId] if !ok || channel == nil { - panic(Fmt("Unknown channel %X", pkt.ChannelId)) + PanicQ(Fmt("Unknown channel %X", pkt.ChannelId)) } msgBytes, err := channel.recvMsgPacket(pkt) if err != nil { - if atomic.LoadUint32(&c.stopped) != 1 { - log.Warn("Connection failed @ recvRoutine", "connection", c, "error", err) + if c.IsRunning() { + log.Warn("Connection failed @ recvRoutine", "conn", c, "error", err) c.stopForError(err) } break FOR_LOOP @@ -430,7 +437,7 @@ FOR_LOOP: c.onReceive(pkt.ChannelId, msgBytes) } default: - panic(Fmt("Unknown message type %X", pktType)) + PanicSanity(Fmt("Unknown message type %X", pktType)) } // TODO: shouldn't this go in the sendRoutine? @@ -480,7 +487,7 @@ type Channel struct { func newChannel(conn *MConnection, desc *ChannelDescriptor) *Channel { desc.FillDefaults() if desc.Priority <= 0 { - panic("Channel default priority must be a postive integer") + PanicSanity("Channel default priority must be a postive integer") } return &Channel{ conn: conn, @@ -566,8 +573,8 @@ func (ch *Channel) nextMsgPacket() msgPacket { func (ch *Channel) writeMsgPacketTo(w io.Writer) (n int64, err error) { packet := ch.nextMsgPacket() log.Debug("Write Msg Packet", "conn", ch.conn, "packet", packet) - binary.WriteByte(packetTypeMsg, w, &n, &err) - binary.WriteBinary(packet, w, &n, &err) + wire.WriteByte(packetTypeMsg, w, &n, &err) + wire.WriteBinary(packet, w, &n, &err) if err != nil { ch.recentlySent += n } @@ -578,8 +585,8 @@ func (ch *Channel) writeMsgPacketTo(w io.Writer) (n int64, err error) { // Not goroutine-safe func (ch *Channel) recvMsgPacket(packet msgPacket) ([]byte, error) { log.Debug("Read Msg Packet", "conn", ch.conn, "packet", packet) - if binary.MaxBinaryReadSize < len(ch.recving)+len(packet.Bytes) { - return nil, binary.ErrBinaryReadSizeOverflow + if wire.MaxBinaryReadSize < len(ch.recving)+len(packet.Bytes) { + return nil, wire.ErrBinaryReadSizeOverflow } ch.recving = append(ch.recving, packet.Bytes...) if packet.EOF == byte(0x01) { diff --git a/Godeps/_workspace/src/github.com/tendermint/tendermint/p2p/listener.go b/Godeps/_workspace/src/github.com/tendermint/tendermint/p2p/listener.go index dadac2f5..26ecf24a 100644 --- a/Godeps/_workspace/src/github.com/tendermint/tendermint/p2p/listener.go +++ b/Godeps/_workspace/src/github.com/tendermint/tendermint/p2p/listener.go @@ -4,7 +4,7 @@ import ( "fmt" "net" "strconv" - "sync/atomic" + "time" . "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/common" "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/p2p/upnp" @@ -15,31 +15,33 @@ type Listener interface { InternalAddress() *NetAddress ExternalAddress() *NetAddress String() string - Stop() + Stop() bool } // Implements Listener type DefaultListener struct { + BaseService + listener net.Listener intAddr *NetAddress extAddr *NetAddress connections chan net.Conn - stopped uint32 } const ( numBufferedConnections = 10 defaultExternalPort = 8770 + tryListenSeconds = 5 ) func splitHostPort(addr string) (host string, port int) { host, portStr, err := net.SplitHostPort(addr) if err != nil { - panic(err) + PanicSanity(err) } port, err = strconv.Atoi(portStr) if err != nil { - panic(err) + PanicSanity(err) } return host, port } @@ -49,13 +51,22 @@ func NewDefaultListener(protocol string, lAddr string, requireUPNPHairpin bool) lAddrIP, lAddrPort := splitHostPort(lAddr) // Create listener - listener, err := net.Listen(protocol, lAddr) + var listener net.Listener + var err error + for i := 0; i < tryListenSeconds; i++ { + listener, err = net.Listen(protocol, lAddr) + if err == nil { + break + } else if i < tryListenSeconds-1 { + time.Sleep(time.Second * 1) + } + } if err != nil { - panic(err) + PanicCrisis(err) } // Actual listener local IP & port listenerIP, listenerPort := splitHostPort(listener.Addr().String()) - log.Debug("Local listener", "ip", listenerIP, "port", listenerPort) + log.Info("Local listener", "ip", listenerIP, "port", listenerPort) // Determine internal address... var intAddr *NetAddress = NewNetAddressString(lAddr) @@ -83,7 +94,7 @@ SKIP_UPNP: extAddr = getNaiveExternalAddress(listenerPort) } if extAddr == nil { - panic("Could not determine external address!") + PanicCrisis("Could not determine external address!") } dl := &DefaultListener{ @@ -92,10 +103,19 @@ SKIP_UPNP: extAddr: extAddr, connections: make(chan net.Conn, numBufferedConnections), } + dl.BaseService = *NewBaseService(log, "DefaultListener", dl) + dl.Start() // Started upon construction + return dl +} - go dl.listenRoutine() +func (l *DefaultListener) OnStart() { + l.BaseService.OnStart() + go l.listenRoutine() +} - return dl +func (l *DefaultListener) OnStop() { + l.BaseService.OnStop() + l.listener.Close() } // Accept connections and pass on the channel @@ -103,14 +123,14 @@ func (l *DefaultListener) listenRoutine() { for { conn, err := l.listener.Accept() - if atomic.LoadUint32(&l.stopped) == 1 { + if !l.IsRunning() { break // Go to cleanup } // listener wasn't stopped, // yet we encountered an error. if err != nil { - panic(err) + PanicCrisis(err) } l.connections <- conn @@ -143,12 +163,6 @@ func (l *DefaultListener) NetListener() net.Listener { return l.listener } -func (l *DefaultListener) Stop() { - if atomic.CompareAndSwapUint32(&l.stopped, 0, 1) { - l.listener.Close() - } -} - func (l *DefaultListener) String() string { return fmt.Sprintf("Listener(@%v)", l.extAddr) } @@ -157,16 +171,16 @@ func (l *DefaultListener) String() string { // UPNP external address discovery & port mapping func getUPNPExternalAddress(externalPort, internalPort int) *NetAddress { - log.Debug("Getting UPNP external address") + log.Info("Getting UPNP external address") nat, err := upnp.Discover() if err != nil { - log.Debug("Could not perform UPNP discover", "error", err) + log.Info("Could not perform UPNP discover", "error", err) return nil } ext, err := nat.GetExternalAddress() if err != nil { - log.Debug("Could not get UPNP external address", "error", err) + log.Info("Could not get UPNP external address", "error", err) return nil } @@ -177,11 +191,11 @@ func getUPNPExternalAddress(externalPort, internalPort int) *NetAddress { externalPort, err = nat.AddPortMapping("tcp", externalPort, internalPort, "tendermint", 0) if err != nil { - log.Debug("Could not add UPNP port mapping", "error", err) + log.Info("Could not add UPNP port mapping", "error", err) return nil } - log.Debug("Got UPNP external address", "address", ext) + log.Info("Got UPNP external address", "address", ext) return NewNetAddressIPPort(ext, uint16(externalPort)) } @@ -189,7 +203,7 @@ func getUPNPExternalAddress(externalPort, internalPort int) *NetAddress { func getNaiveExternalAddress(port int) *NetAddress { addrs, err := net.InterfaceAddrs() if err != nil { - panic(Fmt("Could not fetch interface addresses: %v", err)) + PanicCrisis(Fmt("Could not fetch interface addresses: %v", err)) } for _, a := range addrs { diff --git a/Godeps/_workspace/src/github.com/tendermint/tendermint/p2p/netaddress.go b/Godeps/_workspace/src/github.com/tendermint/tendermint/p2p/netaddress.go index 39979fdc..8588ff73 100644 --- a/Godeps/_workspace/src/github.com/tendermint/tendermint/p2p/netaddress.go +++ b/Godeps/_workspace/src/github.com/tendermint/tendermint/p2p/netaddress.go @@ -9,6 +9,8 @@ import ( "net" "strconv" "time" + + . "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/common" ) type NetAddress struct { @@ -21,7 +23,7 @@ type NetAddress struct { func NewNetAddress(addr net.Addr) *NetAddress { tcpAddr, ok := addr.(*net.TCPAddr) if !ok { - panic(fmt.Sprintf("Only TCPAddrs are supported. Got: %v", addr)) + PanicSanity(fmt.Sprintf("Only TCPAddrs are supported. Got: %v", addr)) } ip := tcpAddr.IP port := uint16(tcpAddr.Port) @@ -32,21 +34,21 @@ func NewNetAddress(addr net.Addr) *NetAddress { func NewNetAddressString(addr string) *NetAddress { host, portStr, err := net.SplitHostPort(addr) if err != nil { - panic(err) + PanicSanity(err) } ip := net.ParseIP(host) if ip == nil { if len(host) > 0 { ips, err := net.LookupIP(host) if err != nil { - panic(err) + PanicSanity(err) } ip = ips[0] } } port, err := strconv.ParseUint(portStr, 10, 16) if err != nil { - panic(err) + PanicSanity(err) } na := NewNetAddressIPPort(ip, uint16(port)) return na @@ -76,7 +78,8 @@ func (na *NetAddress) Less(other interface{}) bool { if o, ok := other.(*NetAddress); ok { return na.String() < o.String() } else { - panic("Cannot compare unequal types") + PanicSanity("Cannot compare unequal types") + return false } } diff --git a/Godeps/_workspace/src/github.com/tendermint/tendermint/p2p/peer.go b/Godeps/_workspace/src/github.com/tendermint/tendermint/p2p/peer.go index 4b62861c..8b0819e5 100644 --- a/Godeps/_workspace/src/github.com/tendermint/tendermint/p2p/peer.go +++ b/Godeps/_workspace/src/github.com/tendermint/tendermint/p2p/peer.go @@ -4,17 +4,17 @@ import ( "fmt" "io" "net" - "sync/atomic" - "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/binary" . "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/common" "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/types" + "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/wire" ) type Peer struct { + BaseService + outbound bool mconn *MConnection - running uint32 *types.NodeInfo Key string @@ -30,12 +30,12 @@ func peerHandshake(conn net.Conn, ourNodeInfo *types.NodeInfo) (*types.NodeInfo, Parallel( func() { var n int64 - binary.WriteBinary(ourNodeInfo, conn, &n, &err1) + wire.WriteBinary(ourNodeInfo, conn, &n, &err1) }, func() { var n int64 - binary.ReadBinary(peerNodeInfo, conn, &n, &err2) - log.Info("Peer handshake", "peerNodeInfo", peerNodeInfo) + wire.ReadBinary(peerNodeInfo, conn, &n, &err2) + log.Notice("Peer handshake", "peerNodeInfo", peerNodeInfo) }) if err1 != nil { return nil, err1 @@ -52,42 +52,34 @@ func newPeer(conn net.Conn, peerNodeInfo *types.NodeInfo, outbound bool, reactor onReceive := func(chId byte, msgBytes []byte) { reactor := reactorsByCh[chId] if reactor == nil { - panic(Fmt("Unknown channel %X", chId)) + PanicSanity(Fmt("Unknown channel %X", chId)) } reactor.Receive(chId, p, msgBytes) } onError := func(r interface{}) { - p.stop() + p.Stop() onPeerError(p, r) } mconn := NewMConnection(conn, chDescs, onReceive, onError) p = &Peer{ outbound: outbound, mconn: mconn, - running: 0, NodeInfo: peerNodeInfo, Key: peerNodeInfo.PubKey.KeyString(), Data: NewCMap(), } + p.BaseService = *NewBaseService(log, "Peer", p) return p } -func (p *Peer) start() { - if atomic.CompareAndSwapUint32(&p.running, 0, 1) { - log.Debug("Starting Peer", "peer", p) - p.mconn.Start() - } -} - -func (p *Peer) stop() { - if atomic.CompareAndSwapUint32(&p.running, 1, 0) { - log.Debug("Stopping Peer", "peer", p) - p.mconn.Stop() - } +func (p *Peer) OnStart() { + p.BaseService.OnStart() + p.mconn.Start() } -func (p *Peer) IsRunning() bool { - return atomic.LoadUint32(&p.running) == 1 +func (p *Peer) OnStop() { + p.BaseService.OnStop() + p.mconn.Stop() } func (p *Peer) Connection() *MConnection { @@ -99,28 +91,28 @@ func (p *Peer) IsOutbound() bool { } func (p *Peer) Send(chId byte, msg interface{}) bool { - if atomic.LoadUint32(&p.running) == 0 { + if !p.IsRunning() { return false } return p.mconn.Send(chId, msg) } func (p *Peer) TrySend(chId byte, msg interface{}) bool { - if atomic.LoadUint32(&p.running) == 0 { + if !p.IsRunning() { return false } return p.mconn.TrySend(chId, msg) } func (p *Peer) CanSend(chId byte) bool { - if atomic.LoadUint32(&p.running) == 0 { + if !p.IsRunning() { return false } return p.mconn.CanSend(chId) } func (p *Peer) WriteTo(w io.Writer) (n int64, err error) { - binary.WriteString(p.Key, w, &n, &err) + wire.WriteString(p.Key, w, &n, &err) return } diff --git a/Godeps/_workspace/src/github.com/tendermint/tendermint/p2p/pex_reactor.go b/Godeps/_workspace/src/github.com/tendermint/tendermint/p2p/pex_reactor.go index f1a1e571..f678a662 100644 --- a/Godeps/_workspace/src/github.com/tendermint/tendermint/p2p/pex_reactor.go +++ b/Godeps/_workspace/src/github.com/tendermint/tendermint/p2p/pex_reactor.go @@ -6,12 +6,11 @@ import ( "fmt" "math/rand" "reflect" - "sync/atomic" "time" - "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/binary" . "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/common" "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/events" + "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/wire" ) var pexErrInvalidMessage = errors.New("Invalid PEX message") @@ -27,39 +26,28 @@ PEXReactor handles PEX (peer exchange) and ensures that an adequate number of peers are connected to the switch. */ type PEXReactor struct { - sw *Switch - quit chan struct{} - started uint32 - stopped uint32 + BaseReactor + sw *Switch book *AddrBook - evsw events.Fireable } func NewPEXReactor(book *AddrBook) *PEXReactor { pexR := &PEXReactor{ - quit: make(chan struct{}), book: book, } + pexR.BaseReactor = *NewBaseReactor(log, "PEXReactor", pexR) return pexR } -// Implements Reactor -func (pexR *PEXReactor) Start(sw *Switch) { - if atomic.CompareAndSwapUint32(&pexR.started, 0, 1) { - log.Info("Starting PEXReactor") - pexR.sw = sw - go pexR.ensurePeersRoutine() - } +func (pexR *PEXReactor) OnStart() { + pexR.BaseReactor.OnStart() + go pexR.ensurePeersRoutine() } -// Implements Reactor -func (pexR *PEXReactor) Stop() { - if atomic.CompareAndSwapUint32(&pexR.stopped, 0, 1) { - log.Info("Stopping PEXReactor") - close(pexR.quit) - } +func (pexR *PEXReactor) OnStop() { + pexR.BaseReactor.OnStop() } // Implements Reactor @@ -103,7 +91,7 @@ func (pexR *PEXReactor) Receive(chId byte, src *Peer, msgBytes []byte) { log.Warn("Error decoding message", "error", err) return } - log.Info("Received message", "msg", msg) + log.Notice("Received message", "msg", msg) switch msg := msg.(type) { case *pexRequestMessage: @@ -147,7 +135,7 @@ FOR_LOOP: select { case <-timer.Ch: pexR.ensurePeers() - case <-pexR.quit: + case <-pexR.Quit: break FOR_LOOP } } @@ -158,9 +146,9 @@ FOR_LOOP: // Ensures that sufficient peers are connected. (once) func (pexR *PEXReactor) ensurePeers() { - numOutPeers, _, numDialing := pexR.sw.NumPeers() + numOutPeers, _, numDialing := pexR.Switch.NumPeers() numToDial := minNumOutboundPeers - (numOutPeers + numDialing) - log.Debug("Ensure peers", "numOutPeers", numOutPeers, "numDialing", numDialing, "numToDial", numToDial) + log.Info("Ensure peers", "numOutPeers", numOutPeers, "numDialing", numDialing, "numToDial", numToDial) if numToDial <= 0 { return } @@ -179,18 +167,18 @@ func (pexR *PEXReactor) ensurePeers() { break } alreadySelected := toDial.Has(try.IP.String()) - alreadyDialing := pexR.sw.IsDialing(try) - alreadyConnected := pexR.sw.Peers().Has(try.IP.String()) + alreadyDialing := pexR.Switch.IsDialing(try) + alreadyConnected := pexR.Switch.Peers().Has(try.IP.String()) if alreadySelected || alreadyDialing || alreadyConnected { /* - log.Debug("Cannot dial address", "addr", try, + log.Info("Cannot dial address", "addr", try, "alreadySelected", alreadySelected, "alreadyDialing", alreadyDialing, "alreadyConnected", alreadyConnected) */ continue } else { - log.Debug("Will dial address", "addr", try) + log.Info("Will dial address", "addr", try) picked = try break } @@ -204,7 +192,7 @@ func (pexR *PEXReactor) ensurePeers() { // Dial picked addresses for _, item := range toDial.Values() { go func(picked *NetAddress) { - _, err := pexR.sw.DialPeerWithAddress(picked) + _, err := pexR.Switch.DialPeerWithAddress(picked) if err != nil { pexR.book.MarkAttempt(picked) } @@ -213,10 +201,10 @@ func (pexR *PEXReactor) ensurePeers() { // If we need more addresses, pick a random peer and ask for more. if pexR.book.NeedMoreAddrs() { - if peers := pexR.sw.Peers().List(); len(peers) > 0 { + if peers := pexR.Switch.Peers().List(); len(peers) > 0 { i := rand.Int() % len(peers) peer := peers[i] - log.Debug("No addresses to dial. Sending pexRequest to random peer", "peer", peer) + log.Info("No addresses to dial. Sending pexRequest to random peer", "peer", peer) pexR.RequestPEX(peer) } } @@ -237,17 +225,17 @@ const ( type PexMessage interface{} -var _ = binary.RegisterInterface( +var _ = wire.RegisterInterface( struct{ PexMessage }{}, - binary.ConcreteType{&pexRequestMessage{}, msgTypeRequest}, - binary.ConcreteType{&pexAddrsMessage{}, msgTypeAddrs}, + wire.ConcreteType{&pexRequestMessage{}, msgTypeRequest}, + wire.ConcreteType{&pexAddrsMessage{}, msgTypeAddrs}, ) func DecodeMessage(bz []byte) (msgType byte, msg PexMessage, err error) { msgType = bz[0] n := new(int64) r := bytes.NewReader(bz) - msg = binary.ReadBinary(struct{ PexMessage }{}, r, n, &err).(struct{ PexMessage }).PexMessage + msg = wire.ReadBinary(struct{ PexMessage }{}, r, n, &err).(struct{ PexMessage }).PexMessage return } diff --git a/Godeps/_workspace/src/github.com/tendermint/tendermint/p2p/secret_connection.go b/Godeps/_workspace/src/github.com/tendermint/tendermint/p2p/secret_connection.go index 355cee22..d00cba0e 100644 --- a/Godeps/_workspace/src/github.com/tendermint/tendermint/p2p/secret_connection.go +++ b/Godeps/_workspace/src/github.com/tendermint/tendermint/p2p/secret_connection.go @@ -1,5 +1,8 @@ // Uses nacl's secret_box to encrypt a net.Conn. // It is (meant to be) an implementation of the STS protocol. +// Note we do not (yet) assume that a remote peer's pubkey +// is known ahead of time, and thus we are technically +// still vulnerable to MITM. (TODO!) // See docs/sts-final.pdf for more info package p2p @@ -11,7 +14,6 @@ import ( "errors" "io" "net" - "sync" "time" "github.com/eris-ltd/eris-db/Godeps/_workspace/src/golang.org/x/crypto/nacl/box" @@ -19,8 +21,8 @@ import ( "github.com/eris-ltd/eris-db/Godeps/_workspace/src/golang.org/x/crypto/ripemd160" acm "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/account" - bm "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/binary" . "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/common" + "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/wire" ) // 2 + 1024 == 1026 total frame size @@ -28,6 +30,7 @@ const dataLenSize = 2 // uint16 to describe the length, is <= dataMaxSize const dataMaxSize = 1024 const totalFrameSize = dataMaxSize + dataLenSize const sealedFrameSize = totalFrameSize + secretbox.Overhead +const authSigMsgSize = (32 + 1) + (64 + 1) // fixed size (length prefixed) byte arrays // Implements net.Conn type SecretConnection struct { @@ -51,6 +54,8 @@ func MakeSecretConnection(conn io.ReadWriteCloser, locPrivKey acm.PrivKeyEd25519 locEphPub, locEphPriv := genEphKeys() // Write local ephemeral pubkey and receive one too. + // NOTE: every 32-byte string is accepted as a Curve25519 public key + // (see DJB's Curve25519 paper: http://cr.yp.to/ecdh/curve25519-20060209.pdf) remEphPub, err := shareEphPubKey(conn, locEphPub) if err != nil { return nil, err @@ -74,7 +79,6 @@ func MakeSecretConnection(conn io.ReadWriteCloser, locPrivKey acm.PrivKeyEd25519 recvBuffer: nil, recvNonce: recvNonce, sendNonce: sendNonce, - remPubKey: nil, shrSecret: shrSecret, } @@ -82,10 +86,11 @@ func MakeSecretConnection(conn io.ReadWriteCloser, locPrivKey acm.PrivKeyEd25519 locSignature := signChallenge(challenge, locPrivKey) // Share (in secret) each other's pubkey & challenge signature - remPubKey, remSignature, err := shareAuthSignature(sc, locPubKey, locSignature) + authSigMsg, err := shareAuthSignature(sc, locPubKey, locSignature) if err != nil { return nil, err } + remPubKey, remSignature := authSigMsg.Key, authSigMsg.Sig if !remPubKey.VerifyBytes(challenge[:], remSignature) { return nil, errors.New("Challenge verification failed") } @@ -158,7 +163,10 @@ func (sc *SecretConnection) Read(data []byte) (n int, err error) { incr2Nonce(sc.recvNonce) // end decryption - var chunkLength = binary.BigEndian.Uint16(frame) + var chunkLength = binary.BigEndian.Uint16(frame) // read the first two bytes + if chunkLength > dataMaxSize { + return 0, errors.New("chunkLength is greater than dataMaxSize") + } var chunk = frame[dataLenSize : dataLenSize+chunkLength] n = copy(data, chunk) @@ -182,28 +190,24 @@ func genEphKeys() (ephPub, ephPriv *[32]byte) { var err error ephPub, ephPriv, err = box.GenerateKey(crand.Reader) if err != nil { - panic("Could not generate ephemeral keypairs") + PanicCrisis("Could not generate ephemeral keypairs") } return } func shareEphPubKey(conn io.ReadWriteCloser, locEphPub *[32]byte) (remEphPub *[32]byte, err error) { var err1, err2 error - var wg sync.WaitGroup - wg.Add(2) - - go func() { - defer wg.Done() - _, err1 = conn.Write(locEphPub[:]) - }() - go func() { - defer wg.Done() - remEphPub = new([32]byte) - _, err2 = io.ReadFull(conn, remEphPub[:]) - }() + Parallel( + func() { + _, err1 = conn.Write(locEphPub[:]) + }, + func() { + remEphPub = new([32]byte) + _, err2 = io.ReadFull(conn, remEphPub[:]) + }, + ) - wg.Wait() if err1 != nil { return nil, err1 } @@ -260,34 +264,33 @@ type authSigMessage struct { Sig acm.SignatureEd25519 } -func shareAuthSignature(sc *SecretConnection, pubKey acm.PubKeyEd25519, signature acm.SignatureEd25519) (acm.PubKeyEd25519, acm.SignatureEd25519, error) { +func shareAuthSignature(sc *SecretConnection, pubKey acm.PubKeyEd25519, signature acm.SignatureEd25519) (*authSigMessage, error) { var recvMsg authSigMessage var err1, err2 error Parallel( func() { - msgBytes := bm.BinaryBytes(authSigMessage{pubKey, signature}) + msgBytes := wire.BinaryBytes(authSigMessage{pubKey, signature}) _, err1 = sc.Write(msgBytes) }, func() { - // NOTE relies on atomicity of small data. - readBuffer := make([]byte, dataMaxSize) - _, err2 = sc.Read(readBuffer) + readBuffer := make([]byte, authSigMsgSize) + _, err2 = io.ReadFull(sc, readBuffer) if err2 != nil { return } n := int64(0) // not used. - recvMsg = bm.ReadBinary(authSigMessage{}, bytes.NewBuffer(readBuffer), &n, &err2).(authSigMessage) + recvMsg = wire.ReadBinary(authSigMessage{}, bytes.NewBuffer(readBuffer), &n, &err2).(authSigMessage) }) if err1 != nil { - return nil, nil, err1 + return nil, err1 } if err2 != nil { - return nil, nil, err2 + return nil, err2 } - return recvMsg.Key, recvMsg.Sig, nil + return &recvMsg, nil } func verifyChallengeSignature(challenge *[32]byte, remPubKey acm.PubKeyEd25519, remSignature acm.SignatureEd25519) bool { diff --git a/Godeps/_workspace/src/github.com/tendermint/tendermint/p2p/secret_connection_test.go b/Godeps/_workspace/src/github.com/tendermint/tendermint/p2p/secret_connection_test.go index bd2504c0..32bf1aac 100644 --- a/Godeps/_workspace/src/github.com/tendermint/tendermint/p2p/secret_connection_test.go +++ b/Godeps/_workspace/src/github.com/tendermint/tendermint/p2p/secret_connection_test.go @@ -32,9 +32,9 @@ func makeDummyConnPair() (fooConn, barConn dummyConn) { func makeSecretConnPair(tb testing.TB) (fooSecConn, barSecConn *SecretConnection) { fooConn, barConn := makeDummyConnPair() - fooPrvKey := acm.PrivKeyEd25519(CRandBytes(32)) + fooPrvKey := acm.GenPrivKeyEd25519() fooPubKey := fooPrvKey.PubKey().(acm.PubKeyEd25519) - barPrvKey := acm.PrivKeyEd25519(CRandBytes(32)) + barPrvKey := acm.GenPrivKeyEd25519() barPubKey := barPrvKey.PubKey().(acm.PubKeyEd25519) Parallel( @@ -45,7 +45,8 @@ func makeSecretConnPair(tb testing.TB) (fooSecConn, barSecConn *SecretConnection tb.Errorf("Failed to establish SecretConnection for foo: %v", err) return } - if !bytes.Equal(fooSecConn.RemotePubKey(), barPubKey) { + remotePubBytes := fooSecConn.RemotePubKey() + if !bytes.Equal(remotePubBytes[:], barPubKey[:]) { tb.Errorf("Unexpected fooSecConn.RemotePubKey. Expected %v, got %v", barPubKey, fooSecConn.RemotePubKey()) } @@ -57,7 +58,8 @@ func makeSecretConnPair(tb testing.TB) (fooSecConn, barSecConn *SecretConnection tb.Errorf("Failed to establish SecretConnection for bar: %v", err) return } - if !bytes.Equal(barSecConn.RemotePubKey(), fooPubKey) { + remotePubBytes := barSecConn.RemotePubKey() + if !bytes.Equal(remotePubBytes[:], fooPubKey[:]) { tb.Errorf("Unexpected barSecConn.RemotePubKey. Expected %v, got %v", fooPubKey, barSecConn.RemotePubKey()) } @@ -87,7 +89,7 @@ func TestSecretConnectionReadWrite(t *testing.T) { genNodeRunner := func(nodeConn dummyConn, nodeWrites []string, nodeReads *[]string) func() { return func() { // Node handskae - nodePrvKey := acm.PrivKeyEd25519(CRandBytes(32)) + nodePrvKey := acm.GenPrivKeyEd25519() nodeSecretConn, err := MakeSecretConnection(nodeConn, nodePrvKey) if err != nil { t.Errorf("Failed to establish SecretConnection for node: %v", err) diff --git a/Godeps/_workspace/src/github.com/tendermint/tendermint/p2p/switch.go b/Godeps/_workspace/src/github.com/tendermint/tendermint/p2p/switch.go index bce10b04..7d9fcb52 100644 --- a/Godeps/_workspace/src/github.com/tendermint/tendermint/p2p/switch.go +++ b/Godeps/_workspace/src/github.com/tendermint/tendermint/p2p/switch.go @@ -5,17 +5,18 @@ import ( "fmt" "net" "strconv" - "sync/atomic" "time" + "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/log15" acm "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/account" . "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/common" "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/types" ) type Reactor interface { - Start(sw *Switch) - Stop() + Service // Start, Stop + + SetSwitch(*Switch) GetChannels() []*ChannelDescriptor AddPeer(peer *Peer) RemovePeer(peer *Peer, reason interface{}) @@ -24,14 +25,25 @@ type Reactor interface { //-------------------------------------- -type BaseReactor struct{} +type BaseReactor struct { + QuitService // Provides Start, Stop, .Quit + Switch *Switch +} + +func NewBaseReactor(log log15.Logger, name string, impl Reactor) *BaseReactor { + return &BaseReactor{ + QuitService: *NewQuitService(log, name, impl), + Switch: nil, + } +} -func (_ BaseReactor) Start(sw *Switch) {} -func (_ BaseReactor) Stop() {} -func (_ BaseReactor) GetChannels() []*ChannelDescriptor { return nil } -func (_ BaseReactor) AddPeer(peer *Peer) {} -func (_ BaseReactor) RemovePeer(peer *Peer, reason interface{}) {} -func (_ BaseReactor) Receive(chId byte, peer *Peer, msgBytes []byte) {} +func (br *BaseReactor) SetSwitch(sw *Switch) { + br.Switch = sw +} +func (_ *BaseReactor) GetChannels() []*ChannelDescriptor { return nil } +func (_ *BaseReactor) AddPeer(peer *Peer) {} +func (_ *BaseReactor) RemovePeer(peer *Peer, reason interface{}) {} +func (_ *BaseReactor) Receive(chId byte, peer *Peer, msgBytes []byte) {} //----------------------------------------------------------------------------- @@ -42,13 +54,14 @@ or more `Channels`. So while sending outgoing messages is typically performed o incoming messages are received on the reactor. */ type Switch struct { + BaseService + listeners []Listener reactors map[string]Reactor chDescs []*ChannelDescriptor reactorsByCh map[byte]Reactor peers *PeerSet dialing *CMap - running uint32 nodeInfo *types.NodeInfo // our node info nodePrivKey acm.PrivKeyEd25519 // our node privkey } @@ -59,8 +72,9 @@ var ( ) const ( - peerDialTimeoutSeconds = 3 // TODO make this configurable - maxNumPeers = 50 // TODO make this configurable + peerDialTimeoutSeconds = 3 // TODO make this configurable + handshakeTimeoutSeconds = 20 // TODO make this configurable + maxNumPeers = 50 // TODO make this configurable ) func NewSwitch() *Switch { @@ -70,10 +84,9 @@ func NewSwitch() *Switch { reactorsByCh: make(map[byte]Reactor), peers: NewPeerSet(), dialing: NewCMap(), - running: 0, nodeInfo: nil, - nodePrivKey: nil, } + sw.BaseService = *NewBaseService(log, "P2P Switch", sw) return sw } @@ -85,12 +98,13 @@ func (sw *Switch) AddReactor(name string, reactor Reactor) Reactor { for _, chDesc := range reactorChannels { chId := chDesc.Id if sw.reactorsByCh[chId] != nil { - panic(fmt.Sprintf("Channel %X has multiple reactors %v & %v", chId, sw.reactorsByCh[chId], reactor)) + PanicSanity(fmt.Sprintf("Channel %X has multiple reactors %v & %v", chId, sw.reactorsByCh[chId], reactor)) } sw.chDescs = append(sw.chDescs, chDesc) sw.reactorsByCh[chId] = reactor } sw.reactors[name] = reactor + reactor.SetSwitch(sw) return reactor } @@ -138,48 +152,51 @@ func (sw *Switch) SetNodePrivKey(nodePrivKey acm.PrivKeyEd25519) { } } -func (sw *Switch) Start() { - if atomic.CompareAndSwapUint32(&sw.running, 0, 1) { - // Start reactors - for _, reactor := range sw.reactors { - reactor.Start(sw) - } - // Start peers - for _, peer := range sw.peers.List() { - sw.startInitPeer(peer) - } - // Start listeners - for _, listener := range sw.listeners { - go sw.listenerRoutine(listener) - } +// Switch.Start() starts all the reactors, peers, and listeners. +func (sw *Switch) OnStart() { + sw.BaseService.OnStart() + // Start reactors + for _, reactor := range sw.reactors { + reactor.Start() + } + // Start peers + for _, peer := range sw.peers.List() { + sw.startInitPeer(peer) + } + // Start listeners + for _, listener := range sw.listeners { + go sw.listenerRoutine(listener) } } -func (sw *Switch) Stop() { - if atomic.CompareAndSwapUint32(&sw.running, 1, 0) { - // Stop listeners - for _, listener := range sw.listeners { - listener.Stop() - } - sw.listeners = nil - // Stop peers - for _, peer := range sw.peers.List() { - peer.stop() - } - sw.peers = NewPeerSet() - // Stop reactors - for _, reactor := range sw.reactors { - reactor.Stop() - } +func (sw *Switch) OnStop() { + sw.BaseService.OnStop() + // Stop listeners + for _, listener := range sw.listeners { + listener.Stop() + } + sw.listeners = nil + // Stop peers + for _, peer := range sw.peers.List() { + peer.Stop() + } + sw.peers = NewPeerSet() + // Stop reactors + for _, reactor := range sw.reactors { + reactor.Stop() } } // NOTE: This performs a blocking handshake before the peer is added. // CONTRACT: Iff error is returned, peer is nil, and conn is immediately closed. func (sw *Switch) AddPeerWithConnection(conn net.Conn, outbound bool) (*Peer, error) { + // Set deadline for handshake so we don't block forever on conn.ReadFull + conn.SetDeadline(time.Now().Add(handshakeTimeoutSeconds * time.Second)) + // First, encrypt the connection. sconn, err := MakeSecretConnection(conn, sw.nodePrivKey) if err != nil { + conn.Close() return nil, err } // Then, perform node handshake @@ -205,9 +222,8 @@ func (sw *Switch) AddPeerWithConnection(conn net.Conn, outbound bool) (*Peer, er return nil, err } - // The peerNodeInfo is not verified, so overwrite. - // Overwrite the IP with that from the conn - // and if we dialed out, the port too + // The peerNodeInfo is not verified, so overwrite + // the IP, and the port too if we dialed out // Everything else we just have to trust ip, port, _ := net.SplitHostPort(sconn.RemoteAddr().String()) peerNodeInfo.Host = ip @@ -220,39 +236,41 @@ func (sw *Switch) AddPeerWithConnection(conn net.Conn, outbound bool) (*Peer, er // Add the peer to .peers // ignore if duplicate or if we already have too many for that IP range if err := sw.peers.Add(peer); err != nil { - log.Info("Ignoring peer", "error", err, "peer", peer) - peer.stop() // will also close sconn + log.Notice("Ignoring peer", "error", err, "peer", peer) + peer.Stop() return nil, err } - if atomic.LoadUint32(&sw.running) == 1 { + // remove deadline and start peer + conn.SetDeadline(time.Time{}) + if sw.IsRunning() { sw.startInitPeer(peer) } - log.Info("Added peer", "peer", peer) + log.Notice("Added peer", "peer", peer) return peer, nil } func (sw *Switch) startInitPeer(peer *Peer) { - peer.start() // spawn send/recv routines + peer.Start() // spawn send/recv routines sw.addPeerToReactors(peer) // run AddPeer on each reactor } func (sw *Switch) DialPeerWithAddress(addr *NetAddress) (*Peer, error) { - log.Debug("Dialing address", "address", addr) + log.Info("Dialing address", "address", addr) sw.dialing.Set(addr.IP.String(), addr) conn, err := addr.DialTimeout(peerDialTimeoutSeconds * time.Second) sw.dialing.Delete(addr.IP.String()) if err != nil { - log.Debug("Failed dialing address", "address", addr, "error", err) + log.Info("Failed dialing address", "address", addr, "error", err) return nil, err } peer, err := sw.AddPeerWithConnection(conn, true) if err != nil { - log.Debug("Failed adding peer", "address", addr, "conn", conn, "error", err) + log.Info("Failed adding peer", "address", addr, "conn", conn, "error", err) return nil, err } - log.Info("Dialed and added peer", "address", addr, "peer", peer) + log.Notice("Dialed and added peer", "address", addr, "peer", peer) return peer, nil } @@ -265,7 +283,7 @@ func (sw *Switch) IsDialing(addr *NetAddress) bool { // which receives success values for each attempted send (false if times out) func (sw *Switch) Broadcast(chId byte, msg interface{}) chan bool { successChan := make(chan bool, len(sw.peers.List())) - log.Debug("Broadcast", "channel", chId, "msg", msg) + log.Info("Broadcast", "channel", chId, "msg", msg) for _, peer := range sw.peers.List() { go func(peer *Peer) { success := peer.Send(chId, msg) @@ -297,18 +315,18 @@ func (sw *Switch) Peers() IPeerSet { // Disconnect from a peer due to external error. // TODO: make record depending on reason. func (sw *Switch) StopPeerForError(peer *Peer, reason interface{}) { - log.Info("Stopping peer for error", "peer", peer, "error", reason) + log.Notice("Stopping peer for error", "peer", peer, "error", reason) sw.peers.Remove(peer) - peer.stop() + peer.Stop() sw.removePeerFromReactors(peer, reason) } // Disconnect from a peer gracefully. // TODO: handle graceful disconnects. func (sw *Switch) StopPeerGracefully(peer *Peer) { - log.Info("Stopping peer gracefully") + log.Notice("Stopping peer gracefully") sw.peers.Remove(peer) - peer.stop() + peer.Stop() sw.removePeerFromReactors(peer, nil) } @@ -333,20 +351,20 @@ func (sw *Switch) listenerRoutine(l Listener) { // ignore connection if we already have enough if maxNumPeers <= sw.peers.Size() { - log.Debug("Ignoring inbound connection: already have enough peers", "conn", inConn, "numPeers", sw.peers.Size(), "max", maxNumPeers) + log.Info("Ignoring inbound connection: already have enough peers", "address", inConn.RemoteAddr().String(), "numPeers", sw.peers.Size(), "max", maxNumPeers) continue } // Ignore connections from IP ranges for which we have too many if sw.peers.HasMaxForIPRange(inConn) { - log.Debug("Ignoring inbound connection: already have enough peers for that IP range", "address", inConn.RemoteAddr().String()) + log.Info("Ignoring inbound connection: already have enough peers for that IP range", "address", inConn.RemoteAddr().String()) continue } // New inbound connection! _, err := sw.AddPeerWithConnection(inConn, false) if err != nil { - log.Info("Ignoring inbound connection: error on AddPeerWithConnection", "conn", inConn, "error", err) + log.Notice("Ignoring inbound connection: error on AddPeerWithConnection", "address", inConn.RemoteAddr().String(), "error", err) continue } diff --git a/Godeps/_workspace/src/github.com/tendermint/tendermint/p2p/switch_test.go b/Godeps/_workspace/src/github.com/tendermint/tendermint/p2p/switch_test.go index 48511e8f..d770a778 100644 --- a/Godeps/_workspace/src/github.com/tendermint/tendermint/p2p/switch_test.go +++ b/Godeps/_workspace/src/github.com/tendermint/tendermint/p2p/switch_test.go @@ -7,9 +7,9 @@ import ( "time" acm "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/account" - "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/binary" . "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/common" "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/types" + "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/wire" ) type PeerMessage struct { @@ -19,6 +19,8 @@ type PeerMessage struct { } type TestReactor struct { + BaseReactor + mtx sync.Mutex channels []*ChannelDescriptor peersAdded []*Peer @@ -29,17 +31,13 @@ type TestReactor struct { } func NewTestReactor(channels []*ChannelDescriptor, logMessages bool) *TestReactor { - return &TestReactor{ + tr := &TestReactor{ channels: channels, logMessages: logMessages, msgsReceived: make(map[byte][]PeerMessage), } -} - -func (tr *TestReactor) Start(sw *Switch) { -} - -func (tr *TestReactor) Stop() { + tr.BaseReactor = *NewBaseReactor(log, "TestReactor", tr) + return tr } func (tr *TestReactor) GetChannels() []*ChannelDescriptor { @@ -94,7 +92,7 @@ func makeSwitchPair(t testing.TB, initSwitch func(*Switch) *Switch) (*Switch, *S }) s2.SetNodePrivKey(s2PrivKey) - // Start switches + // Start switches and reactors s1.Start() s2.Start() @@ -132,11 +130,11 @@ func TestSwitches(t *testing.T) { sw.AddReactor("foo", NewTestReactor([]*ChannelDescriptor{ &ChannelDescriptor{Id: byte(0x00), Priority: 10}, &ChannelDescriptor{Id: byte(0x01), Priority: 10}, - }, true)).Start(sw) // Start the reactor + }, true)) sw.AddReactor("bar", NewTestReactor([]*ChannelDescriptor{ &ChannelDescriptor{Id: byte(0x02), Priority: 10}, &ChannelDescriptor{Id: byte(0x03), Priority: 10}, - }, true)).Start(sw) // Start the reactor + }, true)) return sw }) defer s1.Stop() @@ -166,8 +164,8 @@ func TestSwitches(t *testing.T) { if len(ch0Msgs) != 1 { t.Errorf("Expected to have received 1 message in ch0") } - if !bytes.Equal(ch0Msgs[0].Bytes, binary.BinaryBytes(ch0Msg)) { - t.Errorf("Unexpected message bytes. Wanted: %X, Got: %X", binary.BinaryBytes(ch0Msg), ch0Msgs[0].Bytes) + if !bytes.Equal(ch0Msgs[0].Bytes, wire.BinaryBytes(ch0Msg)) { + t.Errorf("Unexpected message bytes. Wanted: %X, Got: %X", wire.BinaryBytes(ch0Msg), ch0Msgs[0].Bytes) } // Check message on ch1 @@ -175,8 +173,8 @@ func TestSwitches(t *testing.T) { if len(ch1Msgs) != 1 { t.Errorf("Expected to have received 1 message in ch1") } - if !bytes.Equal(ch1Msgs[0].Bytes, binary.BinaryBytes(ch1Msg)) { - t.Errorf("Unexpected message bytes. Wanted: %X, Got: %X", binary.BinaryBytes(ch1Msg), ch1Msgs[0].Bytes) + if !bytes.Equal(ch1Msgs[0].Bytes, wire.BinaryBytes(ch1Msg)) { + t.Errorf("Unexpected message bytes. Wanted: %X, Got: %X", wire.BinaryBytes(ch1Msg), ch1Msgs[0].Bytes) } // Check message on ch2 @@ -184,8 +182,8 @@ func TestSwitches(t *testing.T) { if len(ch2Msgs) != 1 { t.Errorf("Expected to have received 1 message in ch2") } - if !bytes.Equal(ch2Msgs[0].Bytes, binary.BinaryBytes(ch2Msg)) { - t.Errorf("Unexpected message bytes. Wanted: %X, Got: %X", binary.BinaryBytes(ch2Msg), ch2Msgs[0].Bytes) + if !bytes.Equal(ch2Msgs[0].Bytes, wire.BinaryBytes(ch2Msg)) { + t.Errorf("Unexpected message bytes. Wanted: %X, Got: %X", wire.BinaryBytes(ch2Msg), ch2Msgs[0].Bytes) } } diff --git a/Godeps/_workspace/src/github.com/tendermint/tendermint/p2p/upnp/probe.go b/Godeps/_workspace/src/github.com/tendermint/tendermint/p2p/upnp/probe.go index 6c2147ba..4de2f8ca 100644 --- a/Godeps/_workspace/src/github.com/tendermint/tendermint/p2p/upnp/probe.go +++ b/Godeps/_workspace/src/github.com/tendermint/tendermint/p2p/upnp/probe.go @@ -19,19 +19,19 @@ func makeUPNPListener(intPort int, extPort int) (NAT, net.Listener, net.IP, erro if err != nil { return nil, nil, nil, errors.New(fmt.Sprintf("NAT upnp could not be discovered: %v", err)) } - log.Debug(Fmt("ourIP: %v", nat.(*upnpNAT).ourIP)) + log.Info(Fmt("ourIP: %v", nat.(*upnpNAT).ourIP)) ext, err := nat.GetExternalAddress() if err != nil { return nat, nil, nil, errors.New(fmt.Sprintf("External address error: %v", err)) } - log.Debug(Fmt("External address: %v", ext)) + log.Info(Fmt("External address: %v", ext)) port, err := nat.AddPortMapping("tcp", extPort, intPort, "Tendermint UPnP Probe", 0) if err != nil { return nat, nil, ext, errors.New(fmt.Sprintf("Port mapping error: %v", err)) } - log.Debug(Fmt("Port mapping mapped: %v", port)) + log.Info(Fmt("Port mapping mapped: %v", port)) // also run the listener, open for all remote addresses. listener, err := net.Listen("tcp", fmt.Sprintf(":%v", intPort)) @@ -46,17 +46,17 @@ func testHairpin(listener net.Listener, extAddr string) (supportsHairpin bool) { go func() { inConn, err := listener.Accept() if err != nil { - log.Info(Fmt("Listener.Accept() error: %v", err)) + log.Notice(Fmt("Listener.Accept() error: %v", err)) return } - log.Debug(Fmt("Accepted incoming connection: %v -> %v", inConn.LocalAddr(), inConn.RemoteAddr())) + log.Info(Fmt("Accepted incoming connection: %v -> %v", inConn.LocalAddr(), inConn.RemoteAddr())) buf := make([]byte, 1024) n, err := inConn.Read(buf) if err != nil { - log.Info(Fmt("Incoming connection read error: %v", err)) + log.Notice(Fmt("Incoming connection read error: %v", err)) return } - log.Debug(Fmt("Incoming connection read %v bytes: %X", n, buf)) + log.Info(Fmt("Incoming connection read %v bytes: %X", n, buf)) if string(buf) == "test data" { supportsHairpin = true return @@ -66,16 +66,16 @@ func testHairpin(listener net.Listener, extAddr string) (supportsHairpin bool) { // Establish outgoing outConn, err := net.Dial("tcp", extAddr) if err != nil { - log.Info(Fmt("Outgoing connection dial error: %v", err)) + log.Notice(Fmt("Outgoing connection dial error: %v", err)) return } n, err := outConn.Write([]byte("test data")) if err != nil { - log.Info(Fmt("Outgoing connection write error: %v", err)) + log.Notice(Fmt("Outgoing connection write error: %v", err)) return } - log.Debug(Fmt("Outgoing connection wrote %v bytes", n)) + log.Info(Fmt("Outgoing connection wrote %v bytes", n)) // Wait for data receipt time.Sleep(1 * time.Second) @@ -83,7 +83,7 @@ func testHairpin(listener net.Listener, extAddr string) (supportsHairpin bool) { } func Probe() (caps UPNPCapabilities, err error) { - log.Debug("Probing for UPnP!") + log.Info("Probing for UPnP!") intPort, extPort := 8001, 8001 diff --git a/Godeps/_workspace/src/github.com/tendermint/tendermint/p2p/upnp/upnp.go b/Godeps/_workspace/src/github.com/tendermint/tendermint/p2p/upnp/upnp.go index 7aff240b..3d6c5503 100644 --- a/Godeps/_workspace/src/github.com/tendermint/tendermint/p2p/upnp/upnp.go +++ b/Godeps/_workspace/src/github.com/tendermint/tendermint/p2p/upnp/upnp.go @@ -126,7 +126,7 @@ type ExternalIPAddress struct { IP string } -type Service struct { +type UPNPService struct { ServiceType string `xml:"serviceType"` ControlURL string `xml:"controlURL"` } @@ -136,7 +136,7 @@ type DeviceList struct { } type ServiceList struct { - Service []Service `xml:"service"` + Service []UPNPService `xml:"service"` } type Device struct { @@ -160,7 +160,7 @@ func getChildDevice(d *Device, deviceType string) *Device { return nil } -func getChildService(d *Device, serviceType string) *Service { +func getChildService(d *Device, serviceType string) *UPNPService { sl := d.ServiceList.Service for i := 0; i < len(sl); i++ { if strings.Index(sl[i].ServiceType, serviceType) >= 0 { diff --git a/Godeps/_workspace/src/github.com/tendermint/tendermint/permission/types/permissions.go b/Godeps/_workspace/src/github.com/tendermint/tendermint/permission/types/permissions.go index 0588d4f3..3fa8f3dc 100644 --- a/Godeps/_workspace/src/github.com/tendermint/tendermint/permission/types/permissions.go +++ b/Godeps/_workspace/src/github.com/tendermint/tendermint/permission/types/permissions.go @@ -10,8 +10,6 @@ import ( var ( GlobalPermissionsAddress = Zero256[:20] GlobalPermissionsAddress256 = Zero256 - DougAddress = append([]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, []byte("THISISDOUG")...) - DougAddress256 = LeftPadWord256(DougAddress) ) // A particular permission @@ -19,19 +17,29 @@ type PermFlag uint64 // Base permission references are like unix (the index is already bit shifted) const ( - Root PermFlag = 1 << iota // 1 - Send // 2 - Call // 4 - CreateContract // 8 - CreateAccount // 16 - Bond // 32 - Name // 64 - NumBasePermissions uint = 7 // NOTE Adjust this too. - - TopBasePermFlag PermFlag = 1 << (NumBasePermissions - 1) - AllBasePermFlags PermFlag = TopBasePermFlag | (TopBasePermFlag - 1) - AllPermFlags PermFlag = AllBasePermFlags | AllSNativePermFlags - DefaultBasePermFlags PermFlag = Send | Call | CreateContract | CreateAccount | Bond | Name + // chain permissions + Root PermFlag = 1 << iota // 1 + Send // 2 + Call // 4 + CreateContract // 8 + CreateAccount // 16 + Bond // 32 + Name // 64 + + // moderator permissions + HasBase + SetBase + UnsetBase + SetGlobal + HasRole + AddRole + RmRole + + NumPermissions uint = 14 // NOTE Adjust this too. We can support upto 64 + + TopPermFlag PermFlag = 1 << (NumPermissions - 1) + AllPermFlags PermFlag = TopPermFlag | (TopPermFlag - 1) + DefaultPermFlags PermFlag = Send | Call | CreateContract | CreateAccount | Bond | Name | HasBase | HasRole ) var ( @@ -41,7 +49,7 @@ var ( } DefaultAccountPermissions = AccountPermissions{ Base: BasePermissions{ - Perms: DefaultBasePermFlags, + Perms: DefaultPermFlags, SetBit: AllPermFlags, }, Roles: []string{}, @@ -154,8 +162,10 @@ func (aP *AccountPermissions) RmRole(role string) bool { } //-------------------------------------------------------------------------------- +// string utilities -func PermFlagToString(pf PermFlag) (perm string, err error) { +// PermFlagToString assumes the permFlag is valid, else returns "#-UNKNOWN-#" +func PermFlagToString(pf PermFlag) (perm string) { switch pf { case Root: perm = "root" @@ -171,8 +181,22 @@ func PermFlagToString(pf PermFlag) (perm string, err error) { perm = "bond" case Name: perm = "name" + case HasBase: + perm = "has_base" + case SetBase: + perm = "set_base" + case UnsetBase: + perm = "unset_base" + case SetGlobal: + perm = "set_global" + case HasRole: + perm = "has_role" + case AddRole: + perm = "add_role" + case RmRole: + perm = "rm_role" default: - err = fmt.Errorf("Unknown permission flag %b", pf) + perm = "#-UNKNOWN-#" } return } @@ -193,6 +217,20 @@ func PermStringToFlag(perm string) (pf PermFlag, err error) { pf = Bond case "name": pf = Name + case "has_base": + pf = HasBase + case "set_base": + pf = SetBase + case "unset_base": + pf = UnsetBase + case "set_global": + pf = SetGlobal + case "has_role": + pf = HasRole + case "add_role": + pf = AddRole + case "rm_role": + pf = RmRole default: err = fmt.Errorf("Unknown permission %s", perm) } diff --git a/Godeps/_workspace/src/github.com/tendermint/tendermint/permission/types/snatives.go b/Godeps/_workspace/src/github.com/tendermint/tendermint/permission/types/snatives.go index be1d0b24..0b612bd3 100644 --- a/Godeps/_workspace/src/github.com/tendermint/tendermint/permission/types/snatives.go +++ b/Godeps/_workspace/src/github.com/tendermint/tendermint/permission/types/snatives.go @@ -1,23 +1,102 @@ package types -const ( - // first 32 bits of BasePermission are for chain, second 32 are for snative - FirstSNativePermFlag PermFlag = 1 << 32 +import ( + "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/wire" ) -// we need to reset iota with no const block +//--------------------------------------------------------------------------------------------------- +// PermissionsTx.PermArgs interface and argument encoding + +// Arguments are a registered interface in the PermissionsTx, +// so binary handles the arguments and each permission function gets a type-byte +// PermFlag() maps the type-byte to the permission +// The account sending the PermissionsTx must have this PermFlag set +type PermArgs interface { + PermFlag() PermFlag +} + const ( - // each snative has an associated permission flag - HasBasePerm PermFlag = FirstSNativePermFlag << iota - SetBasePerm - UnsetBasePerm - SetGlobalPerm - ClearBasePerm - HasRole - AddRole - RmRole - NumSNativePermissions uint = 8 // NOTE adjust this too - - TopSNativePermFlag PermFlag = FirstSNativePermFlag << (NumSNativePermissions - 1) - AllSNativePermFlags PermFlag = (TopSNativePermFlag | (TopSNativePermFlag - 1)) &^ (FirstSNativePermFlag - 1) + PermArgsTypeHasBase = byte(0x01) + PermArgsTypeSetBase = byte(0x02) + PermArgsTypeUnsetBase = byte(0x03) + PermArgsTypeSetGlobal = byte(0x04) + PermArgsTypeHasRole = byte(0x05) + PermArgsTypeAddRole = byte(0x06) + PermArgsTypeRmRole = byte(0x07) +) + +// for wire.readReflect +var _ = wire.RegisterInterface( + struct{ PermArgs }{}, + wire.ConcreteType{&HasBaseArgs{}, PermArgsTypeHasBase}, + wire.ConcreteType{&SetBaseArgs{}, PermArgsTypeSetBase}, + wire.ConcreteType{&UnsetBaseArgs{}, PermArgsTypeUnsetBase}, + wire.ConcreteType{&SetGlobalArgs{}, PermArgsTypeSetGlobal}, + wire.ConcreteType{&HasRoleArgs{}, PermArgsTypeHasRole}, + wire.ConcreteType{&AddRoleArgs{}, PermArgsTypeAddRole}, + wire.ConcreteType{&RmRoleArgs{}, PermArgsTypeRmRole}, ) + +type HasBaseArgs struct { + Address []byte `json:"address"` + Permission PermFlag `json:"permission"` +} + +func (*HasBaseArgs) PermFlag() PermFlag { + return HasBase +} + +type SetBaseArgs struct { + Address []byte `json:"address"` + Permission PermFlag `json:"permission"` + Value bool `json:"value"` +} + +func (*SetBaseArgs) PermFlag() PermFlag { + return SetBase +} + +type UnsetBaseArgs struct { + Address []byte `json:"address"` + Permission PermFlag `json:"permission"` +} + +func (*UnsetBaseArgs) PermFlag() PermFlag { + return UnsetBase +} + +type SetGlobalArgs struct { + Permission PermFlag `json:"permission"` + Value bool `json:"value"` +} + +func (*SetGlobalArgs) PermFlag() PermFlag { + return SetGlobal +} + +type HasRoleArgs struct { + Address []byte `json:"address"` + Role string `json:"role"` +} + +func (*HasRoleArgs) PermFlag() PermFlag { + return HasRole +} + +type AddRoleArgs struct { + Address []byte `json:"address"` + Role string `json:"role"` +} + +func (*AddRoleArgs) PermFlag() PermFlag { + return AddRole +} + +type RmRoleArgs struct { + Address []byte `json:"address"` + Role string `json:"role"` +} + +func (*RmRoleArgs) PermFlag() PermFlag { + return RmRole +} diff --git a/Godeps/_workspace/src/github.com/tendermint/tendermint/rpc/core/blocks.go b/Godeps/_workspace/src/github.com/tendermint/tendermint/rpc/core/blocks.go index f50b2ebb..0e109e6c 100644 --- a/Godeps/_workspace/src/github.com/tendermint/tendermint/rpc/core/blocks.go +++ b/Godeps/_workspace/src/github.com/tendermint/tendermint/rpc/core/blocks.go @@ -18,7 +18,7 @@ func BlockchainInfo(minHeight, maxHeight int) (*ctypes.ResponseBlockchainInfo, e if minHeight == 0 { minHeight = MaxInt(1, maxHeight-20) } - log.Debug("BlockchainInfoHandler", "maxHeight", maxHeight, "minHeight", minHeight) + log.Info("BlockchainInfoHandler", "maxHeight", maxHeight, "minHeight", minHeight) blockMetas := []*types.BlockMeta{} for height := maxHeight; height >= minHeight; height-- { diff --git a/Godeps/_workspace/src/github.com/tendermint/tendermint/rpc/core/consensus.go b/Godeps/_workspace/src/github.com/tendermint/tendermint/rpc/core/consensus.go index 69efc084..4840dbca 100644 --- a/Godeps/_workspace/src/github.com/tendermint/tendermint/rpc/core/consensus.go +++ b/Godeps/_workspace/src/github.com/tendermint/tendermint/rpc/core/consensus.go @@ -1,10 +1,10 @@ package core import ( - "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/binary" cm "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/consensus" ctypes "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/rpc/core/types" sm "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/state" + "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/wire" ) func ListValidators() (*ctypes.ResponseListValidators, error) { @@ -33,7 +33,7 @@ func DumpConsensusState() (*ctypes.ResponseDumpConsensusState, error) { // TODO: clean this up? peerState := peer.Data.Get(cm.PeerStateKey).(*cm.PeerState) peerRoundState := peerState.GetRoundState() - peerRoundStateStr := peer.Key + ":" + string(binary.JSONBytes(peerRoundState)) + peerRoundStateStr := peer.Key + ":" + string(wire.JSONBytes(peerRoundState)) peerRoundStates = append(peerRoundStates, peerRoundStateStr) } return &ctypes.ResponseDumpConsensusState{roundState.String(), peerRoundStates}, nil diff --git a/Godeps/_workspace/src/github.com/tendermint/tendermint/rpc/core/routes.go b/Godeps/_workspace/src/github.com/tendermint/tendermint/rpc/core/routes.go index 5ad50d6f..af7687ab 100644 --- a/Godeps/_workspace/src/github.com/tendermint/tendermint/rpc/core/routes.go +++ b/Godeps/_workspace/src/github.com/tendermint/tendermint/rpc/core/routes.go @@ -4,6 +4,7 @@ import ( rpc "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/rpc/server" ) +// TODO: eliminate redundancy between here and reading code from core/ var Routes = map[string]*rpc.RPCFunc{ "status": rpc.NewRPCFunc(Status, []string{}), "net_info": rpc.NewRPCFunc(NetInfo, []string{}), @@ -12,8 +13,8 @@ var Routes = map[string]*rpc.RPCFunc{ "get_block": rpc.NewRPCFunc(GetBlock, []string{"height"}), "get_account": rpc.NewRPCFunc(GetAccount, []string{"address"}), "get_storage": rpc.NewRPCFunc(GetStorage, []string{"address", "key"}), - "call": rpc.NewRPCFunc(Call, []string{"address", "data"}), - "call_code": rpc.NewRPCFunc(CallCode, []string{"code", "data"}), + "call": rpc.NewRPCFunc(Call, []string{"fromAddress", "toAddress", "data"}), + "call_code": rpc.NewRPCFunc(CallCode, []string{"fromAddress", "code", "data"}), "list_validators": rpc.NewRPCFunc(ListValidators, []string{}), "dump_consensus_state": rpc.NewRPCFunc(DumpConsensusState, []string{}), "dump_storage": rpc.NewRPCFunc(DumpStorage, []string{"address"}), @@ -24,4 +25,5 @@ var Routes = map[string]*rpc.RPCFunc{ "list_names": rpc.NewRPCFunc(ListNames, []string{}), "unsafe/gen_priv_account": rpc.NewRPCFunc(GenPrivAccount, []string{}), "unsafe/sign_tx": rpc.NewRPCFunc(SignTx, []string{"tx", "privAccounts"}), + // subscribe/unsubscribe are reserved for websocket events. } diff --git a/Godeps/_workspace/src/github.com/tendermint/tendermint/rpc/core/txs.go b/Godeps/_workspace/src/github.com/tendermint/tendermint/rpc/core/txs.go index 83aee445..266bc6d1 100644 --- a/Godeps/_workspace/src/github.com/tendermint/tendermint/rpc/core/txs.go +++ b/Godeps/_workspace/src/github.com/tendermint/tendermint/rpc/core/txs.go @@ -2,7 +2,7 @@ package core import ( "fmt" - "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/account" + acm "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/account" . "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/common" ctypes "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/rpc/core/types" "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/state" @@ -10,14 +10,13 @@ import ( "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/vm" ) -func toVMAccount(acc *account.Account) *vm.Account { +func toVMAccount(acc *acm.Account) *vm.Account { return &vm.Account{ - Address: LeftPadWord256(acc.Address), - Balance: acc.Balance, - Code: acc.Code, // This is crazy. - Nonce: int64(acc.Sequence), - StorageRoot: LeftPadWord256(acc.StorageRoot), - Other: acc.PubKey, + Address: LeftPadWord256(acc.Address), + Balance: acc.Balance, + Code: acc.Code, // This is crazy. + Nonce: int64(acc.Sequence), + Other: acc.PubKey, } } @@ -25,25 +24,25 @@ func toVMAccount(acc *account.Account) *vm.Account { // Run a contract's code on an isolated and unpersisted state // Cannot be used to create new contracts -func Call(address, data []byte) (*ctypes.ResponseCall, error) { +func Call(fromAddress, toAddress, data []byte) (*ctypes.ResponseCall, error) { st := consensusState.GetState() // performs a copy cache := state.NewBlockCache(st) - outAcc := cache.GetAccount(address) + outAcc := cache.GetAccount(toAddress) if outAcc == nil { - return nil, fmt.Errorf("Account %x does not exist", address) + return nil, fmt.Errorf("Account %x does not exist", toAddress) } callee := toVMAccount(outAcc) - caller := &vm.Account{Address: Zero256} + caller := &vm.Account{Address: LeftPadWord256(fromAddress)} txCache := state.NewTxCache(cache) params := vm.Params{ BlockHeight: int64(st.LastBlockHeight), BlockHash: LeftPadWord256(st.LastBlockHash), BlockTime: st.LastBlockTime.Unix(), - GasLimit: 10000000, + GasLimit: st.GetGasLimit(), } vmach := vm.NewVM(txCache, params, caller.Address, nil) - gas := int64(1000000000) + gas := st.GetGasLimit() ret, err := vmach.Call(caller, callee, callee.Code, data, 0, &gas) if err != nil { return nil, err @@ -53,22 +52,22 @@ func Call(address, data []byte) (*ctypes.ResponseCall, error) { // Run the given code on an isolated and unpersisted state // Cannot be used to create new contracts -func CallCode(code, data []byte) (*ctypes.ResponseCall, error) { +func CallCode(fromAddress, code, data []byte) (*ctypes.ResponseCall, error) { st := consensusState.GetState() // performs a copy cache := mempoolReactor.Mempool.GetCache() - callee := &vm.Account{Address: Zero256} - caller := &vm.Account{Address: Zero256} + callee := &vm.Account{Address: LeftPadWord256(fromAddress)} + caller := &vm.Account{Address: LeftPadWord256(fromAddress)} txCache := state.NewTxCache(cache) params := vm.Params{ BlockHeight: int64(st.LastBlockHeight), BlockHash: LeftPadWord256(st.LastBlockHash), BlockTime: st.LastBlockTime.Unix(), - GasLimit: 10000000, + GasLimit: st.GetGasLimit(), } vmach := vm.NewVM(txCache, params, caller.Address, nil) - gas := int64(1000000000) + gas := st.GetGasLimit() ret, err := vmach.Call(caller, callee, code, data, 0, &gas) if err != nil { return nil, err @@ -78,7 +77,7 @@ func CallCode(code, data []byte) (*ctypes.ResponseCall, error) { //----------------------------------------------------------------------------- -func SignTx(tx types.Tx, privAccounts []*account.PrivAccount) (types.Tx, error) { +func SignTx(tx types.Tx, privAccounts []*acm.PrivAccount) (types.Tx, error) { // more checks? for i, privAccount := range privAccounts { @@ -101,17 +100,17 @@ func SignTx(tx types.Tx, privAccounts []*account.PrivAccount) (types.Tx, error) bondTx := tx.(*types.BondTx) // the first privaccount corresponds to the BondTx pub key. // the rest to the inputs - bondTx.Signature = privAccounts[0].Sign(config.GetString("chain_id"), bondTx).(account.SignatureEd25519) + bondTx.Signature = privAccounts[0].Sign(config.GetString("chain_id"), bondTx).(acm.SignatureEd25519) for i, input := range bondTx.Inputs { input.PubKey = privAccounts[i+1].PubKey input.Signature = privAccounts[i+1].Sign(config.GetString("chain_id"), bondTx) } case *types.UnbondTx: unbondTx := tx.(*types.UnbondTx) - unbondTx.Signature = privAccounts[0].Sign(config.GetString("chain_id"), unbondTx).(account.SignatureEd25519) + unbondTx.Signature = privAccounts[0].Sign(config.GetString("chain_id"), unbondTx).(acm.SignatureEd25519) case *types.RebondTx: rebondTx := tx.(*types.RebondTx) - rebondTx.Signature = privAccounts[0].Sign(config.GetString("chain_id"), rebondTx).(account.SignatureEd25519) + rebondTx.Signature = privAccounts[0].Sign(config.GetString("chain_id"), rebondTx).(acm.SignatureEd25519) } return tx, nil } diff --git a/Godeps/_workspace/src/github.com/tendermint/tendermint/rpc/core/types/responses.go b/Godeps/_workspace/src/github.com/tendermint/tendermint/rpc/core/types/responses.go index bd1e88b8..cc0363bd 100644 --- a/Godeps/_workspace/src/github.com/tendermint/tendermint/rpc/core/types/responses.go +++ b/Godeps/_workspace/src/github.com/tendermint/tendermint/rpc/core/types/responses.go @@ -1,7 +1,7 @@ package core_types import ( - "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/account" + acm "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/account" sm "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/state" "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/types" ) @@ -18,8 +18,8 @@ type ResponseCall struct { } type ResponseListAccounts struct { - BlockHeight int `json:"block_height"` - Accounts []*account.Account `json:"accounts"` + BlockHeight int `json:"block_height"` + Accounts []*acm.Account `json:"accounts"` } type StorageItem struct { @@ -51,7 +51,7 @@ type Receipt struct { type ResponseStatus struct { NodeInfo *types.NodeInfo `json:"node_info"` GenesisHash []byte `json:"genesis_hash"` - PubKey account.PubKey `json:"pub_key"` + PubKey acm.PubKey `json:"pub_key"` LatestBlockHash []byte `json:"latest_block_hash"` LatestBlockHeight int `json:"latest_block_height"` LatestBlockTime int64 `json:"latest_block_time"` // nano @@ -83,3 +83,11 @@ type ResponseListNames struct { BlockHeight int `json:"block_height"` Names []*types.NameRegEntry `json:"names"` } + +//---------------------------------------- +// event responses + +type ResponseEvent struct { + Event string `json:"event"` + Data interface{} `json:"data"` +} diff --git a/Godeps/_workspace/src/github.com/tendermint/tendermint/rpc/server/handlers.go b/Godeps/_workspace/src/github.com/tendermint/tendermint/rpc/server/handlers.go index cae908aa..aca3addf 100644 --- a/Godeps/_workspace/src/github.com/tendermint/tendermint/rpc/server/handlers.go +++ b/Godeps/_workspace/src/github.com/tendermint/tendermint/rpc/server/handlers.go @@ -9,13 +9,13 @@ import ( "net/http" "reflect" "sort" - "sync/atomic" "time" "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/gorilla/websocket" - "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/binary" + . "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/common" "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/events" . "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/rpc/types" + "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/wire" ) func RegisterRPCFuncs(mux *http.ServeMux, funcMap map[string]*RPCFunc) { @@ -28,12 +28,6 @@ func RegisterRPCFuncs(mux *http.ServeMux, funcMap map[string]*RPCFunc) { mux.HandleFunc("/", makeJSONRPCHandler(funcMap)) } -func RegisterEventsHandler(mux *http.ServeMux, evsw *events.EventSwitch) { - // websocket endpoint - wm := NewWebsocketManager(evsw) - mux.HandleFunc("/events", wm.websocketHandler) // websocket.Handler(w.eventsHandler)) -} - //------------------------------------- // function introspection @@ -84,12 +78,7 @@ func funcReturnTypes(f interface{}) []reflect.Type { // jsonrpc calls grab the given method's function info and runs reflect.Call func makeJSONRPCHandler(funcMap map[string]*RPCFunc) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { - if len(r.URL.Path) > 1 { - WriteRPCResponse(w, NewRPCResponse(nil, fmt.Sprintf("Invalid JSONRPC endpoint %s", r.URL.Path))) - return - } b, _ := ioutil.ReadAll(r.Body) - // if its an empty request (like from a browser), // just display a list of functions if len(b) == 0 { @@ -100,27 +89,31 @@ func makeJSONRPCHandler(funcMap map[string]*RPCFunc) http.HandlerFunc { var request RPCRequest err := json.Unmarshal(b, &request) if err != nil { - WriteRPCResponse(w, NewRPCResponse(nil, err.Error())) + WriteRPCResponse(w, NewRPCResponse("", nil, err.Error())) + return + } + if len(r.URL.Path) > 1 { + WriteRPCResponse(w, NewRPCResponse(request.Id, nil, fmt.Sprintf("Invalid JSONRPC endpoint %s", r.URL.Path))) return } rpcFunc := funcMap[request.Method] if rpcFunc == nil { - WriteRPCResponse(w, NewRPCResponse(nil, "RPC method unknown: "+request.Method)) + WriteRPCResponse(w, NewRPCResponse(request.Id, nil, "RPC method unknown: "+request.Method)) return } args, err := jsonParamsToArgs(rpcFunc, request.Params) if err != nil { - WriteRPCResponse(w, NewRPCResponse(nil, err.Error())) + WriteRPCResponse(w, NewRPCResponse(request.Id, nil, err.Error())) return } returns := rpcFunc.f.Call(args) - log.Debug("HTTPJSONRPC", "method", request.Method, "args", args, "returns", returns) - response, err := unreflectResponse(returns) + log.Info("HTTPJSONRPC", "method", request.Method, "args", args, "returns", returns) + result, err := unreflectResult(returns) if err != nil { - WriteRPCResponse(w, NewRPCResponse(nil, err.Error())) + WriteRPCResponse(w, NewRPCResponse(request.Id, nil, err.Error())) return } - WriteRPCResponse(w, NewRPCResponse(response, "")) + WriteRPCResponse(w, NewRPCResponse(request.Id, result, "")) } } @@ -145,7 +138,7 @@ func jsonParamsToArgs(rpcFunc *RPCFunc, params []interface{}) ([]reflect.Value, func _jsonObjectToArg(ty reflect.Type, object interface{}) (reflect.Value, error) { var err error v := reflect.New(ty) - binary.ReadJSONObjectPtr(v.Interface(), object, &err) + wire.ReadJSONObjectPtr(v.Interface(), object, &err) if err != nil { return v, err } @@ -162,17 +155,17 @@ func makeHTTPHandler(rpcFunc *RPCFunc) func(http.ResponseWriter, *http.Request) return func(w http.ResponseWriter, r *http.Request) { args, err := httpParamsToArgs(rpcFunc, r) if err != nil { - WriteRPCResponse(w, NewRPCResponse(nil, err.Error())) + WriteRPCResponse(w, NewRPCResponse("", nil, err.Error())) return } returns := rpcFunc.f.Call(args) - log.Debug("HTTPRestRPC", "method", r.URL.Path, "args", args, "returns", returns) - response, err := unreflectResponse(returns) + log.Info("HTTPRestRPC", "method", r.URL.Path, "args", args, "returns", returns) + result, err := unreflectResult(returns) if err != nil { - WriteRPCResponse(w, NewRPCResponse(nil, err.Error())) + WriteRPCResponse(w, NewRPCResponse("", nil, err.Error())) return } - WriteRPCResponse(w, NewRPCResponse(response, "")) + WriteRPCResponse(w, NewRPCResponse("", result, "")) } } @@ -198,7 +191,7 @@ func httpParamsToArgs(rpcFunc *RPCFunc, r *http.Request) ([]reflect.Value, error func _jsonStringToArg(ty reflect.Type, arg string) (reflect.Value, error) { var err error v := reflect.New(ty) - binary.ReadJSONPtr(v.Interface(), []byte(arg), &err) + wire.ReadJSONPtr(v.Interface(), []byte(arg), &err) if err != nil { return v, err } @@ -211,162 +204,221 @@ func _jsonStringToArg(ty reflect.Type, arg string) (reflect.Value, error) { // rpc.websocket const ( - WSConnectionReaperSeconds = 5 - MaxFailedSends = 10 - WriteChanBufferSize = 10 + writeChanCapacity = 20 + WSWriteTimeoutSeconds = 10 // exposed for tests + WSReadTimeoutSeconds = 10 // exposed for tests ) // a single websocket connection // contains listener id, underlying ws connection, // and the event switch for subscribing to events type WSConnection struct { + QuitService + id string - wsConn *websocket.Conn - writeChan chan WSResponse - quitChan chan struct{} - failedSends int - started uint32 - stopped uint32 - - evsw *events.EventSwitch + baseConn *websocket.Conn + writeChan chan RPCResponse + readTimeout *time.Timer + + funcMap map[string]*RPCFunc + evsw *events.EventSwitch } // new websocket connection wrapper -func NewWSConnection(wsConn *websocket.Conn) *WSConnection { - return &WSConnection{ - id: wsConn.RemoteAddr().String(), - wsConn: wsConn, - writeChan: make(chan WSResponse, WriteChanBufferSize), // buffered. we keep track when its full - quitChan: make(chan struct{}), +func NewWSConnection(baseConn *websocket.Conn, funcMap map[string]*RPCFunc, evsw *events.EventSwitch) *WSConnection { + wsc := &WSConnection{ + id: baseConn.RemoteAddr().String(), + baseConn: baseConn, + writeChan: make(chan RPCResponse, writeChanCapacity), // error when full. + funcMap: funcMap, + evsw: evsw, } + wsc.QuitService = *NewQuitService(log, "WSConnection", wsc) + return wsc } -// start the connection and hand her the event switch -func (con *WSConnection) Start(evsw *events.EventSwitch) { - if atomic.CompareAndSwapUint32(&con.started, 0, 1) { - con.evsw = evsw +// wsc.Start() blocks until the connection closes. +func (wsc *WSConnection) OnStart() { + wsc.QuitService.OnStart() + + // Read subscriptions/unsubscriptions to events + go wsc.readRoutine() + + // Custom Ping handler to touch readTimeout + wsc.readTimeout = time.NewTimer(time.Second * WSReadTimeoutSeconds) + wsc.baseConn.SetPingHandler(func(m string) error { + wsc.baseConn.WriteControl(websocket.PongMessage, []byte(m), time.Now().Add(time.Second*WSWriteTimeoutSeconds)) + wsc.readTimeout.Reset(time.Second * WSReadTimeoutSeconds) + return nil + }) + wsc.baseConn.SetPongHandler(func(m string) error { + wsc.readTimeout.Reset(time.Second * WSReadTimeoutSeconds) + return nil + }) + go wsc.readTimeoutRoutine() + + // Write responses, BLOCKING. + wsc.writeRoutine() +} - // read subscriptions/unsubscriptions to events - go con.read() - // write responses - con.write() - } +func (wsc *WSConnection) OnStop() { + wsc.QuitService.OnStop() + wsc.evsw.RemoveListener(wsc.id) + wsc.readTimeout.Stop() + // The write loop closes the websocket connection + // when it exits its loop, and the read loop + // closes the writeChan } -// close the connection -func (con *WSConnection) Stop() { - if atomic.CompareAndSwapUint32(&con.stopped, 0, 1) { - con.evsw.RemoveListener(con.id) - close(con.quitChan) - // the write loop closes the websocket connection - // when it exits its loop, and the read loop - // closes the writeChan +func (wsc *WSConnection) readTimeoutRoutine() { + select { + case <-wsc.readTimeout.C: + log.Notice("Stopping connection due to read timeout") + wsc.Stop() + case <-wsc.Quit: + return } } -// attempt to write response to writeChan and record failures -func (con *WSConnection) safeWrite(resp WSResponse) { +// Attempt to write response to writeChan and record failures +func (wsc *WSConnection) writeRPCResponse(resp RPCResponse) { select { - case con.writeChan <- resp: - // yay - con.failedSends = 0 + case wsc.writeChan <- resp: default: - // channel is full - // if this happens too many times in a row, - // close connection - con.failedSends += 1 + log.Notice("Stopping connection due to writeChan overflow", "id", wsc.id) + wsc.Stop() // writeChan capacity exceeded, error. } } -// read from the socket and subscribe to or unsubscribe from events -func (con *WSConnection) read() { - defer close(con.writeChan) - reaper := time.Tick(time.Second * WSConnectionReaperSeconds) +// Read from the socket and subscribe to or unsubscribe from events +func (wsc *WSConnection) readRoutine() { + // Do not close writeChan, to allow writeRPCResponse() to fail. + // defer close(wsc.writeChan) + for { select { - // TODO: this actually doesn't work - // since ReadMessage blocks. Really it needs its own - // go routine - case <-reaper: - if con.failedSends > MaxFailedSends { - // sending has failed too many times. - // kill the connection - con.Stop() - return - } + case <-wsc.Quit: + return default: var in []byte - _, in, err := con.wsConn.ReadMessage() + // Do not set a deadline here like below: + // wsc.baseConn.SetReadDeadline(time.Now().Add(time.Second * WSReadTimeoutSeconds)) + // The client may not send anything for a while. + // We use `readTimeout` to handle read timeouts. + _, in, err := wsc.baseConn.ReadMessage() if err != nil { + log.Notice("Failed to read from connection", "id", wsc.id) // an error reading the connection, // kill the connection - con.Stop() + wsc.Stop() return } - var req WSRequest - err = json.Unmarshal(in, &req) + var request RPCRequest + err = json.Unmarshal(in, &request) if err != nil { errStr := fmt.Sprintf("Error unmarshaling data: %s", err.Error()) - con.safeWrite(WSResponse{Error: errStr}) + wsc.writeRPCResponse(NewRPCResponse(request.Id, nil, errStr)) continue } - switch req.Type { + switch request.Method { case "subscribe": - log.Info("New event subscription", "con id", con.id, "event", req.Event) - con.evsw.AddListenerForEvent(con.id, req.Event, func(msg interface{}) { - resp := WSResponse{ - Event: req.Event, - Data: msg, - } - con.safeWrite(resp) - }) + if len(request.Params) != 1 { + wsc.writeRPCResponse(NewRPCResponse(request.Id, nil, "subscribe takes 1 event parameter string")) + continue + } + if event, ok := request.Params[0].(string); !ok { + wsc.writeRPCResponse(NewRPCResponse(request.Id, nil, "subscribe takes 1 event parameter string")) + continue + } else { + log.Notice("Subscribe to event", "id", wsc.id, "event", event) + wsc.evsw.AddListenerForEvent(wsc.id, event, func(msg interface{}) { + wsc.writeRPCResponse(NewRPCResponse(request.Id, RPCEventResult{event, msg}, "")) + }) + continue + } case "unsubscribe": - if req.Event != "" { - con.evsw.RemoveListenerForEvent(req.Event, con.id) + if len(request.Params) == 0 { + log.Notice("Unsubscribe from all events", "id", wsc.id) + wsc.evsw.RemoveListener(wsc.id) + continue + } else if len(request.Params) == 1 { + if event, ok := request.Params[0].(string); !ok { + wsc.writeRPCResponse(NewRPCResponse(request.Id, nil, "unsubscribe takes 0 or 1 event parameter strings")) + continue + } else { + log.Notice("Unsubscribe from event", "id", wsc.id, "event", event) + wsc.evsw.RemoveListenerForEvent(event, wsc.id) + continue + } } else { - con.evsw.RemoveListener(con.id) + wsc.writeRPCResponse(NewRPCResponse(request.Id, nil, "unsubscribe takes 0 or 1 event parameter strings")) + continue } default: - con.safeWrite(WSResponse{Error: "Unknown request type: " + req.Type}) + rpcFunc := wsc.funcMap[request.Method] + if rpcFunc == nil { + wsc.writeRPCResponse(NewRPCResponse(request.Id, nil, "RPC method unknown: "+request.Method)) + continue + } + args, err := jsonParamsToArgs(rpcFunc, request.Params) + if err != nil { + wsc.writeRPCResponse(NewRPCResponse(request.Id, nil, err.Error())) + continue + } + returns := rpcFunc.f.Call(args) + log.Info("WSJSONRPC", "method", request.Method, "args", args, "returns", returns) + result, err := unreflectResult(returns) + if err != nil { + wsc.writeRPCResponse(NewRPCResponse(request.Id, nil, err.Error())) + continue + } else { + wsc.writeRPCResponse(NewRPCResponse(request.Id, result, "")) + continue + } } } } } // receives on a write channel and writes out on the socket -func (con *WSConnection) write() { - defer con.wsConn.Close() +func (wsc *WSConnection) writeRoutine() { + defer wsc.baseConn.Close() n, err := new(int64), new(error) for { select { - case msg := <-con.writeChan: + case <-wsc.Quit: + return + case msg := <-wsc.writeChan: buf := new(bytes.Buffer) - binary.WriteJSON(msg, buf, n, err) + wire.WriteJSON(msg, buf, n, err) if *err != nil { - log.Error("Failed to marshal WSResponse to JSON", "error", err) + log.Error("Failed to marshal RPCResponse to JSON", "error", err) } else { - if err := con.wsConn.WriteMessage(websocket.TextMessage, buf.Bytes()); err != nil { + wsc.baseConn.SetWriteDeadline(time.Now().Add(time.Second * WSWriteTimeoutSeconds)) + if err := wsc.baseConn.WriteMessage(websocket.TextMessage, buf.Bytes()); err != nil { log.Warn("Failed to write response on websocket", "error", err) - con.Stop() + wsc.Stop() return } } - case <-con.quitChan: - return } } } +//---------------------------------------- + // main manager for all websocket connections // holds the event switch type WebsocketManager struct { websocket.Upgrader - evsw *events.EventSwitch + funcMap map[string]*RPCFunc + evsw *events.EventSwitch } -func NewWebsocketManager(evsw *events.EventSwitch) *WebsocketManager { +func NewWebsocketManager(funcMap map[string]*RPCFunc, evsw *events.EventSwitch) *WebsocketManager { return &WebsocketManager{ - evsw: evsw, + funcMap: funcMap, + evsw: evsw, Upgrader: websocket.Upgrader{ ReadBufferSize: 1024, WriteBufferSize: 1024, @@ -378,7 +430,8 @@ func NewWebsocketManager(evsw *events.EventSwitch) *WebsocketManager { } } -func (wm *WebsocketManager) websocketHandler(w http.ResponseWriter, r *http.Request) { +// Upgrade the request/response (via http.Hijack) and starts the WSConnection. +func (wm *WebsocketManager) WebsocketHandler(w http.ResponseWriter, r *http.Request) { wsConn, err := wm.Upgrade(w, r, nil) if err != nil { // TODO - return http error @@ -387,16 +440,16 @@ func (wm *WebsocketManager) websocketHandler(w http.ResponseWriter, r *http.Requ } // register connection - con := NewWSConnection(wsConn) - log.Info("New websocket connection", "origin", con.id) - con.Start(wm.evsw) + con := NewWSConnection(wsConn, wm.funcMap, wm.evsw) + log.Notice("New websocket connection", "origin", con.id) + con.Start() // Blocking } // rpc.websocket //----------------------------------------------------------------------------- -// returns is Response struct and error. If error is not nil, return it -func unreflectResponse(returns []reflect.Value) (interface{}, error) { +// returns is result struct and error. If error is not nil, return it +func unreflectResult(returns []reflect.Value) (interface{}, error) { errV := returns[1] if errV.Interface() != nil { return nil, fmt.Errorf("%v", errV.Interface()) diff --git a/Godeps/_workspace/src/github.com/tendermint/tendermint/rpc/server/http_params.go b/Godeps/_workspace/src/github.com/tendermint/tendermint/rpc/server/http_params.go index 1c0148e4..acf5b4c8 100644 --- a/Godeps/_workspace/src/github.com/tendermint/tendermint/rpc/server/http_params.go +++ b/Godeps/_workspace/src/github.com/tendermint/tendermint/rpc/server/http_params.go @@ -6,8 +6,6 @@ import ( "net/http" "regexp" "strconv" - - . "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/rpc/types" ) var ( @@ -24,10 +22,6 @@ var ( //RE_ID12 = regexp.MustCompile(`^[a-zA-Z0-9]{12}$`) ) -func panicRPC(err error) { - panic(NewRPCResponse(nil, err.Error())) -} - func GetParam(r *http.Request, param string) string { s := r.URL.Query().Get(param) if s == "" { diff --git a/Godeps/_workspace/src/github.com/tendermint/tendermint/rpc/server/http_server.go b/Godeps/_workspace/src/github.com/tendermint/tendermint/rpc/server/http_server.go index 8520fba9..b8d91fb3 100644 --- a/Godeps/_workspace/src/github.com/tendermint/tendermint/rpc/server/http_server.go +++ b/Godeps/_workspace/src/github.com/tendermint/tendermint/rpc/server/http_server.go @@ -11,13 +11,13 @@ import ( "time" "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/alert" - "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/binary" . "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/common" . "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/rpc/types" + "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/wire" ) func StartHTTPServer(listenAddr string, handler http.Handler) (net.Listener, error) { - log.Info(Fmt("Starting RPC HTTP server on %v", listenAddr)) + log.Notice(Fmt("Starting RPC HTTP server on %v", listenAddr)) listener, err := net.Listen("tcp", listenAddr) if err != nil { return nil, fmt.Errorf("Failed to listen to %v", listenAddr) @@ -34,7 +34,7 @@ func StartHTTPServer(listenAddr string, handler http.Handler) (net.Listener, err func WriteRPCResponse(w http.ResponseWriter, res RPCResponse) { buf, n, err := new(bytes.Buffer), new(int64), new(error) - binary.WriteJSON(res, buf, n, err) + wire.WriteJSON(res, buf, n, err) if *err != nil { log.Warn("Failed to write RPC response", "error", err) } @@ -75,7 +75,7 @@ func RecoverAndLogHandler(handler http.Handler) http.Handler { // For the rest, log.Error("Panic in RPC HTTP handler", "error", e, "stack", string(debug.Stack())) rww.WriteHeader(http.StatusInternalServerError) - WriteRPCResponse(rww, NewRPCResponse(nil, Fmt("Internal Server Error: %v", e))) + WriteRPCResponse(rww, NewRPCResponse("", nil, Fmt("Internal Server Error: %v", e))) } } @@ -84,7 +84,7 @@ func RecoverAndLogHandler(handler http.Handler) http.Handler { if rww.Status == -1 { rww.Status = 200 } - log.Debug("Served RPC HTTP response", + log.Info("Served RPC HTTP response", "method", r.Method, "url", r.URL, "status", rww.Status, "duration", durationMS, "remoteAddr", r.RemoteAddr, diff --git a/Godeps/_workspace/src/github.com/tendermint/tendermint/rpc/types/types.go b/Godeps/_workspace/src/github.com/tendermint/tendermint/rpc/types/types.go index f3c14bbd..47cea1c5 100644 --- a/Godeps/_workspace/src/github.com/tendermint/tendermint/rpc/types/types.go +++ b/Godeps/_workspace/src/github.com/tendermint/tendermint/rpc/types/types.go @@ -2,39 +2,32 @@ package rpctypes type RPCRequest struct { JSONRPC string `json:"jsonrpc"` + Id string `json:"id"` Method string `json:"method"` Params []interface{} `json:"params"` - Id int `json:"id"` } type RPCResponse struct { + JSONRPC string `json:"jsonrpc"` + Id string `json:"id"` Result interface{} `json:"result"` Error string `json:"error"` - Id string `json:"id"` - JSONRPC string `json:"jsonrpc"` } -func NewRPCResponse(res interface{}, err string) RPCResponse { +func NewRPCResponse(id string, res interface{}, err string) RPCResponse { if res == nil { res = struct{}{} } return RPCResponse{ + JSONRPC: "2.0", + Id: id, Result: res, Error: err, - Id: "", - JSONRPC: "2.0", } } -// for requests coming in -type WSRequest struct { - Type string `json:"type"` // subscribe or unsubscribe - Event string `json:"event"` -} - -// for responses going out -type WSResponse struct { +// Goes in the Result field of an RPCResponse. +type RPCEventResult struct { Event string `json:"event"` Data interface{} `json:"data"` - Error string `json:"error"` } diff --git a/Godeps/_workspace/src/github.com/tendermint/tendermint/state/block_cache.go b/Godeps/_workspace/src/github.com/tendermint/tendermint/state/block_cache.go index a388fd7d..823681b8 100644 --- a/Godeps/_workspace/src/github.com/tendermint/tendermint/state/block_cache.go +++ b/Godeps/_workspace/src/github.com/tendermint/tendermint/state/block_cache.go @@ -4,18 +4,18 @@ import ( "bytes" "sort" - ac "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/account" - "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/binary" + acm "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/account" . "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/common" dbm "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/db" "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/merkle" "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/types" + "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/wire" ) func makeStorage(db dbm.DB, root []byte) merkle.Tree { storage := merkle.NewIAVLTree( - binary.BasicCodec, - binary.BasicCodec, + wire.BasicCodec, + wire.BasicCodec, 1024, db, ) @@ -23,6 +23,7 @@ func makeStorage(db dbm.DB, root []byte) merkle.Tree { return storage } +// The blockcache helps prevent unnecessary IAVLTree updates and garbage generation. type BlockCache struct { db dbm.DB backend *State @@ -48,7 +49,7 @@ func (cache *BlockCache) State() *State { //------------------------------------- // BlockCache.account -func (cache *BlockCache) GetAccount(addr []byte) *ac.Account { +func (cache *BlockCache) GetAccount(addr []byte) *acm.Account { acc, _, removed, _ := cache.accounts[string(addr)].unpack() if removed { return nil @@ -61,24 +62,20 @@ func (cache *BlockCache) GetAccount(addr []byte) *ac.Account { } } -func (cache *BlockCache) UpdateAccount(acc *ac.Account) { +func (cache *BlockCache) UpdateAccount(acc *acm.Account) { addr := acc.Address _, storage, removed, _ := cache.accounts[string(addr)].unpack() - // SANITY CHECK if removed { - panic("UpdateAccount on a removed account") + PanicSanity("UpdateAccount on a removed account") } - // SANITY CHECK END cache.accounts[string(addr)] = accountInfo{acc, storage, false, true} } func (cache *BlockCache) RemoveAccount(addr []byte) { - // SANITY CHECK _, _, removed, _ := cache.accounts[string(addr)].unpack() if removed { - panic("RemoveAccount on a removed account") + PanicSanity("RemoveAccount on a removed account") } - // SANITY CHECK END cache.accounts[string(addr)] = accountInfo{nil, nil, true, false} } @@ -95,11 +92,9 @@ func (cache *BlockCache) GetStorage(addr Word256, key Word256) (value Word256) { // Get or load storage acc, storage, removed, dirty := cache.accounts[string(addr.Postfix(20))].unpack() - // SANITY CHECK if removed { - panic("GetStorage() on removed account") + PanicSanity("GetStorage() on removed account") } - // SANITY CHECK END if acc != nil && storage == nil { storage = makeStorage(cache.db, acc.StorageRoot) cache.accounts[string(addr.Postfix(20))] = accountInfo{acc, storage, false, dirty} @@ -119,12 +114,10 @@ func (cache *BlockCache) GetStorage(addr Word256, key Word256) (value Word256) { // NOTE: Set value to zero to removed from the trie. func (cache *BlockCache) SetStorage(addr Word256, key Word256, value Word256) { - // SANITY CHECK _, _, removed, _ := cache.accounts[string(addr.Postfix(20))].unpack() if removed { - panic("SetStorage() on a removed account") + PanicSanity("SetStorage() on a removed account") } - // SANITY CHECK END cache.storages[Tuple256{addr, key}] = storageInfo{value, true} } @@ -151,12 +144,10 @@ func (cache *BlockCache) UpdateNameRegEntry(entry *types.NameRegEntry) { } func (cache *BlockCache) RemoveNameRegEntry(name string) { - // SANITY CHECK _, removed, _ := cache.names[name].unpack() if removed { - panic("RemoveNameRegEntry on a removed entry") + PanicSanity("RemoveNameRegEntry on a removed entry") } - // SANITY CHECK END cache.names[name] = nameInfo{nil, true, false} } @@ -178,7 +169,7 @@ func (cache *BlockCache) Sync() { // Later we'll iterate over all the users and save storage + update storage root. var ( curAddr Word256 - curAcc *ac.Account + curAcc *acm.Account curAccRemoved bool curStorage merkle.Tree ) @@ -222,8 +213,7 @@ func (cache *BlockCache) Sync() { if removed { removed := cache.backend.RemoveAccount(acc.Address) if !removed { - // SOMETHING HORRIBLE HAS GONE WRONG - panic(Fmt("Could not remove account to be removed: %X", acc.Address)) + PanicCrisis(Fmt("Could not remove account to be removed: %X", acc.Address)) } } else { if acc == nil { @@ -256,8 +246,7 @@ func (cache *BlockCache) Sync() { if removed { removed := cache.backend.RemoveNameRegEntry(nameStr) if !removed { - // SOMETHING HORRIBLE HAS GONE WRONG - panic(Fmt("Could not remove namereg entry to be removed: %s", nameStr)) + PanicCrisis(Fmt("Could not remove namereg entry to be removed: %s", nameStr)) } } else { if entry == nil { @@ -274,13 +263,13 @@ func (cache *BlockCache) Sync() { //----------------------------------------------------------------------------- type accountInfo struct { - account *ac.Account + account *acm.Account storage merkle.Tree removed bool dirty bool } -func (accInfo accountInfo) unpack() (*ac.Account, merkle.Tree, bool, bool) { +func (accInfo accountInfo) unpack() (*acm.Account, merkle.Tree, bool, bool) { return accInfo.account, accInfo.storage, accInfo.removed, accInfo.dirty } diff --git a/Godeps/_workspace/src/github.com/tendermint/tendermint/state/common.go b/Godeps/_workspace/src/github.com/tendermint/tendermint/state/common.go index 0cde469a..bb0f91ed 100644 --- a/Godeps/_workspace/src/github.com/tendermint/tendermint/state/common.go +++ b/Godeps/_workspace/src/github.com/tendermint/tendermint/state/common.go @@ -1,13 +1,13 @@ package state import ( - ac "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/account" + acm "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/account" . "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/common" "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/vm" ) type AccountGetter interface { - GetAccount(addr []byte) *ac.Account + GetAccount(addr []byte) *acm.Account } type VMAccountState interface { diff --git a/Godeps/_workspace/src/github.com/tendermint/tendermint/state/execution.go b/Godeps/_workspace/src/github.com/tendermint/tendermint/state/execution.go index 8e03a142..5a1e587a 100644 --- a/Godeps/_workspace/src/github.com/tendermint/tendermint/state/execution.go +++ b/Godeps/_workspace/src/github.com/tendermint/tendermint/state/execution.go @@ -5,7 +5,7 @@ import ( "errors" "fmt" - "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/account" + acm "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/account" . "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/common" "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/events" ptypes "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/permission/types" // for GlobalPermissionAddress ... @@ -57,29 +57,28 @@ func execBlock(s *State, block *types.Block, blockPartsHeader types.PartSetHeade } // Update Validator.LastCommitHeight as necessary. - // If we panic in here, something has gone horribly wrong for i, precommit := range block.LastValidation.Precommits { if precommit == nil { continue } _, val := s.LastBondedValidators.GetByIndex(i) if val == nil { - panic(Fmt("Failed to fetch validator at index %v", i)) + PanicCrisis(Fmt("Failed to fetch validator at index %v", i)) } if _, val_ := s.BondedValidators.GetByAddress(val.Address); val_ != nil { val_.LastCommitHeight = block.Height - 1 updated := s.BondedValidators.Update(val_) if !updated { - panic("Failed to update bonded validator LastCommitHeight") + PanicCrisis("Failed to update bonded validator LastCommitHeight") } } else if _, val_ := s.UnbondingValidators.GetByAddress(val.Address); val_ != nil { val_.LastCommitHeight = block.Height - 1 updated := s.UnbondingValidators.Update(val_) if !updated { - panic("Failed to update unbonding validator LastCommitHeight") + PanicCrisis("Failed to update unbonding validator LastCommitHeight") } } else { - panic("Could not find validator") + PanicCrisis("Could not find validator") } } @@ -119,7 +118,7 @@ func execBlock(s *State, block *types.Block, blockPartsHeader types.PartSetHeade s.BondedValidators.Iterate(func(index int, val *Validator) bool { lastActivityHeight := MaxInt(val.BondHeight, val.LastCommitHeight) if lastActivityHeight+validatorTimeoutBlocks < block.Height { - log.Info("Validator timeout", "validator", val, "height", block.Height) + log.Notice("Validator timeout", "validator", val, "height", block.Height) toTimeout = append(toTimeout, val) } return false @@ -138,11 +137,11 @@ func execBlock(s *State, block *types.Block, blockPartsHeader types.PartSetHeade } // The accounts from the TxInputs must either already have -// account.PubKey.(type) != nil, (it must be known), +// acm.PubKey.(type) != nil, (it must be known), // or it must be specified in the TxInput. If redeclared, // the TxInput is modified and input.PubKey set to nil. -func getInputs(state AccountGetter, ins []*types.TxInput) (map[string]*account.Account, error) { - accounts := map[string]*account.Account{} +func getInputs(state AccountGetter, ins []*types.TxInput) (map[string]*acm.Account, error) { + accounts := map[string]*acm.Account{} for _, in := range ins { // Account shouldn't be duplicated if _, ok := accounts[string(in.Address)]; ok { @@ -161,9 +160,9 @@ func getInputs(state AccountGetter, ins []*types.TxInput) (map[string]*account.A return accounts, nil } -func getOrMakeOutputs(state AccountGetter, accounts map[string]*account.Account, outs []*types.TxOutput) (map[string]*account.Account, error) { +func getOrMakeOutputs(state AccountGetter, accounts map[string]*acm.Account, outs []*types.TxOutput) (map[string]*acm.Account, error) { if accounts == nil { - accounts = make(map[string]*account.Account) + accounts = make(map[string]*acm.Account) } // we should err if an account is being created but the inputs don't have permission @@ -182,7 +181,7 @@ func getOrMakeOutputs(state AccountGetter, accounts map[string]*account.Account, } checkedCreatePerms = true } - acc = &account.Account{ + acc = &acm.Account{ Address: out.Address, PubKey: nil, Sequence: 0, @@ -195,7 +194,7 @@ func getOrMakeOutputs(state AccountGetter, accounts map[string]*account.Account, return accounts, nil } -func checkInputPubKey(acc *account.Account, in *types.TxInput) error { +func checkInputPubKey(acc *acm.Account, in *types.TxInput) error { if acc.PubKey == nil { if in.PubKey == nil { return types.ErrTxUnknownPubKey @@ -210,14 +209,12 @@ func checkInputPubKey(acc *account.Account, in *types.TxInput) error { return nil } -func validateInputs(accounts map[string]*account.Account, signBytes []byte, ins []*types.TxInput) (total int64, err error) { +func validateInputs(accounts map[string]*acm.Account, signBytes []byte, ins []*types.TxInput) (total int64, err error) { for _, in := range ins { acc := accounts[string(in.Address)] - // SANITY CHECK if acc == nil { - panic("validateInputs() expects account in accounts") + PanicSanity("validateInputs() expects account in accounts") } - // SANITY CHECK END err = validateInput(acc, signBytes, in) if err != nil { return @@ -228,7 +225,7 @@ func validateInputs(accounts map[string]*account.Account, signBytes []byte, ins return total, nil } -func validateInput(acc *account.Account, signBytes []byte, in *types.TxInput) (err error) { +func validateInput(acc *acm.Account, signBytes []byte, in *types.TxInput) (err error) { // Check TxInput basic if err := in.ValidateBasic(); err != nil { return err @@ -263,30 +260,26 @@ func validateOutputs(outs []*types.TxOutput) (total int64, err error) { return total, nil } -func adjustByInputs(accounts map[string]*account.Account, ins []*types.TxInput) { +func adjustByInputs(accounts map[string]*acm.Account, ins []*types.TxInput) { for _, in := range ins { acc := accounts[string(in.Address)] - // SANITY CHECK if acc == nil { - panic("adjustByInputs() expects account in accounts") + PanicSanity("adjustByInputs() expects account in accounts") } if acc.Balance < in.Amount { - panic("adjustByInputs() expects sufficient funds") + PanicSanity("adjustByInputs() expects sufficient funds") } - // SANITY CHECK END acc.Balance -= in.Amount acc.Sequence += 1 } } -func adjustByOutputs(accounts map[string]*account.Account, outs []*types.TxOutput) { +func adjustByOutputs(accounts map[string]*acm.Account, outs []*types.TxOutput) { for _, out := range outs { acc := accounts[string(out.Address)] - // SANITY CHECK if acc == nil { - panic("adjustByOutputs() expects account in accounts") + PanicSanity("adjustByOutputs() expects account in accounts") } - // SANITY CHECK END acc.Balance += out.Amount } } @@ -319,7 +312,7 @@ func ExecTx(blockCache *BlockCache, tx types.Tx, runCall bool, evc events.Fireab return err } - signBytes := account.SignBytes(_s.ChainID, tx) + signBytes := acm.SignBytes(_s.ChainID, tx) inTotal, err := validateInputs(accounts, signBytes, tx.Inputs) if err != nil { return err @@ -354,19 +347,19 @@ func ExecTx(blockCache *BlockCache, tx types.Tx, runCall bool, evc events.Fireab return nil case *types.CallTx: - var inAcc, outAcc *account.Account + var inAcc, outAcc *acm.Account // Validate input inAcc = blockCache.GetAccount(tx.Input.Address) if inAcc == nil { - log.Debug(Fmt("Can't find in account %X", tx.Input.Address)) + log.Info(Fmt("Can't find in account %X", tx.Input.Address)) return types.ErrTxInvalidAddress } - createAccount := len(tx.Address) == 0 - if createAccount { + createContract := len(tx.Address) == 0 + if createContract { if !hasCreateContractPermission(blockCache, inAcc) { - return fmt.Errorf("Account %X does not have Create permission", tx.Input.Address) + return fmt.Errorf("Account %X does not have CreateContract permission", tx.Input.Address) } } else { if !hasCallPermission(blockCache, inAcc) { @@ -376,123 +369,131 @@ func ExecTx(blockCache *BlockCache, tx types.Tx, runCall bool, evc events.Fireab // pubKey should be present in either "inAcc" or "tx.Input" if err := checkInputPubKey(inAcc, tx.Input); err != nil { - log.Debug(Fmt("Can't find pubkey for %X", tx.Input.Address)) + log.Info(Fmt("Can't find pubkey for %X", tx.Input.Address)) return err } - signBytes := account.SignBytes(_s.ChainID, tx) + signBytes := acm.SignBytes(_s.ChainID, tx) err := validateInput(inAcc, signBytes, tx.Input) if err != nil { - log.Debug(Fmt("validateInput failed on %X: %v", tx.Input.Address, err)) + log.Info(Fmt("validateInput failed on %X: %v", tx.Input.Address, err)) return err } if tx.Input.Amount < tx.Fee { - log.Debug(Fmt("Sender did not send enough to cover the fee %X", tx.Input.Address)) + log.Info(Fmt("Sender did not send enough to cover the fee %X", tx.Input.Address)) return types.ErrTxInsufficientFunds } - if !createAccount { + if !createContract { // Validate output if len(tx.Address) != 20 { - log.Debug(Fmt("Destination address is not 20 bytes %X", tx.Address)) + log.Info(Fmt("Destination address is not 20 bytes %X", tx.Address)) return types.ErrTxInvalidAddress } - // this may be nil if we are still in mempool and contract was created in same block as this tx + // check if its a native contract + if vm.RegisteredNativeContract(LeftPadWord256(tx.Address)) { + return fmt.Errorf("NativeContracts can not be called using CallTx. Use a contract or the appropriate tx type (eg. PermissionsTx, NameTx)") + } + + // Output account may be nil if we are still in mempool and contract was created in same block as this tx // but that's fine, because the account will be created properly when the create tx runs in the block // and then this won't return nil. otherwise, we take their fee - // it may also be nil if its an snative (not a "real" account) outAcc = blockCache.GetAccount(tx.Address) } - log.Debug(Fmt("Out account: %v", outAcc)) + log.Info(Fmt("Out account: %v", outAcc)) // Good! value := tx.Input.Amount - tx.Fee inAcc.Sequence += 1 + inAcc.Balance -= tx.Fee + blockCache.UpdateAccount(inAcc) + // The logic in runCall MUST NOT return. if runCall { + // VM call variables var ( gas int64 = tx.GasLimit err error = nil caller *vm.Account = toVMAccount(inAcc) - callee *vm.Account = nil + callee *vm.Account = nil // initialized below code []byte = nil + ret []byte = nil txCache = NewTxCache(blockCache) params = vm.Params{ BlockHeight: int64(_s.LastBlockHeight), BlockHash: LeftPadWord256(_s.LastBlockHash), BlockTime: _s.LastBlockTime.Unix(), - GasLimit: 10000000, + GasLimit: _s.GetGasLimit(), } ) - // get or create callee - if !createAccount { - - if outAcc == nil || len(outAcc.Code) == 0 { - // check if its an snative - if _, ok := vm.RegisteredSNativeContracts[LeftPadWord256(tx.Address)]; ok { - // set the outAcc (simply a placeholder until we reach the call) - outAcc = &account.Account{Address: tx.Address} - } else { - // if you call an account that doesn't exist - // or an account with no code then we take fees (sorry pal) - // NOTE: it's fine to create a contract and call it within one - // block (nonce will prevent re-ordering of those txs) - // but to create with one account and call with another - // you have to wait a block to avoid a re-ordering attack - // that will take your fees - inAcc.Balance -= tx.Fee - blockCache.UpdateAccount(inAcc) - if outAcc == nil { - log.Debug(Fmt("Cannot find destination address %X. Deducting fee from caller", tx.Address)) - } else { - log.Debug(Fmt("Attempting to call an account (%X) with no code. Deducting fee from caller", tx.Address)) - } - return types.ErrTxInvalidAddress - } + if !createContract && (outAcc == nil || len(outAcc.Code) == 0) { + // if you call an account that doesn't exist + // or an account with no code then we take fees (sorry pal) + // NOTE: it's fine to create a contract and call it within one + // block (nonce will prevent re-ordering of those txs) + // but to create with one contract and call with another + // you have to wait a block to avoid a re-ordering attack + // that will take your fees + if outAcc == nil { + log.Info(Fmt("%X tries to call %X but it does not exist.", + inAcc.Address, tx.Address)) + } else { + log.Info(Fmt("%X tries to call %X but code is blank.", + inAcc.Address, tx.Address)) } - callee = toVMAccount(outAcc) - code = callee.Code - log.Debug(Fmt("Calling contract %X with code %X", callee.Address, callee.Code)) - } else { + err = types.ErrTxInvalidAddress + goto CALL_COMPLETE + } + + // get or create callee + if createContract { + // We already checked for permission callee = txCache.CreateAccount(caller) - log.Debug(Fmt("Created new account %X", callee.Address)) + log.Info(Fmt("Created new contract %X", callee.Address)) code = tx.Data - } - log.Debug(Fmt("Code for this contract: %X", code)) - - txCache.UpdateAccount(caller) // because we bumped nonce - txCache.UpdateAccount(callee) // so the txCache knows about the callee and the create and/or transfer takes effect - - vmach := vm.NewVM(txCache, params, caller.Address, types.TxID(_s.ChainID, tx)) - vmach.SetFireable(evc) - - // NOTE: Call() transfers the value from caller to callee iff call succeeds. - ret, err := vmach.Call(caller, callee, code, tx.Data, value, &gas) - exception := "" - if err != nil { - exception = err.Error() - // Failure. Charge the gas fee. The 'value' was otherwise not transferred. - log.Debug(Fmt("Error on execution: %v", err)) - inAcc.Balance -= tx.Fee - blockCache.UpdateAccount(inAcc) - // Throw away 'txCache' which holds incomplete updates (don't sync it). } else { - log.Debug("Successful execution") - // Success - if createAccount { - callee.Code = ret + callee = toVMAccount(outAcc) + log.Info(Fmt("Calling contract %X with code %X", callee.Address, callee.Code)) + code = callee.Code + } + log.Info(Fmt("Code for this contract: %X", code)) + + // Run VM call and sync txCache to blockCache. + { // Capture scope for goto. + // Write caller/callee to txCache. + txCache.UpdateAccount(caller) + txCache.UpdateAccount(callee) + vmach := vm.NewVM(txCache, params, caller.Address, types.TxID(_s.ChainID, tx)) + vmach.SetFireable(evc) + // NOTE: Call() transfers the value from caller to callee iff call succeeds. + ret, err = vmach.Call(caller, callee, code, tx.Data, value, &gas) + if err != nil { + // Failure. Charge the gas fee. The 'value' was otherwise not transferred. + log.Info(Fmt("Error on execution: %v", err)) + goto CALL_COMPLETE } + log.Info("Successful execution") + if createContract { + callee.Code = ret + } txCache.Sync() } + + CALL_COMPLETE: // err may or may not be nil. + // Create a receipt from the ret and whether errored. - log.Info("VM call complete", "caller", caller, "callee", callee, "return", ret, "err", err) + log.Notice("VM call complete", "caller", caller, "callee", callee, "return", ret, "err", err) // Fire Events for sender and receiver // a separate event will be fired from vm for each additional call if evc != nil { + exception := "" + if err != nil { + exception = err.Error() + } evc.FireEvent(types.EventStringAccInput(tx.Input.Address), types.EventMsgCallTx{tx, ret, exception}) evc.FireEvent(types.EventStringAccOutput(tx.Address), types.EventMsgCallTx{tx, ret, exception}) } @@ -502,7 +503,7 @@ func ExecTx(blockCache *BlockCache, tx types.Tx, runCall bool, evc events.Fireab // So mempool will skip the actual .Call(), // and only deduct from the caller's balance. inAcc.Balance -= value - if createAccount { + if createContract { inAcc.Sequence += 1 } blockCache.UpdateAccount(inAcc) @@ -511,12 +512,12 @@ func ExecTx(blockCache *BlockCache, tx types.Tx, runCall bool, evc events.Fireab return nil case *types.NameTx: - var inAcc *account.Account + var inAcc *acm.Account // Validate input inAcc = blockCache.GetAccount(tx.Input.Address) if inAcc == nil { - log.Debug(Fmt("Can't find in account %X", tx.Input.Address)) + log.Info(Fmt("Can't find in account %X", tx.Input.Address)) return types.ErrTxInvalidAddress } // check permission @@ -525,24 +526,24 @@ func ExecTx(blockCache *BlockCache, tx types.Tx, runCall bool, evc events.Fireab } // pubKey should be present in either "inAcc" or "tx.Input" if err := checkInputPubKey(inAcc, tx.Input); err != nil { - log.Debug(Fmt("Can't find pubkey for %X", tx.Input.Address)) + log.Info(Fmt("Can't find pubkey for %X", tx.Input.Address)) return err } - signBytes := account.SignBytes(_s.ChainID, tx) + signBytes := acm.SignBytes(_s.ChainID, tx) err := validateInput(inAcc, signBytes, tx.Input) if err != nil { - log.Debug(Fmt("validateInput failed on %X: %v", tx.Input.Address, err)) + log.Info(Fmt("validateInput failed on %X: %v", tx.Input.Address, err)) return err } // fee is in addition to the amount which is used to determine the TTL if tx.Input.Amount < tx.Fee { - log.Debug(Fmt("Sender did not send enough to cover the fee %X", tx.Input.Address)) + log.Info(Fmt("Sender did not send enough to cover the fee %X", tx.Input.Address)) return types.ErrTxInsufficientFunds } // validate the input strings if err := tx.ValidateStrings(); err != nil { - log.Debug(err.Error()) + log.Info(err.Error()) return types.ErrTxInvalidString } @@ -553,7 +554,7 @@ func ExecTx(blockCache *BlockCache, tx types.Tx, runCall bool, evc events.Fireab expiresIn := int(value / costPerBlock) lastBlockHeight := _s.LastBlockHeight - log.Debug("New NameTx", "value", value, "costPerBlock", costPerBlock, "expiresIn", expiresIn, "lastBlock", lastBlockHeight) + log.Info("New NameTx", "value", value, "costPerBlock", costPerBlock, "expiresIn", expiresIn, "lastBlock", lastBlockHeight) // check if the name exists entry := blockCache.GetNameRegEntry(tx.Name) @@ -564,8 +565,8 @@ func ExecTx(blockCache *BlockCache, tx types.Tx, runCall bool, evc events.Fireab if entry.Expires > lastBlockHeight { // ensure we are owner if bytes.Compare(entry.Owner, tx.Input.Address) != 0 { - log.Debug(Fmt("Sender %X is trying to update a name (%s) for which he is not owner", tx.Input.Address, tx.Name)) - return types.ErrIncorrectOwner + log.Info(Fmt("Sender %X is trying to update a name (%s) for which he is not owner", tx.Input.Address, tx.Name)) + return types.ErrTxPermissionDenied } } else { expired = true @@ -575,7 +576,7 @@ func ExecTx(blockCache *BlockCache, tx types.Tx, runCall bool, evc events.Fireab if value == 0 && len(tx.Data) == 0 { // maybe we reward you for telling us we can delete this crap // (owners if not expired, anyone if expired) - log.Debug("Removing namereg entry", "name", entry.Name) + log.Info("Removing namereg entry", "name", entry.Name) blockCache.RemoveNameRegEntry(entry.Name) } else { // update the entry by bumping the expiry @@ -586,7 +587,7 @@ func ExecTx(blockCache *BlockCache, tx types.Tx, runCall bool, evc events.Fireab } entry.Expires = lastBlockHeight + expiresIn entry.Owner = tx.Input.Address - log.Debug("An old namereg entry has expired and been reclaimed", "name", entry.Name, "expiresIn", expiresIn, "owner", entry.Owner) + log.Info("An old namereg entry has expired and been reclaimed", "name", entry.Name, "expiresIn", expiresIn, "owner", entry.Owner) } else { // since the size of the data may have changed // we use the total amount of "credit" @@ -597,7 +598,7 @@ func ExecTx(blockCache *BlockCache, tx types.Tx, runCall bool, evc events.Fireab return errors.New(Fmt("Names must be registered for at least %d blocks", types.MinNameRegistrationPeriod)) } entry.Expires = lastBlockHeight + expiresIn - log.Debug("Updated namereg entry", "name", entry.Name, "expiresIn", expiresIn, "oldCredit", oldCredit, "value", value, "credit", credit) + log.Info("Updated namereg entry", "name", entry.Name, "expiresIn", expiresIn, "oldCredit", oldCredit, "value", value, "credit", credit) } entry.Data = tx.Data blockCache.UpdateNameRegEntry(entry) @@ -613,7 +614,7 @@ func ExecTx(blockCache *BlockCache, tx types.Tx, runCall bool, evc events.Fireab Data: tx.Data, Expires: lastBlockHeight + expiresIn, } - log.Debug("Creating namereg entry", "name", entry.Name, "expiresIn", expiresIn) + log.Info("Creating namereg entry", "name", entry.Name, "expiresIn", expiresIn) blockCache.UpdateNameRegEntry(entry) } @@ -661,14 +662,11 @@ func ExecTx(blockCache *BlockCache, tx types.Tx, runCall bool, evc events.Fireab return fmt.Errorf("At least one input lacks permission to bond") } - signBytes := account.SignBytes(_s.ChainID, tx) + signBytes := acm.SignBytes(_s.ChainID, tx) inTotal, err := validateInputs(accounts, signBytes, tx.Inputs) if err != nil { return err } - if err := tx.PubKey.ValidateBasic(); err != nil { - return err - } if !tx.PubKey.VerifyBytes(signBytes, tx.Signature) { return types.ErrTxInvalidSignature } @@ -704,10 +702,10 @@ func ExecTx(blockCache *BlockCache, tx types.Tx, runCall bool, evc events.Fireab Accum: 0, }) if !added { - // SOMETHING HAS GONE HORRIBLY WRONG - panic("Failed to add validator") + PanicCrisis("Failed to add validator") } if evc != nil { + // TODO: fire for all inputs evc.FireEvent(types.EventStringBond(), tx) } return nil @@ -720,7 +718,7 @@ func ExecTx(blockCache *BlockCache, tx types.Tx, runCall bool, evc events.Fireab } // Verify the signature - signBytes := account.SignBytes(_s.ChainID, tx) + signBytes := acm.SignBytes(_s.ChainID, tx) if !val.PubKey.VerifyBytes(signBytes, tx.Signature) { return types.ErrTxInvalidSignature } @@ -745,7 +743,7 @@ func ExecTx(blockCache *BlockCache, tx types.Tx, runCall bool, evc events.Fireab } // Verify the signature - signBytes := account.SignBytes(_s.ChainID, tx) + signBytes := acm.SignBytes(_s.ChainID, tx) if !val.PubKey.VerifyBytes(signBytes, tx.Signature) { return types.ErrTxInvalidSignature } @@ -774,8 +772,8 @@ func ExecTx(blockCache *BlockCache, tx types.Tx, runCall bool, evc events.Fireab return types.ErrTxInvalidAddress } } - voteASignBytes := account.SignBytes(_s.ChainID, &tx.VoteA) - voteBSignBytes := account.SignBytes(_s.ChainID, &tx.VoteB) + voteASignBytes := acm.SignBytes(_s.ChainID, &tx.VoteA) + voteBSignBytes := acm.SignBytes(_s.ChainID, &tx.VoteB) if !accused.PubKey.VerifyBytes(voteASignBytes, tx.VoteA.Signature) || !accused.PubKey.VerifyBytes(voteBSignBytes, tx.VoteB.Signature) { return types.ErrTxInvalidSignature @@ -804,19 +802,111 @@ func ExecTx(blockCache *BlockCache, tx types.Tx, runCall bool, evc events.Fireab } return nil + case *types.PermissionsTx: + var inAcc *acm.Account + + // Validate input + inAcc = blockCache.GetAccount(tx.Input.Address) + if inAcc == nil { + log.Debug(Fmt("Can't find in account %X", tx.Input.Address)) + return types.ErrTxInvalidAddress + } + + permFlag := tx.PermArgs.PermFlag() + // check permission + if !HasPermission(blockCache, inAcc, permFlag) { + return fmt.Errorf("Account %X does not have moderator permission %s (%b)", tx.Input.Address, ptypes.PermFlagToString(permFlag), permFlag) + } + + // pubKey should be present in either "inAcc" or "tx.Input" + if err := checkInputPubKey(inAcc, tx.Input); err != nil { + log.Debug(Fmt("Can't find pubkey for %X", tx.Input.Address)) + return err + } + signBytes := acm.SignBytes(_s.ChainID, tx) + err := validateInput(inAcc, signBytes, tx.Input) + if err != nil { + log.Debug(Fmt("validateInput failed on %X: %v", tx.Input.Address, err)) + return err + } + + value := tx.Input.Amount + + log.Debug("New PermissionsTx", "function", ptypes.PermFlagToString(permFlag), "args", tx.PermArgs) + + var permAcc *acm.Account + switch args := tx.PermArgs.(type) { + case *ptypes.HasBaseArgs: + // this one doesn't make sense from txs + return fmt.Errorf("HasBase is for contracts, not humans. Just look at the blockchain") + case *ptypes.SetBaseArgs: + if permAcc = blockCache.GetAccount(args.Address); permAcc == nil { + return fmt.Errorf("Trying to update permissions for unknown account %X", args.Address) + } + err = permAcc.Permissions.Base.Set(args.Permission, args.Value) + case *ptypes.UnsetBaseArgs: + if permAcc = blockCache.GetAccount(args.Address); permAcc == nil { + return fmt.Errorf("Trying to update permissions for unknown account %X", args.Address) + } + err = permAcc.Permissions.Base.Unset(args.Permission) + case *ptypes.SetGlobalArgs: + if permAcc = blockCache.GetAccount(ptypes.GlobalPermissionsAddress); permAcc == nil { + PanicSanity("can't find global permissions account") + } + err = permAcc.Permissions.Base.Set(args.Permission, args.Value) + case *ptypes.HasRoleArgs: + return fmt.Errorf("HasRole is for contracts, not humans. Just look at the blockchain") + case *ptypes.AddRoleArgs: + if permAcc = blockCache.GetAccount(args.Address); permAcc == nil { + return fmt.Errorf("Trying to update roles for unknown account %X", args.Address) + } + if !permAcc.Permissions.AddRole(args.Role) { + return fmt.Errorf("Role (%s) already exists for account %X", args.Role, args.Address) + } + case *ptypes.RmRoleArgs: + if permAcc = blockCache.GetAccount(args.Address); permAcc == nil { + return fmt.Errorf("Trying to update roles for unknown account %X", args.Address) + } + if !permAcc.Permissions.RmRole(args.Role) { + return fmt.Errorf("Role (%s) does not exist for account %X", args.Role, args.Address) + } + default: + PanicSanity(Fmt("invalid permission function: %s", ptypes.PermFlagToString(permFlag))) + } + + // TODO: maybe we want to take funds on error and allow txs in that don't do anythingi? + if err != nil { + return err + } + + // Good! + inAcc.Sequence += 1 + inAcc.Balance -= value + blockCache.UpdateAccount(inAcc) + if permAcc != nil { + blockCache.UpdateAccount(permAcc) + } + + if evc != nil { + evc.FireEvent(types.EventStringAccInput(tx.Input.Address), tx) + evc.FireEvent(types.EventStringPermissions(ptypes.PermFlagToString(permFlag)), tx) + } + + return nil + default: - // SANITY CHECK (binary decoding should catch bad tx types - // before they get here - panic("Unknown Tx type") + // binary decoding should not let this happen + PanicSanity("Unknown Tx type") + return nil } } //--------------------------------------------------------------- // Get permission on an account or fall back to global value -func HasPermission(state AccountGetter, acc *account.Account, perm ptypes.PermFlag) bool { - if perm > ptypes.AllBasePermFlags { - panic("Checking an unknown permission in state should never happen") +func HasPermission(state AccountGetter, acc *acm.Account, perm ptypes.PermFlag) bool { + if perm > ptypes.AllPermFlags { + PanicSanity("Checking an unknown permission in state should never happen") } if acc == nil { @@ -824,23 +914,25 @@ func HasPermission(state AccountGetter, acc *account.Account, perm ptypes.PermFl // this needs to fall back to global or do some other specific things // eg. a bondAcc may be nil and so can only bond if global bonding is true } + permString := ptypes.PermFlagToString(perm) v, err := acc.Permissions.Base.Get(perm) if _, ok := err.(ptypes.ErrValueNotSet); ok { - log.Debug("Account does not have permission", "account", acc, "accPermissions", acc.Permissions, "perm", perm) if state == nil { - panic("All known global permissions should be set!") + PanicSanity("All known global permissions should be set!") } - log.Debug("Querying GlobalPermissionsAddress") + log.Info("Permission for account is not set. Querying GlobalPermissionsAddress", "perm", permString) return HasPermission(nil, state.GetAccount(ptypes.GlobalPermissionsAddress), perm) + } else if v { + log.Info("Account has permission", "address", Fmt("%X", acc.Address), "perm", permString) } else { - log.Debug("Account has permission", "account", acc, "accPermissions", acc.Permissions, "perm", perm) + log.Info("Account does not have permission", "address", Fmt("%X", acc.Address), "perm", permString) } return v } // TODO: for debug log the failed accounts -func hasSendPermission(state AccountGetter, accs map[string]*account.Account) bool { +func hasSendPermission(state AccountGetter, accs map[string]*acm.Account) bool { for _, acc := range accs { if !HasPermission(state, acc, ptypes.Send) { return false @@ -849,19 +941,19 @@ func hasSendPermission(state AccountGetter, accs map[string]*account.Account) bo return true } -func hasNamePermission(state AccountGetter, acc *account.Account) bool { +func hasNamePermission(state AccountGetter, acc *acm.Account) bool { return HasPermission(state, acc, ptypes.Name) } -func hasCallPermission(state AccountGetter, acc *account.Account) bool { +func hasCallPermission(state AccountGetter, acc *acm.Account) bool { return HasPermission(state, acc, ptypes.Call) } -func hasCreateContractPermission(state AccountGetter, acc *account.Account) bool { +func hasCreateContractPermission(state AccountGetter, acc *acm.Account) bool { return HasPermission(state, acc, ptypes.CreateContract) } -func hasCreateAccountPermission(state AccountGetter, accs map[string]*account.Account) bool { +func hasCreateAccountPermission(state AccountGetter, accs map[string]*acm.Account) bool { for _, acc := range accs { if !HasPermission(state, acc, ptypes.CreateAccount) { return false @@ -870,11 +962,11 @@ func hasCreateAccountPermission(state AccountGetter, accs map[string]*account.Ac return true } -func hasBondPermission(state AccountGetter, acc *account.Account) bool { +func hasBondPermission(state AccountGetter, acc *acm.Account) bool { return HasPermission(state, acc, ptypes.Bond) } -func hasBondOrSendPermission(state AccountGetter, accs map[string]*account.Account) bool { +func hasBondOrSendPermission(state AccountGetter, accs map[string]*acm.Account) bool { for _, acc := range accs { if !HasPermission(state, acc, ptypes.Bond) { if !HasPermission(state, acc, ptypes.Send) { diff --git a/Godeps/_workspace/src/github.com/tendermint/tendermint/state/genesis.go b/Godeps/_workspace/src/github.com/tendermint/tendermint/state/genesis.go index 0a29f961..e150754c 100644 --- a/Godeps/_workspace/src/github.com/tendermint/tendermint/state/genesis.go +++ b/Godeps/_workspace/src/github.com/tendermint/tendermint/state/genesis.go @@ -5,13 +5,13 @@ import ( "os" "time" - "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/account" - "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/binary" + acm "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/account" . "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/common" dbm "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/db" "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/merkle" ptypes "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/permission/types" "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/types" + "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/wire" ) //------------------------------------------------------------ @@ -35,10 +35,10 @@ type GenesisAccount struct { } type GenesisValidator struct { - PubKey account.PubKeyEd25519 `json:"pub_key"` - Amount int64 `json:"amount"` - Name string `json:"name"` - UnbondTo []BasicAccount `json:"unbond_to"` + PubKey acm.PubKeyEd25519 `json:"pub_key"` + Amount int64 `json:"amount"` + Name string `json:"name"` + UnbondTo []BasicAccount `json:"unbond_to"` } type GenesisParams struct { @@ -58,7 +58,7 @@ type GenesisDoc struct { func GenesisDocFromJSON(jsonBlob []byte) (genState *GenesisDoc) { var err error - binary.ReadJSONPtr(&genState, jsonBlob, &err) + wire.ReadJSONPtr(&genState, jsonBlob, &err) if err != nil { log.Error(Fmt("Couldn't read GenesisDoc: %v", err)) os.Exit(1) @@ -86,13 +86,13 @@ func MakeGenesisState(db dbm.DB, genDoc *GenesisDoc) *State { } // Make accounts state tree - accounts := merkle.NewIAVLTree(binary.BasicCodec, account.AccountCodec, defaultAccountsCacheCapacity, db) + accounts := merkle.NewIAVLTree(wire.BasicCodec, acm.AccountCodec, defaultAccountsCacheCapacity, db) for _, genAcc := range genDoc.Accounts { perm := ptypes.ZeroAccountPermissions if genAcc.Permissions != nil { perm = *genAcc.Permissions } - acc := &account.Account{ + acc := &acm.Account{ Address: genAcc.Address, PubKey: nil, Sequence: 0, @@ -112,7 +112,7 @@ func MakeGenesisState(db dbm.DB, genDoc *GenesisDoc) *State { globalPerms.Base.SetBit = ptypes.AllPermFlags } - permsAcc := &account.Account{ + permsAcc := &acm.Account{ Address: ptypes.GlobalPermissionsAddress, PubKey: nil, Sequence: 0, @@ -122,7 +122,7 @@ func MakeGenesisState(db dbm.DB, genDoc *GenesisDoc) *State { accounts.Set(permsAcc.Address, permsAcc) // Make validatorInfos state tree && validators slice - validatorInfos := merkle.NewIAVLTree(binary.BasicCodec, ValidatorInfoCodec, 0, db) + validatorInfos := merkle.NewIAVLTree(wire.BasicCodec, ValidatorInfoCodec, 0, db) validators := make([]*Validator, len(genDoc.Validators)) for i, val := range genDoc.Validators { pubKey := val.PubKey @@ -153,7 +153,7 @@ func MakeGenesisState(db dbm.DB, genDoc *GenesisDoc) *State { } // Make namereg tree - nameReg := merkle.NewIAVLTree(binary.BasicCodec, NameRegCodec, 0, db) + nameReg := merkle.NewIAVLTree(wire.BasicCodec, NameRegCodec, 0, db) // TODO: add names, contracts to genesis.json // IAVLTrees must be persisted before copy operations. diff --git a/Godeps/_workspace/src/github.com/tendermint/tendermint/state/permissions_test.go b/Godeps/_workspace/src/github.com/tendermint/tendermint/state/permissions_test.go index 61887f33..dc51d8bd 100644 --- a/Godeps/_workspace/src/github.com/tendermint/tendermint/state/permissions_test.go +++ b/Godeps/_workspace/src/github.com/tendermint/tendermint/state/permissions_test.go @@ -7,13 +7,12 @@ import ( "testing" "time" - "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/account" + acm "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/account" . "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/common" dbm "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/db" "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/events" ptypes "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/permission/types" "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/types" - "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/vm" ) /* @@ -81,11 +80,11 @@ x - roles: has, add, rm var user = makeUsers(10) var chainID = "testchain" -func makeUsers(n int) []*account.PrivAccount { - accounts := []*account.PrivAccount{} +func makeUsers(n int) []*acm.PrivAccount { + accounts := []*acm.PrivAccount{} for i := 0; i < n; i++ { secret := []byte("mysecret" + strconv.Itoa(i)) - user := account.GenPrivAccountFromSecret(secret) + user := acm.GenPrivAccountFromSecret(secret) accounts = append(accounts, user) } return accounts @@ -115,7 +114,7 @@ func newBaseGenDoc(globalPerm, accountPerm ptypes.AccountPermissions) GenesisDoc Accounts: genAccounts, Validators: []GenesisValidator{ GenesisValidator{ - PubKey: user[0].PubKey.(account.PubKeyEd25519), + PubKey: user[0].PubKey.(acm.PubKeyEd25519), Amount: 10, UnbondTo: []BasicAccount{ BasicAccount{ @@ -344,11 +343,11 @@ func TestCallPermission(t *testing.T) { //------------------------------ // call to simple contract - fmt.Println("##### SIMPLE CONTRACT") + fmt.Println("\n##### SIMPLE CONTRACT") // create simple contract simpleContractAddr := NewContractAddress(user[0].Address, 100) - simpleAcc := &account.Account{ + simpleAcc := &acm.Account{ Address: simpleContractAddr, Balance: 0, Code: []byte{0x60}, @@ -367,14 +366,14 @@ func TestCallPermission(t *testing.T) { //---------------------------------------------------------- // call to contract that calls simple contract - without perm - fmt.Println("##### CALL TO SIMPLE CONTRACT (FAIL)") + fmt.Println("\n##### CALL TO SIMPLE CONTRACT (FAIL)") // create contract that calls the simple contract contractCode := callContractCode(simpleContractAddr) caller1ContractAddr := NewContractAddress(user[0].Address, 101) - caller1Acc := &account.Account{ + caller1Acc := &acm.Account{ Address: caller1ContractAddr, - Balance: 0, + Balance: 10000, Code: contractCode, Sequence: 0, StorageRoot: Zero256.Bytes(), @@ -386,15 +385,15 @@ func TestCallPermission(t *testing.T) { tx, _ = types.NewCallTx(blockCache, user[0].PubKey, caller1ContractAddr, nil, 100, 10000, 100) tx.Sign(chainID, user[0]) - // we need to subscribe to the Receive event to detect the exception - _, exception := execTxWaitEvent(t, blockCache, tx, types.EventStringAccReceive(caller1ContractAddr)) // + // we need to subscribe to the Call event to detect the exception + _, exception := execTxWaitEvent(t, blockCache, tx, types.EventStringAccCall(caller1ContractAddr)) // if exception == "" { t.Fatal("Expected exception") } //---------------------------------------------------------- // call to contract that calls simple contract - with perm - fmt.Println("##### CALL TO SIMPLE CONTRACT (PASS)") + fmt.Println("\n##### CALL TO SIMPLE CONTRACT (PASS)") // A single input, having the permission, and the contract has permission caller1Acc.Permissions.Base.Set(ptypes.Call, true) @@ -402,8 +401,8 @@ func TestCallPermission(t *testing.T) { tx, _ = types.NewCallTx(blockCache, user[0].PubKey, caller1ContractAddr, nil, 100, 10000, 100) tx.Sign(chainID, user[0]) - // we need to subscribe to the Receive event to detect the exception - _, exception = execTxWaitEvent(t, blockCache, tx, types.EventStringAccReceive(caller1ContractAddr)) // + // we need to subscribe to the Call event to detect the exception + _, exception = execTxWaitEvent(t, blockCache, tx, types.EventStringAccCall(caller1ContractAddr)) // if exception != "" { t.Fatal("Unexpected exception:", exception) } @@ -412,11 +411,11 @@ func TestCallPermission(t *testing.T) { // call to contract that calls contract that calls simple contract - without perm // caller1Contract calls simpleContract. caller2Contract calls caller1Contract. // caller1Contract does not have call perms, but caller2Contract does. - fmt.Println("##### CALL TO CONTRACT CALLING SIMPLE CONTRACT (FAIL)") + fmt.Println("\n##### CALL TO CONTRACT CALLING SIMPLE CONTRACT (FAIL)") contractCode2 := callContractCode(caller1ContractAddr) caller2ContractAddr := NewContractAddress(user[0].Address, 102) - caller2Acc := &account.Account{ + caller2Acc := &acm.Account{ Address: caller2ContractAddr, Balance: 1000, Code: contractCode2, @@ -432,8 +431,8 @@ func TestCallPermission(t *testing.T) { tx, _ = types.NewCallTx(blockCache, user[0].PubKey, caller2ContractAddr, nil, 100, 10000, 100) tx.Sign(chainID, user[0]) - // we need to subscribe to the Receive event to detect the exception - _, exception = execTxWaitEvent(t, blockCache, tx, types.EventStringAccReceive(caller1ContractAddr)) // + // we need to subscribe to the Call event to detect the exception + _, exception = execTxWaitEvent(t, blockCache, tx, types.EventStringAccCall(caller1ContractAddr)) // if exception == "" { t.Fatal("Expected exception") } @@ -442,7 +441,7 @@ func TestCallPermission(t *testing.T) { // call to contract that calls contract that calls simple contract - without perm // caller1Contract calls simpleContract. caller2Contract calls caller1Contract. // both caller1 and caller2 have permission - fmt.Println("##### CALL TO CONTRACT CALLING SIMPLE CONTRACT (PASS)") + fmt.Println("\n##### CALL TO CONTRACT CALLING SIMPLE CONTRACT (PASS)") caller1Acc.Permissions.Base.Set(ptypes.Call, true) blockCache.UpdateAccount(caller1Acc) @@ -450,8 +449,8 @@ func TestCallPermission(t *testing.T) { tx, _ = types.NewCallTx(blockCache, user[0].PubKey, caller2ContractAddr, nil, 100, 10000, 100) tx.Sign(chainID, user[0]) - // we need to subscribe to the Receive event to detect the exception - _, exception = execTxWaitEvent(t, blockCache, tx, types.EventStringAccReceive(caller1ContractAddr)) // + // we need to subscribe to the Call event to detect the exception + _, exception = execTxWaitEvent(t, blockCache, tx, types.EventStringAccCall(caller1ContractAddr)) // if exception != "" { t.Fatal("Unexpected exception", exception) } @@ -467,7 +466,7 @@ func TestCreatePermission(t *testing.T) { //------------------------------ // create a simple contract - fmt.Println("##### CREATE SIMPLE CONTRACT") + fmt.Println("\n##### CREATE SIMPLE CONTRACT") contractCode := []byte{0x60} createCode := wrapContractForCreate(contractCode) @@ -490,7 +489,7 @@ func TestCreatePermission(t *testing.T) { //------------------------------ // create contract that uses the CREATE op - fmt.Println("##### CREATE FACTORY") + fmt.Println("\n##### CREATE FACTORY") contractCode = []byte{0x60} createCode = wrapContractForCreate(contractCode) @@ -515,20 +514,20 @@ func TestCreatePermission(t *testing.T) { //------------------------------ // call the contract (should FAIL) - fmt.Println("###### CALL THE FACTORY (FAIL)") + fmt.Println("\n###### CALL THE FACTORY (FAIL)") // A single input, having the permission, should succeed tx, _ = types.NewCallTx(blockCache, user[0].PubKey, contractAddr, createCode, 100, 100, 100) tx.Sign(chainID, user[0]) - // we need to subscribe to the Receive event to detect the exception - _, exception := execTxWaitEvent(t, blockCache, tx, types.EventStringAccReceive(contractAddr)) // + // we need to subscribe to the Call event to detect the exception + _, exception := execTxWaitEvent(t, blockCache, tx, types.EventStringAccCall(contractAddr)) // if exception == "" { t.Fatal("expected exception") } //------------------------------ // call the contract (should PASS) - fmt.Println("###### CALL THE FACTORY (PASS)") + fmt.Println("\n###### CALL THE FACTORY (PASS)") contractAcc.Permissions.Base.Set(ptypes.CreateContract, true) blockCache.UpdateAccount(contractAcc) @@ -536,19 +535,19 @@ func TestCreatePermission(t *testing.T) { // A single input, having the permission, should succeed tx, _ = types.NewCallTx(blockCache, user[0].PubKey, contractAddr, createCode, 100, 100, 100) tx.Sign(chainID, user[0]) - // we need to subscribe to the Receive event to detect the exception - _, exception = execTxWaitEvent(t, blockCache, tx, types.EventStringAccReceive(contractAddr)) // + // we need to subscribe to the Call event to detect the exception + _, exception = execTxWaitEvent(t, blockCache, tx, types.EventStringAccCall(contractAddr)) // if exception != "" { t.Fatal("unexpected exception", exception) } //-------------------------------- - fmt.Println("##### CALL to empty address") + fmt.Println("\n##### CALL to empty address") zeroAddr := LeftPadBytes([]byte{}, 20) code := callContractCode(zeroAddr) contractAddr = NewContractAddress(user[0].Address, 110) - contractAcc = &account.Account{ + contractAcc = &acm.Account{ Address: contractAddr, Balance: 1000, Code: code, @@ -563,8 +562,8 @@ func TestCreatePermission(t *testing.T) { // this should call the 0 address but not create ... tx, _ = types.NewCallTx(blockCache, user[0].PubKey, contractAddr, createCode, 100, 10000, 100) tx.Sign(chainID, user[0]) - // we need to subscribe to the Receive event to detect the exception - _, exception = execTxWaitEvent(t, blockCache, tx, types.EventStringAccReceive(zeroAddr)) // + // we need to subscribe to the Call event to detect the exception + _, exception = execTxWaitEvent(t, blockCache, tx, types.EventStringAccCall(zeroAddr)) // if exception != "" { t.Fatal("unexpected exception", exception) } @@ -579,7 +578,7 @@ func TestBondPermission(t *testing.T) { genDoc := newBaseGenDoc(PermsAllFalse, PermsAllFalse) st := MakeGenesisState(stateDB, &genDoc) blockCache := NewBlockCache(st) - var bondAcc *account.Account + var bondAcc *acm.Account //------------------------------ // one bonder without permission should fail @@ -800,7 +799,7 @@ func TestCreateAccountPermission(t *testing.T) { // create contract that calls the simple contract contractCode := callContractCode(user[9].Address) caller1ContractAddr := NewContractAddress(user[4].Address, 101) - caller1Acc := &account.Account{ + caller1Acc := &acm.Account{ Address: caller1ContractAddr, Balance: 0, Code: contractCode, @@ -814,8 +813,8 @@ func TestCreateAccountPermission(t *testing.T) { txCall, _ := types.NewCallTx(blockCache, user[0].PubKey, caller1ContractAddr, nil, 100, 10000, 100) txCall.Sign(chainID, user[0]) - // we need to subscribe to the Receive event to detect the exception - _, exception := execTxWaitEvent(t, blockCache, txCall, types.EventStringAccReceive(caller1ContractAddr)) // + // we need to subscribe to the Call event to detect the exception + _, exception := execTxWaitEvent(t, blockCache, txCall, types.EventStringAccCall(caller1ContractAddr)) // if exception == "" { t.Fatal("Expected exception") } @@ -829,14 +828,17 @@ func TestCreateAccountPermission(t *testing.T) { txCall, _ = types.NewCallTx(blockCache, user[0].PubKey, caller1ContractAddr, nil, 100, 10000, 100) txCall.Sign(chainID, user[0]) - // we need to subscribe to the Receive event to detect the exception - _, exception = execTxWaitEvent(t, blockCache, txCall, types.EventStringAccReceive(caller1ContractAddr)) // + // we need to subscribe to the Call event to detect the exception + _, exception = execTxWaitEvent(t, blockCache, txCall, types.EventStringAccCall(caller1ContractAddr)) // if exception != "" { t.Fatal("Unexpected exception", exception) } } +// holla at my boy +var DougAddress = append([]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, []byte("THISISDOUG")...) + func TestSNativeCALL(t *testing.T) { stateDB := dbm.GetDB("state") genDoc := newBaseGenDoc(PermsAllFalse, PermsAllFalse) @@ -851,8 +853,8 @@ func TestSNativeCALL(t *testing.T) { // Test CALL to SNative contracts // make the main contract once - doug := &account.Account{ - Address: ptypes.DougAddress, + doug := &acm.Account{ + Address: DougAddress, Balance: 0, Code: nil, Sequence: 0, @@ -860,11 +862,12 @@ func TestSNativeCALL(t *testing.T) { Permissions: ptypes.ZeroAccountPermissions, } doug.Permissions.Base.Set(ptypes.Call, true) + //doug.Permissions.Base.Set(ptypes.HasBase, true) blockCache.UpdateAccount(doug) - fmt.Println("#### hasBasePerm") - // hasBasePerm - snativeAddress, data := snativePermTestInput("hasBasePerm", user[3], ptypes.Bond, false) + fmt.Println("\n#### HasBase") + // HasBase + snativeAddress, data := snativePermTestInputCALL("has_base", user[3], ptypes.Bond, false) testSNativeCALLExpectFail(t, blockCache, doug, snativeAddress, data) testSNativeCALLExpectPass(t, blockCache, doug, snativeAddress, data, func(ret []byte) error { // return value should be true or false as a 32 byte array... @@ -874,12 +877,12 @@ func TestSNativeCALL(t *testing.T) { return nil }) - fmt.Println("#### setBasePerm") - // setBasePerm - snativeAddress, data = snativePermTestInput("setBasePerm", user[3], ptypes.Bond, false) + fmt.Println("\n#### SetBase") + // SetBase + snativeAddress, data = snativePermTestInputCALL("set_base", user[3], ptypes.Bond, false) testSNativeCALLExpectFail(t, blockCache, doug, snativeAddress, data) testSNativeCALLExpectPass(t, blockCache, doug, snativeAddress, data, func(ret []byte) error { return nil }) - snativeAddress, data = snativePermTestInput("hasBasePerm", user[3], ptypes.Bond, false) + snativeAddress, data = snativePermTestInputCALL("has_base", user[3], ptypes.Bond, false) testSNativeCALLExpectPass(t, blockCache, doug, snativeAddress, data, func(ret []byte) error { // return value should be true or false as a 32 byte array... if !IsZeros(ret) { @@ -887,9 +890,9 @@ func TestSNativeCALL(t *testing.T) { } return nil }) - snativeAddress, data = snativePermTestInput("setBasePerm", user[3], ptypes.CreateContract, true) + snativeAddress, data = snativePermTestInputCALL("set_base", user[3], ptypes.CreateContract, true) testSNativeCALLExpectPass(t, blockCache, doug, snativeAddress, data, func(ret []byte) error { return nil }) - snativeAddress, data = snativePermTestInput("hasBasePerm", user[3], ptypes.CreateContract, false) + snativeAddress, data = snativePermTestInputCALL("has_base", user[3], ptypes.CreateContract, false) testSNativeCALLExpectPass(t, blockCache, doug, snativeAddress, data, func(ret []byte) error { // return value should be true or false as a 32 byte array... if !IsZeros(ret[:31]) || ret[31] != byte(1) { @@ -898,12 +901,12 @@ func TestSNativeCALL(t *testing.T) { return nil }) - fmt.Println("#### unsetBasePerm") - // unsetBasePerm - snativeAddress, data = snativePermTestInput("unsetBasePerm", user[3], ptypes.CreateContract, false) + fmt.Println("\n#### UnsetBase") + // UnsetBase + snativeAddress, data = snativePermTestInputCALL("unset_base", user[3], ptypes.CreateContract, false) testSNativeCALLExpectFail(t, blockCache, doug, snativeAddress, data) testSNativeCALLExpectPass(t, blockCache, doug, snativeAddress, data, func(ret []byte) error { return nil }) - snativeAddress, data = snativePermTestInput("hasBasePerm", user[3], ptypes.CreateContract, false) + snativeAddress, data = snativePermTestInputCALL("has_base", user[3], ptypes.CreateContract, false) testSNativeCALLExpectPass(t, blockCache, doug, snativeAddress, data, func(ret []byte) error { if !IsZeros(ret) { return fmt.Errorf("Expected 0. Got %X", ret) @@ -911,12 +914,12 @@ func TestSNativeCALL(t *testing.T) { return nil }) - fmt.Println("#### setGlobalPerm") - // setGlobalPerm - snativeAddress, data = snativePermTestInput("setGlobalPerm", user[3], ptypes.CreateContract, true) + fmt.Println("\n#### SetGlobal") + // SetGlobalPerm + snativeAddress, data = snativePermTestInputCALL("set_global", user[3], ptypes.CreateContract, true) testSNativeCALLExpectFail(t, blockCache, doug, snativeAddress, data) testSNativeCALLExpectPass(t, blockCache, doug, snativeAddress, data, func(ret []byte) error { return nil }) - snativeAddress, data = snativePermTestInput("hasBasePerm", user[3], ptypes.CreateContract, false) + snativeAddress, data = snativePermTestInputCALL("has_base", user[3], ptypes.CreateContract, false) testSNativeCALLExpectPass(t, blockCache, doug, snativeAddress, data, func(ret []byte) error { // return value should be true or false as a 32 byte array... if !IsZeros(ret[:31]) || ret[31] != byte(1) { @@ -925,12 +928,9 @@ func TestSNativeCALL(t *testing.T) { return nil }) - // clearBasePerm - // TODO - - fmt.Println("#### hasRole") - // hasRole - snativeAddress, data = snativeRoleTestInput("hasRole", user[3], "bumble") + fmt.Println("\n#### HasRole") + // HasRole + snativeAddress, data = snativeRoleTestInputCALL("has_role", user[3], "bumble") testSNativeCALLExpectFail(t, blockCache, doug, snativeAddress, data) testSNativeCALLExpectPass(t, blockCache, doug, snativeAddress, data, func(ret []byte) error { if !IsZeros(ret[:31]) || ret[31] != byte(1) { @@ -939,19 +939,19 @@ func TestSNativeCALL(t *testing.T) { return nil }) - fmt.Println("#### addRole") - // addRole - snativeAddress, data = snativeRoleTestInput("hasRole", user[3], "chuck") + fmt.Println("\n#### AddRole") + // AddRole + snativeAddress, data = snativeRoleTestInputCALL("has_role", user[3], "chuck") testSNativeCALLExpectPass(t, blockCache, doug, snativeAddress, data, func(ret []byte) error { if !IsZeros(ret) { return fmt.Errorf("Expected 0. Got %X", ret) } return nil }) - snativeAddress, data = snativeRoleTestInput("addRole", user[3], "chuck") + snativeAddress, data = snativeRoleTestInputCALL("add_role", user[3], "chuck") testSNativeCALLExpectFail(t, blockCache, doug, snativeAddress, data) testSNativeCALLExpectPass(t, blockCache, doug, snativeAddress, data, func(ret []byte) error { return nil }) - snativeAddress, data = snativeRoleTestInput("hasRole", user[3], "chuck") + snativeAddress, data = snativeRoleTestInputCALL("has_role", user[3], "chuck") testSNativeCALLExpectPass(t, blockCache, doug, snativeAddress, data, func(ret []byte) error { if !IsZeros(ret[:31]) || ret[31] != byte(1) { return fmt.Errorf("Expected 1. Got %X", ret) @@ -959,12 +959,12 @@ func TestSNativeCALL(t *testing.T) { return nil }) - fmt.Println("#### rmRole") - // rmRole - snativeAddress, data = snativeRoleTestInput("rmRole", user[3], "chuck") + fmt.Println("\n#### RmRole") + // RmRole + snativeAddress, data = snativeRoleTestInputCALL("rm_role", user[3], "chuck") testSNativeCALLExpectFail(t, blockCache, doug, snativeAddress, data) testSNativeCALLExpectPass(t, blockCache, doug, snativeAddress, data, func(ret []byte) error { return nil }) - snativeAddress, data = snativeRoleTestInput("hasRole", user[3], "chuck") + snativeAddress, data = snativeRoleTestInputCALL("has_role", user[3], "chuck") testSNativeCALLExpectPass(t, blockCache, doug, snativeAddress, data, func(ret []byte) error { if !IsZeros(ret) { return fmt.Errorf("Expected 0. Got %X", ret) @@ -973,7 +973,7 @@ func TestSNativeCALL(t *testing.T) { }) } -func TestSNativeCallTx(t *testing.T) { +func TestSNativeTx(t *testing.T) { stateDB := dbm.GetDB("state") genDoc := newBaseGenDoc(PermsAllFalse, PermsAllFalse) genDoc.Accounts[0].Permissions.Base.Set(ptypes.Call, true) // give the 0 account permission @@ -984,127 +984,74 @@ func TestSNativeCallTx(t *testing.T) { blockCache := NewBlockCache(st) //---------------------------------------------------------- - // Test CallTx to SNative contracts - var doug *account.Account = nil - - fmt.Println("#### hasBasePerm") - // hasBasePerm - snativeAddress, data := snativePermTestInput("hasBasePerm", user[3], ptypes.Bond, false) - testSNativeCALLExpectFail(t, blockCache, doug, snativeAddress, data) - testSNativeCALLExpectPass(t, blockCache, doug, snativeAddress, data, func(ret []byte) error { - // return value should be true or false as a 32 byte array... - if !IsZeros(ret[:31]) || ret[31] != byte(1) { - return fmt.Errorf("Expected 1. Got %X", ret) - } - return nil - }) - - fmt.Println("#### setBasePerm") - // setBasePerm - snativeAddress, data = snativePermTestInput("setBasePerm", user[3], ptypes.Bond, false) - testSNativeCALLExpectFail(t, blockCache, doug, snativeAddress, data) - testSNativeCALLExpectPass(t, blockCache, doug, snativeAddress, data, func(ret []byte) error { return nil }) - snativeAddress, data = snativePermTestInput("hasBasePerm", user[3], ptypes.Bond, false) - testSNativeCALLExpectPass(t, blockCache, doug, snativeAddress, data, func(ret []byte) error { - // return value should be true or false as a 32 byte array... - if !IsZeros(ret) { - return fmt.Errorf("Expected 0. Got %X", ret) - } - return nil - }) - snativeAddress, data = snativePermTestInput("setBasePerm", user[3], ptypes.CreateContract, true) - testSNativeCALLExpectPass(t, blockCache, doug, snativeAddress, data, func(ret []byte) error { return nil }) - snativeAddress, data = snativePermTestInput("hasBasePerm", user[3], ptypes.CreateContract, false) - testSNativeCALLExpectPass(t, blockCache, doug, snativeAddress, data, func(ret []byte) error { - // return value should be true or false as a 32 byte array... - if !IsZeros(ret[:31]) || ret[31] != byte(1) { - return fmt.Errorf("Expected 1. Got %X", ret) - } - return nil - }) - - fmt.Println("#### unsetBasePerm") - // unsetBasePerm - snativeAddress, data = snativePermTestInput("unsetBasePerm", user[3], ptypes.CreateContract, false) - testSNativeCALLExpectFail(t, blockCache, doug, snativeAddress, data) - testSNativeCALLExpectPass(t, blockCache, doug, snativeAddress, data, func(ret []byte) error { return nil }) - snativeAddress, data = snativePermTestInput("hasBasePerm", user[3], ptypes.CreateContract, false) - testSNativeCALLExpectPass(t, blockCache, doug, snativeAddress, data, func(ret []byte) error { - if !IsZeros(ret) { - return fmt.Errorf("Expected 0. Got %X", ret) - } - return nil - }) - - fmt.Println("#### setGlobalPerm") - // setGlobalPerm - snativeAddress, data = snativePermTestInput("setGlobalPerm", user[3], ptypes.CreateContract, true) - testSNativeCALLExpectFail(t, blockCache, doug, snativeAddress, data) - testSNativeCALLExpectPass(t, blockCache, doug, snativeAddress, data, func(ret []byte) error { return nil }) - snativeAddress, data = snativePermTestInput("hasBasePerm", user[3], ptypes.CreateContract, false) - testSNativeCALLExpectPass(t, blockCache, doug, snativeAddress, data, func(ret []byte) error { - // return value should be true or false as a 32 byte array... - if !IsZeros(ret[:31]) || ret[31] != byte(1) { - return fmt.Errorf("Expected 1. Got %X", ret) - } - return nil - }) - - // clearBasePerm - // TODO + // Test SNativeTx - fmt.Println("#### hasRole") - // hasRole - snativeAddress, data = snativeRoleTestInput("hasRole", user[3], "bumble") - testSNativeCALLExpectFail(t, blockCache, doug, snativeAddress, data) - testSNativeCALLExpectPass(t, blockCache, doug, snativeAddress, data, func(ret []byte) error { - if !IsZeros(ret[:31]) || ret[31] != byte(1) { - return fmt.Errorf("Expected 1. Got %X", ret) - } - return nil - }) - - fmt.Println("#### addRole") - // addRole - snativeAddress, data = snativeRoleTestInput("hasRole", user[3], "chuck") - testSNativeCALLExpectPass(t, blockCache, doug, snativeAddress, data, func(ret []byte) error { - if !IsZeros(ret) { - return fmt.Errorf("Expected 0. Got %X", ret) - } - return nil - }) - snativeAddress, data = snativeRoleTestInput("addRole", user[3], "chuck") - testSNativeCALLExpectFail(t, blockCache, doug, snativeAddress, data) - testSNativeCALLExpectPass(t, blockCache, doug, snativeAddress, data, func(ret []byte) error { return nil }) - snativeAddress, data = snativeRoleTestInput("hasRole", user[3], "chuck") - testSNativeCALLExpectPass(t, blockCache, doug, snativeAddress, data, func(ret []byte) error { - if !IsZeros(ret[:31]) || ret[31] != byte(1) { - return fmt.Errorf("Expected 1. Got %X", ret) - } - return nil - }) - - fmt.Println("#### rmRole") - // rmRole - snativeAddress, data = snativeRoleTestInput("rmRole", user[3], "chuck") - testSNativeCALLExpectFail(t, blockCache, doug, snativeAddress, data) - testSNativeCALLExpectPass(t, blockCache, doug, snativeAddress, data, func(ret []byte) error { return nil }) - snativeAddress, data = snativeRoleTestInput("hasRole", user[3], "chuck") - testSNativeCALLExpectPass(t, blockCache, doug, snativeAddress, data, func(ret []byte) error { - if !IsZeros(ret) { - return fmt.Errorf("Expected 0. Got %X", ret) - } - return nil - }) + fmt.Println("\n#### SetBase") + // SetBase + snativeArgs := snativePermTestInputTx("set_base", user[3], ptypes.Bond, false) + testSNativeTxExpectFail(t, blockCache, snativeArgs) + testSNativeTxExpectPass(t, blockCache, ptypes.SetBase, snativeArgs) + acc := blockCache.GetAccount(user[3].Address) + if v, _ := acc.Permissions.Base.Get(ptypes.Bond); v { + t.Fatal("expected permission to be set false") + } + snativeArgs = snativePermTestInputTx("set_base", user[3], ptypes.CreateContract, true) + testSNativeTxExpectPass(t, blockCache, ptypes.SetBase, snativeArgs) + acc = blockCache.GetAccount(user[3].Address) + if v, _ := acc.Permissions.Base.Get(ptypes.CreateContract); !v { + t.Fatal("expected permission to be set true") + } + + fmt.Println("\n#### UnsetBase") + // UnsetBase + snativeArgs = snativePermTestInputTx("unset_base", user[3], ptypes.CreateContract, false) + testSNativeTxExpectFail(t, blockCache, snativeArgs) + testSNativeTxExpectPass(t, blockCache, ptypes.UnsetBase, snativeArgs) + acc = blockCache.GetAccount(user[3].Address) + if v, _ := acc.Permissions.Base.Get(ptypes.CreateContract); v { + t.Fatal("expected permission to be set false") + } + + fmt.Println("\n#### SetGlobal") + // SetGlobalPerm + snativeArgs = snativePermTestInputTx("set_global", user[3], ptypes.CreateContract, true) + testSNativeTxExpectFail(t, blockCache, snativeArgs) + testSNativeTxExpectPass(t, blockCache, ptypes.SetGlobal, snativeArgs) + acc = blockCache.GetAccount(ptypes.GlobalPermissionsAddress) + if v, _ := acc.Permissions.Base.Get(ptypes.CreateContract); !v { + t.Fatal("expected permission to be set true") + } + + fmt.Println("\n#### AddRole") + // AddRole + snativeArgs = snativeRoleTestInputTx("add_role", user[3], "chuck") + testSNativeTxExpectFail(t, blockCache, snativeArgs) + testSNativeTxExpectPass(t, blockCache, ptypes.AddRole, snativeArgs) + acc = blockCache.GetAccount(user[3].Address) + if v := acc.Permissions.HasRole("chuck"); !v { + t.Fatal("expected role to be added") + } + + fmt.Println("\n#### RmRole") + // RmRole + snativeArgs = snativeRoleTestInputTx("rm_role", user[3], "chuck") + testSNativeTxExpectFail(t, blockCache, snativeArgs) + testSNativeTxExpectPass(t, blockCache, ptypes.RmRole, snativeArgs) + acc = blockCache.GetAccount(user[3].Address) + if v := acc.Permissions.HasRole("chuck"); v { + t.Fatal("expected role to be removed") + } } //------------------------------------------------------------------------------------- // helpers -// run ExecTx and wait for the Receive event on given addr +var ExceptionTimeOut = "timed out waiting for event" + +// run ExecTx and wait for the Call event on given addr // returns the msg data and an error/exception func execTxWaitEvent(t *testing.T, blockCache *BlockCache, tx types.Tx, eventid string) (interface{}, string) { - evsw := new(events.EventSwitch) + evsw := events.NewEventSwitch() evsw.Start() ch := make(chan interface{}) evsw.AddListenerForEvent("test", eventid, func(msg interface{}) { @@ -1117,7 +1064,14 @@ func execTxWaitEvent(t *testing.T, blockCache *BlockCache, tx types.Tx, eventid } evc.Flush() }() - msg := <-ch + ticker := time.NewTicker(5 * time.Second) + var msg interface{} + select { + case msg = <-ch: + case <-ticker.C: + return nil, ExceptionTimeOut + } + switch ev := msg.(type) { case types.EventMsgCallTx: return ev, ev.Exception @@ -1130,52 +1084,77 @@ func execTxWaitEvent(t *testing.T, blockCache *BlockCache, tx types.Tx, eventid } } +// give a contract perms for an snative, call it, it calls the snative, but shouldn't have permission +func testSNativeCALLExpectFail(t *testing.T, blockCache *BlockCache, doug *acm.Account, snativeAddress, data []byte) { + testSNativeCALL(t, false, blockCache, doug, snativeAddress, data, nil) +} + // give a contract perms for an snative, call it, it calls the snative, ensure the check funciton (f) succeeds -func testSNativeCALLExpectPass(t *testing.T, blockCache *BlockCache, doug *account.Account, snativeAddress, data []byte, f func([]byte) error) { - perm := vm.RegisteredSNativePermissions[LeftPadWord256(snativeAddress)] - var addr []byte - if doug != nil { - contractCode := callContractCode(snativeAddress) - doug.Code = contractCode +func testSNativeCALLExpectPass(t *testing.T, blockCache *BlockCache, doug *acm.Account, snativeAddress, data []byte, f func([]byte) error) { + testSNativeCALL(t, true, blockCache, doug, snativeAddress, data, f) +} + +func testSNativeCALL(t *testing.T, expectPass bool, blockCache *BlockCache, doug *acm.Account, snativeAddress, data []byte, f func([]byte) error) { + if expectPass { + perm, err := ptypes.PermStringToFlag(TrimmedString(snativeAddress)) + if err != nil { + t.Fatal(err) + } doug.Permissions.Base.Set(perm, true) - blockCache.UpdateAccount(doug) - addr = doug.Address - } else { - acc := blockCache.GetAccount(user[0].Address) - acc.Permissions.Base.Set(perm, true) - blockCache.UpdateAccount(acc) - addr = snativeAddress } + var addr []byte + contractCode := callContractCode(snativeAddress) + doug.Code = contractCode + blockCache.UpdateAccount(doug) + addr = doug.Address tx, _ := types.NewCallTx(blockCache, user[0].PubKey, addr, data, 100, 10000, 100) tx.Sign(chainID, user[0]) - ev, exception := execTxWaitEvent(t, blockCache, tx, types.EventStringAccReceive(snativeAddress)) // - if exception != "" { - t.Fatal("Unexpected exception", exception) - } - evv := ev.(types.EventMsgCall) - ret := evv.Return - if err := f(ret); err != nil { - t.Fatal(err) + fmt.Println("subscribing to", types.EventStringAccCall(snativeAddress)) + ev, exception := execTxWaitEvent(t, blockCache, tx, types.EventStringAccCall(snativeAddress)) + if exception == ExceptionTimeOut { + t.Fatal("Timed out waiting for event") + } + if expectPass { + if exception != "" { + t.Fatal("Unexpected exception", exception) + } + evv := ev.(types.EventMsgCall) + ret := evv.Return + if err := f(ret); err != nil { + t.Fatal(err) + } + } else { + if exception == "" { + t.Fatal("Expected exception") + } } } -// assumes the contract has not been given the permission. calls the it, it calls the snative, expects to fail -func testSNativeCALLExpectFail(t *testing.T, blockCache *BlockCache, doug *account.Account, snativeAddress, data []byte) { - var addr []byte - if doug != nil { - contractCode := callContractCode(snativeAddress) - doug.Code = contractCode - blockCache.UpdateAccount(doug) - addr = doug.Address - } else { - addr = snativeAddress +func testSNativeTxExpectFail(t *testing.T, blockCache *BlockCache, snativeArgs ptypes.PermArgs) { + testSNativeTx(t, false, blockCache, 0, snativeArgs) +} + +func testSNativeTxExpectPass(t *testing.T, blockCache *BlockCache, perm ptypes.PermFlag, snativeArgs ptypes.PermArgs) { + testSNativeTx(t, true, blockCache, perm, snativeArgs) +} + +func testSNativeTx(t *testing.T, expectPass bool, blockCache *BlockCache, perm ptypes.PermFlag, snativeArgs ptypes.PermArgs) { + if expectPass { + acc := blockCache.GetAccount(user[0].Address) + acc.Permissions.Base.Set(perm, true) + blockCache.UpdateAccount(acc) } - tx, _ := types.NewCallTx(blockCache, user[0].PubKey, addr, data, 100, 10000, 100) + tx, _ := types.NewPermissionsTx(blockCache, user[0].PubKey, snativeArgs) tx.Sign(chainID, user[0]) - fmt.Println("subscribing to", types.EventStringAccReceive(snativeAddress)) - _, exception := execTxWaitEvent(t, blockCache, tx, types.EventStringAccReceive(snativeAddress)) - if exception == "" { - t.Fatal("Expected exception") + err := ExecTx(blockCache, tx, true, nil) + if expectPass { + if err != nil { + t.Fatal("Unexpected exception", err) + } + } else { + if err == nil { + t.Fatal("Expected exception") + } } } @@ -1189,31 +1168,56 @@ func boolToWord256(v bool) Word256 { return LeftPadWord256([]byte{vint}) } -func snativePermTestInput(name string, user *account.PrivAccount, perm ptypes.PermFlag, val bool) (addr []byte, data []byte) { +func snativePermTestInputCALL(name string, user *acm.PrivAccount, perm ptypes.PermFlag, val bool) (addr []byte, data []byte) { addr = LeftPadWord256([]byte(name)).Postfix(20) switch name { - case "hasBasePerm", "unsetBasePerm": + case "has_base", "unset_base": data = LeftPadBytes(user.Address, 32) data = append(data, Uint64ToWord256(uint64(perm)).Bytes()...) - case "setBasePerm": + case "set_base": data = LeftPadBytes(user.Address, 32) data = append(data, Uint64ToWord256(uint64(perm)).Bytes()...) data = append(data, boolToWord256(val).Bytes()...) - case "setGlobalPerm": + case "set_global": data = Uint64ToWord256(uint64(perm)).Bytes() data = append(data, boolToWord256(val).Bytes()...) - case "clearBasePerm": } return } -func snativeRoleTestInput(name string, user *account.PrivAccount, role string) (addr []byte, data []byte) { +func snativePermTestInputTx(name string, user *acm.PrivAccount, perm ptypes.PermFlag, val bool) (snativeArgs ptypes.PermArgs) { + switch name { + case "has_base": + snativeArgs = &ptypes.HasBaseArgs{user.Address, perm} + case "unset_base": + snativeArgs = &ptypes.UnsetBaseArgs{user.Address, perm} + case "set_base": + snativeArgs = &ptypes.SetBaseArgs{user.Address, perm, val} + case "set_global": + snativeArgs = &ptypes.SetGlobalArgs{perm, val} + } + return +} + +func snativeRoleTestInputCALL(name string, user *acm.PrivAccount, role string) (addr []byte, data []byte) { addr = LeftPadWord256([]byte(name)).Postfix(20) data = LeftPadBytes(user.Address, 32) data = append(data, LeftPadBytes([]byte(role), 32)...) return } +func snativeRoleTestInputTx(name string, user *acm.PrivAccount, role string) (snativeArgs ptypes.PermArgs) { + switch name { + case "has_role": + snativeArgs = &ptypes.HasRoleArgs{user.Address, role} + case "add_role": + snativeArgs = &ptypes.AddRoleArgs{user.Address, role} + case "rm_role": + snativeArgs = &ptypes.RmRoleArgs{user.Address, role} + } + return +} + // convenience function for contract that calls a given address func callContractCode(contractAddr []byte) []byte { // calldatacopy into mem and use as input to call diff --git a/Godeps/_workspace/src/github.com/tendermint/tendermint/state/priv_validator.go b/Godeps/_workspace/src/github.com/tendermint/tendermint/state/priv_validator.go index c0aba08a..1a9019bf 100644 --- a/Godeps/_workspace/src/github.com/tendermint/tendermint/state/priv_validator.go +++ b/Godeps/_workspace/src/github.com/tendermint/tendermint/state/priv_validator.go @@ -7,11 +7,11 @@ import ( "math" "sync" - "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/account" - "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/binary" + acm "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/account" . "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/common" . "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/consensus/types" "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/types" + "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/wire" "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/ed25519" ) @@ -30,19 +30,18 @@ func voteToStep(vote *types.Vote) int8 { case types.VoteTypePrecommit: return stepPrecommit default: - // SANITY CHECK (binary decoding should catch bad vote types - // before they get here (right?!) - panic("Unknown vote type") + PanicSanity("Unknown vote type") + return 0 } } type PrivValidator struct { - Address []byte `json:"address"` - PubKey account.PubKeyEd25519 `json:"pub_key"` - PrivKey account.PrivKeyEd25519 `json:"priv_key"` - LastHeight int `json:"last_height"` - LastRound int `json:"last_round"` - LastStep int8 `json:"last_step"` + Address []byte `json:"address"` + PubKey acm.PubKeyEd25519 `json:"pub_key"` + PrivKey acm.PrivKeyEd25519 `json:"priv_key"` + LastHeight int `json:"last_height"` + LastRound int `json:"last_round"` + LastStep int8 `json:"last_step"` // For persistence. // Overloaded for testing. @@ -55,8 +54,8 @@ func GenPrivValidator() *PrivValidator { privKeyBytes := new([64]byte) copy(privKeyBytes[:32], CRandBytes(32)) pubKeyBytes := ed25519.MakePublicKey(privKeyBytes) - pubKey := account.PubKeyEd25519(pubKeyBytes[:]) - privKey := account.PrivKeyEd25519(privKeyBytes[:]) + pubKey := acm.PubKeyEd25519(*pubKeyBytes) + privKey := acm.PrivKeyEd25519(*privKeyBytes) return &PrivValidator{ Address: pubKey.Address(), PubKey: pubKey, @@ -73,7 +72,7 @@ func LoadPrivValidator(filePath string) *PrivValidator { if err != nil { Exit(err.Error()) } - privVal := binary.ReadJSON(&PrivValidator{}, privValJSONBytes, &err).(*PrivValidator) + privVal := wire.ReadJSON(&PrivValidator{}, privValJSONBytes, &err).(*PrivValidator) if err != nil { Exit(Fmt("Error reading PrivValidator from %v: %v\n", filePath, err)) } @@ -95,14 +94,13 @@ func (privVal *PrivValidator) Save() { func (privVal *PrivValidator) save() { if privVal.filePath == "" { - // SANITY CHECK - panic("Cannot save PrivValidator: filePath not set") + PanicSanity("Cannot save PrivValidator: filePath not set") } - jsonBytes := binary.JSONBytes(privVal) + jsonBytes := wire.JSONBytes(privVal) err := WriteFileAtomic(privVal.filePath, jsonBytes) if err != nil { // `@; BOOM!!! - panic(err) + PanicCrisis(err) } } @@ -138,7 +136,7 @@ func (privVal *PrivValidator) SignVote(chainID string, vote *types.Vote) error { } func (privVal *PrivValidator) SignVoteUnsafe(chainID string, vote *types.Vote) { - vote.Signature = privVal.PrivKey.Sign(account.SignBytes(chainID, vote)).(account.SignatureEd25519) + vote.Signature = privVal.PrivKey.Sign(acm.SignBytes(chainID, vote)).(acm.SignatureEd25519) } func (privVal *PrivValidator) SignProposal(chainID string, proposal *Proposal) error { @@ -155,7 +153,7 @@ func (privVal *PrivValidator) SignProposal(chainID string, proposal *Proposal) e privVal.save() // Sign - proposal.Signature = privVal.PrivKey.Sign(account.SignBytes(chainID, proposal)).(account.SignatureEd25519) + proposal.Signature = privVal.PrivKey.Sign(acm.SignBytes(chainID, proposal)).(acm.SignatureEd25519) return nil } else { return errors.New(fmt.Sprintf("Attempt of duplicate signing of proposal: Height %v, Round %v", proposal.Height, proposal.Round)) @@ -175,7 +173,7 @@ func (privVal *PrivValidator) SignRebondTx(chainID string, rebondTx *types.Rebon privVal.save() // Sign - rebondTx.Signature = privVal.PrivKey.Sign(account.SignBytes(chainID, rebondTx)).(account.SignatureEd25519) + rebondTx.Signature = privVal.PrivKey.Sign(acm.SignBytes(chainID, rebondTx)).(acm.SignatureEd25519) return nil } else { return errors.New(fmt.Sprintf("Attempt of duplicate signing of rebondTx: Height %v", rebondTx.Height)) diff --git a/Godeps/_workspace/src/github.com/tendermint/tendermint/state/state.go b/Godeps/_workspace/src/github.com/tendermint/tendermint/state/state.go index 263f5c24..395c01ff 100644 --- a/Godeps/_workspace/src/github.com/tendermint/tendermint/state/state.go +++ b/Godeps/_workspace/src/github.com/tendermint/tendermint/state/state.go @@ -5,13 +5,13 @@ import ( "io" "time" - "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/account" - "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/binary" + acm "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/account" . "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/common" dbm "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/db" "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/events" "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/merkle" "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/types" + "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/wire" ) var ( @@ -49,22 +49,22 @@ func LoadState(db dbm.DB) *State { return nil } else { r, n, err := bytes.NewReader(buf), new(int64), new(error) - s.ChainID = binary.ReadString(r, n, err) - s.LastBlockHeight = binary.ReadVarint(r, n, err) - s.LastBlockHash = binary.ReadByteSlice(r, n, err) - s.LastBlockParts = binary.ReadBinary(types.PartSetHeader{}, r, n, err).(types.PartSetHeader) - s.LastBlockTime = binary.ReadTime(r, n, err) - s.BondedValidators = binary.ReadBinary(&ValidatorSet{}, r, n, err).(*ValidatorSet) - s.LastBondedValidators = binary.ReadBinary(&ValidatorSet{}, r, n, err).(*ValidatorSet) - s.UnbondingValidators = binary.ReadBinary(&ValidatorSet{}, r, n, err).(*ValidatorSet) - accountsHash := binary.ReadByteSlice(r, n, err) - s.accounts = merkle.NewIAVLTree(binary.BasicCodec, account.AccountCodec, defaultAccountsCacheCapacity, db) + s.ChainID = wire.ReadString(r, n, err) + s.LastBlockHeight = wire.ReadVarint(r, n, err) + s.LastBlockHash = wire.ReadByteSlice(r, n, err) + s.LastBlockParts = wire.ReadBinary(types.PartSetHeader{}, r, n, err).(types.PartSetHeader) + s.LastBlockTime = wire.ReadTime(r, n, err) + s.BondedValidators = wire.ReadBinary(&ValidatorSet{}, r, n, err).(*ValidatorSet) + s.LastBondedValidators = wire.ReadBinary(&ValidatorSet{}, r, n, err).(*ValidatorSet) + s.UnbondingValidators = wire.ReadBinary(&ValidatorSet{}, r, n, err).(*ValidatorSet) + accountsHash := wire.ReadByteSlice(r, n, err) + s.accounts = merkle.NewIAVLTree(wire.BasicCodec, acm.AccountCodec, defaultAccountsCacheCapacity, db) s.accounts.Load(accountsHash) - validatorInfosHash := binary.ReadByteSlice(r, n, err) - s.validatorInfos = merkle.NewIAVLTree(binary.BasicCodec, ValidatorInfoCodec, 0, db) + validatorInfosHash := wire.ReadByteSlice(r, n, err) + s.validatorInfos = merkle.NewIAVLTree(wire.BasicCodec, ValidatorInfoCodec, 0, db) s.validatorInfos.Load(validatorInfosHash) - nameRegHash := binary.ReadByteSlice(r, n, err) - s.nameReg = merkle.NewIAVLTree(binary.BasicCodec, NameRegCodec, 0, db) + nameRegHash := wire.ReadByteSlice(r, n, err) + s.nameReg = merkle.NewIAVLTree(wire.BasicCodec, NameRegCodec, 0, db) s.nameReg.Load(nameRegHash) if *err != nil { // DATA HAS BEEN CORRUPTED OR THE SPEC HAS CHANGED @@ -80,20 +80,19 @@ func (s *State) Save() { s.validatorInfos.Save() s.nameReg.Save() buf, n, err := new(bytes.Buffer), new(int64), new(error) - binary.WriteString(s.ChainID, buf, n, err) - binary.WriteVarint(s.LastBlockHeight, buf, n, err) - binary.WriteByteSlice(s.LastBlockHash, buf, n, err) - binary.WriteBinary(s.LastBlockParts, buf, n, err) - binary.WriteTime(s.LastBlockTime, buf, n, err) - binary.WriteBinary(s.BondedValidators, buf, n, err) - binary.WriteBinary(s.LastBondedValidators, buf, n, err) - binary.WriteBinary(s.UnbondingValidators, buf, n, err) - binary.WriteByteSlice(s.accounts.Hash(), buf, n, err) - binary.WriteByteSlice(s.validatorInfos.Hash(), buf, n, err) - binary.WriteByteSlice(s.nameReg.Hash(), buf, n, err) + wire.WriteString(s.ChainID, buf, n, err) + wire.WriteVarint(s.LastBlockHeight, buf, n, err) + wire.WriteByteSlice(s.LastBlockHash, buf, n, err) + wire.WriteBinary(s.LastBlockParts, buf, n, err) + wire.WriteTime(s.LastBlockTime, buf, n, err) + wire.WriteBinary(s.BondedValidators, buf, n, err) + wire.WriteBinary(s.LastBondedValidators, buf, n, err) + wire.WriteBinary(s.UnbondingValidators, buf, n, err) + wire.WriteByteSlice(s.accounts.Hash(), buf, n, err) + wire.WriteByteSlice(s.validatorInfos.Hash(), buf, n, err) + wire.WriteByteSlice(s.nameReg.Hash(), buf, n, err) if *err != nil { - // SOMETHING HAS GONE HORRIBLY WRONG - panic(*err) + PanicCrisis(*err) } s.DB.Set(stateKey, buf.Bytes()) } @@ -148,6 +147,14 @@ func (s *State) SetDB(db dbm.DB) { s.DB = db } +//------------------------------------- +// State.params + +func (s *State) GetGasLimit() int64 { + return 1000000 // TODO +} + +// State.params //------------------------------------- // State.accounts @@ -155,18 +162,18 @@ func (s *State) SetDB(db dbm.DB) { // The returned Account is a copy, so mutating it // has no side effects. // Implements Statelike -func (s *State) GetAccount(address []byte) *account.Account { +func (s *State) GetAccount(address []byte) *acm.Account { _, acc := s.accounts.Get(address) if acc == nil { return nil } - return acc.(*account.Account).Copy() + return acc.(*acm.Account).Copy() } // The account is copied before setting, so mutating it // afterwards has no side effects. // Implements Statelike -func (s *State) UpdateAccount(account *account.Account) bool { +func (s *State) UpdateAccount(account *acm.Account) bool { return s.accounts.Set(account.Address, account.Copy()) } @@ -216,14 +223,12 @@ func (s *State) unbondValidator(val *Validator) { // Move validator to UnbondingValidators val, removed := s.BondedValidators.Remove(val.Address) if !removed { - // SOMETHING HAS GONE HORRIBLY WRONG - panic("Couldn't remove validator for unbonding") + PanicCrisis("Couldn't remove validator for unbonding") } val.UnbondHeight = s.LastBlockHeight + 1 added := s.UnbondingValidators.Add(val) if !added { - // SOMETHING HAS GONE HORRIBLY WRONG - panic("Couldn't add validator for unbonding") + PanicCrisis("Couldn't add validator for unbonding") } } @@ -231,35 +236,29 @@ func (s *State) rebondValidator(val *Validator) { // Move validator to BondingValidators val, removed := s.UnbondingValidators.Remove(val.Address) if !removed { - // SOMETHING HAS GONE HORRIBLY WRONG - panic("Couldn't remove validator for rebonding") + PanicCrisis("Couldn't remove validator for rebonding") } val.BondHeight = s.LastBlockHeight + 1 added := s.BondedValidators.Add(val) if !added { - // SOMETHING HAS GONE HORRIBLY WRONG - panic("Couldn't add validator for rebonding") + PanicCrisis("Couldn't add validator for rebonding") } } func (s *State) releaseValidator(val *Validator) { // Update validatorInfo valInfo := s.GetValidatorInfo(val.Address) - // SANITY CHECK if valInfo == nil { - panic("Couldn't find validatorInfo for release") + PanicSanity("Couldn't find validatorInfo for release") } - // SANITY CHECK END valInfo.ReleasedHeight = s.LastBlockHeight + 1 s.SetValidatorInfo(valInfo) // Send coins back to UnbondTo outputs accounts, err := getOrMakeOutputs(s, nil, valInfo.UnbondTo) - // SANITY CHECK if err != nil { - panic("Couldn't get or make unbondTo accounts") + PanicSanity("Couldn't get or make unbondTo accounts") } - // SANITY CHECK END adjustByOutputs(accounts, valInfo.UnbondTo) for _, acc := range accounts { s.UpdateAccount(acc) @@ -268,19 +267,16 @@ func (s *State) releaseValidator(val *Validator) { // Remove validator from UnbondingValidators _, removed := s.UnbondingValidators.Remove(val.Address) if !removed { - // SOMETHING HAS GONE HORRIBLY WRONG - panic("Couldn't remove validator for release") + PanicCrisis("Couldn't remove validator for release") } } func (s *State) destroyValidator(val *Validator) { // Update validatorInfo valInfo := s.GetValidatorInfo(val.Address) - // SANITY CHECK if valInfo == nil { - panic("Couldn't find validatorInfo for release") + PanicSanity("Couldn't find validatorInfo for release") } - // SANITY CHECK END valInfo.DestroyedHeight = s.LastBlockHeight + 1 valInfo.DestroyedAmount = val.VotingPower s.SetValidatorInfo(valInfo) @@ -290,8 +286,7 @@ func (s *State) destroyValidator(val *Validator) { if !removed { _, removed := s.UnbondingValidators.Remove(val.Address) if !removed { - // SOMETHING HAS GONE HORRIBLY WRONG - panic("Couldn't remove validator for destruction") + PanicCrisis("Couldn't remove validator for destruction") } } @@ -307,7 +302,7 @@ func (s *State) SetValidatorInfos(validatorInfos merkle.Tree) { // State.storage func (s *State) LoadStorage(hash []byte) (storage merkle.Tree) { - storage = merkle.NewIAVLTree(binary.BasicCodec, binary.BasicCodec, 1024, s.DB) + storage = merkle.NewIAVLTree(wire.BasicCodec, wire.BasicCodec, 1024, s.DB) storage.Load(hash) return storage } @@ -344,14 +339,14 @@ func (s *State) SetNameReg(nameReg merkle.Tree) { } func NameRegEncoder(o interface{}, w io.Writer, n *int64, err *error) { - binary.WriteBinary(o.(*types.NameRegEntry), w, n, err) + wire.WriteBinary(o.(*types.NameRegEntry), w, n, err) } func NameRegDecoder(r io.Reader, n *int64, err *error) interface{} { - return binary.ReadBinary(&types.NameRegEntry{}, r, n, err) + return wire.ReadBinary(&types.NameRegEntry{}, r, n, err) } -var NameRegCodec = binary.Codec{ +var NameRegCodec = wire.Codec{ Encode: NameRegEncoder, Decode: NameRegDecoder, } diff --git a/Godeps/_workspace/src/github.com/tendermint/tendermint/state/test.go b/Godeps/_workspace/src/github.com/tendermint/tendermint/state/test.go index dddcbf45..e26aa3a3 100644 --- a/Godeps/_workspace/src/github.com/tendermint/tendermint/state/test.go +++ b/Godeps/_workspace/src/github.com/tendermint/tendermint/state/test.go @@ -4,7 +4,7 @@ import ( "bytes" "sort" - "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/account" + acm "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/account" . "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/common" dbm "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/db" ptypes "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/permission/types" @@ -18,15 +18,15 @@ import ( func Tempfile(prefix string) (*os.File, string) { file, err := ioutil.TempFile("", prefix) if err != nil { - panic(err) + PanicCrisis(err) } return file, file.Name() } -func RandAccount(randBalance bool, minBalance int64) (*account.Account, *account.PrivAccount) { - privAccount := account.GenPrivAccount() +func RandAccount(randBalance bool, minBalance int64) (*acm.Account, *acm.PrivAccount) { + privAccount := acm.GenPrivAccount() perms := ptypes.DefaultAccountPermissions - acc := &account.Account{ + acc := &acm.Account{ Address: privAccount.PubKey.Address(), PubKey: privAccount.PubKey, Sequence: RandInt(), @@ -69,9 +69,9 @@ func RandValidator(randBonded bool, minBonded int64) (*ValidatorInfo, *Validator return valInfo, val, privVal } -func RandGenesisDoc(numAccounts int, randBalance bool, minBalance int64, numValidators int, randBonded bool, minBonded int64) (*GenesisDoc, []*account.PrivAccount, []*PrivValidator) { +func RandGenesisDoc(numAccounts int, randBalance bool, minBalance int64, numValidators int, randBonded bool, minBonded int64) (*GenesisDoc, []*acm.PrivAccount, []*PrivValidator) { accounts := make([]GenesisAccount, numAccounts) - privAccounts := make([]*account.PrivAccount, numAccounts) + privAccounts := make([]*acm.PrivAccount, numAccounts) defaultPerms := ptypes.DefaultAccountPermissions for i := 0; i < numAccounts; i++ { account, privAccount := RandAccount(randBalance, minBalance) @@ -108,7 +108,7 @@ func RandGenesisDoc(numAccounts int, randBalance bool, minBalance int64, numVali } -func RandGenesisState(numAccounts int, randBalance bool, minBalance int64, numValidators int, randBonded bool, minBonded int64) (*State, []*account.PrivAccount, []*PrivValidator) { +func RandGenesisState(numAccounts int, randBalance bool, minBalance int64, numValidators int, randBonded bool, minBonded int64) (*State, []*acm.PrivAccount, []*PrivValidator) { db := dbm.NewMemDB() genDoc, privAccounts, privValidators := RandGenesisDoc(numAccounts, randBalance, minBalance, numValidators, randBonded, minBonded) s0 := MakeGenesisState(db, genDoc) diff --git a/Godeps/_workspace/src/github.com/tendermint/tendermint/state/tx_cache.go b/Godeps/_workspace/src/github.com/tendermint/tendermint/state/tx_cache.go index e3f4752c..422ae7df 100644 --- a/Godeps/_workspace/src/github.com/tendermint/tendermint/state/tx_cache.go +++ b/Godeps/_workspace/src/github.com/tendermint/tendermint/state/tx_cache.go @@ -1,7 +1,7 @@ package state import ( - ac "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/account" + acm "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/account" . "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/common" ptypes "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/permission/types" // for GlobalPermissionAddress ... "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/vm" @@ -28,7 +28,7 @@ func NewTxCache(backend *BlockCache) *TxCache { // TxCache.account func (cache *TxCache) GetAccount(addr Word256) *vm.Account { - acc, removed := vmUnpack(cache.accounts[addr]) + acc, removed := cache.accounts[addr].unpack() if removed { return nil } else if acc == nil { @@ -42,23 +42,19 @@ func (cache *TxCache) GetAccount(addr Word256) *vm.Account { func (cache *TxCache) UpdateAccount(acc *vm.Account) { addr := acc.Address - // SANITY CHECK - _, removed := vmUnpack(cache.accounts[addr]) + _, removed := cache.accounts[addr].unpack() if removed { - panic("UpdateAccount on a removed account") + PanicSanity("UpdateAccount on a removed account") } - // SANITY CHECK END cache.accounts[addr] = vmAccountInfo{acc, false} } func (cache *TxCache) RemoveAccount(acc *vm.Account) { addr := acc.Address - // SANITY CHECK - _, removed := vmUnpack(cache.accounts[addr]) + _, removed := cache.accounts[addr].unpack() if removed { - panic("RemoveAccount on a removed account") + PanicSanity("RemoveAccount on a removed account") } - // SANITY CHECK END cache.accounts[addr] = vmAccountInfo{acc, true} } @@ -72,22 +68,25 @@ func (cache *TxCache) CreateAccount(creator *vm.Account) *vm.Account { addr := LeftPadWord256(NewContractAddress(creator.Address.Postfix(20), int(nonce))) // Create account from address. - account, removed := vmUnpack(cache.accounts[addr]) + account, removed := cache.accounts[addr].unpack() if removed || account == nil { account = &vm.Account{ Address: addr, Balance: 0, Code: nil, Nonce: 0, - StorageRoot: Zero256, Permissions: cache.GetAccount(ptypes.GlobalPermissionsAddress256).Permissions, - Other: nil, + Other: vmAccountOther{ + PubKey: nil, + StorageRoot: nil, + }, } cache.accounts[addr] = vmAccountInfo{account, false} return account } else { - // NONCE HANDLING SANITY CHECK OR SHA3 IS BROKEN - panic(Fmt("Could not create account, address already exists: %X", addr)) + // either we've messed up nonce handling, or sha3 is broken + PanicSanity(Fmt("Could not create account, address already exists: %X", addr)) + return nil } } @@ -108,12 +107,10 @@ func (cache *TxCache) GetStorage(addr Word256, key Word256) Word256 { // NOTE: Set value to zero to removed from the trie. func (cache *TxCache) SetStorage(addr Word256, key Word256, value Word256) { - // SANITY CHECK - _, removed := vmUnpack(cache.accounts[addr]) + _, removed := cache.accounts[addr].unpack() if removed { - panic("SetStorage() on a removed account") + PanicSanity("SetStorage() on a removed account") } - // SANITY CHECK END cache.storages[Tuple256{addr, key}] = value } @@ -132,15 +129,13 @@ func (cache *TxCache) Sync() { // Remove or update accounts for addr, accInfo := range cache.accounts { - acc, removed := vmUnpack(accInfo) + acc, removed := accInfo.unpack() if removed { cache.backend.RemoveAccount(addr.Postfix(20)) } else { cache.backend.UpdateAccount(toStateAccount(acc)) } } - - // TODO support logs, add them to the cache somehow. } func (cache *TxCache) AddLog(log *vm.Log) { @@ -158,32 +153,29 @@ func NewContractAddress(caller []byte, nonce int) []byte { } // Converts backend.Account to vm.Account struct. -func toVMAccount(acc *ac.Account) *vm.Account { +func toVMAccount(acc *acm.Account) *vm.Account { return &vm.Account{ Address: LeftPadWord256(acc.Address), Balance: acc.Balance, Code: acc.Code, // This is crazy. Nonce: int64(acc.Sequence), - StorageRoot: LeftPadWord256(acc.StorageRoot), Permissions: acc.Permissions, // Copy - Other: acc.PubKey, + Other: vmAccountOther{ + PubKey: acc.PubKey, + StorageRoot: acc.StorageRoot, + }, } } // Converts vm.Account to backend.Account struct. -func toStateAccount(acc *vm.Account) *ac.Account { - pubKey, ok := acc.Other.(ac.PubKey) - if !ok { - pubKey = nil - } - +func toStateAccount(acc *vm.Account) *acm.Account { + var pubKey acm.PubKey var storageRoot []byte - if acc.StorageRoot.IsZero() { - storageRoot = nil - } else { - storageRoot = acc.StorageRoot.Bytes() + if acc.Other != nil { + pubKey, storageRoot = acc.Other.(vmAccountOther).unpack() } - return &ac.Account{ + + return &acm.Account{ Address: acc.Address.Postfix(20), PubKey: pubKey, Balance: acc.Balance, @@ -194,11 +186,22 @@ func toStateAccount(acc *vm.Account) *ac.Account { } } +// Everything in acmAccount that doesn't belong in +// exported vmAccount fields. +type vmAccountOther struct { + PubKey acm.PubKey + StorageRoot []byte +} + +func (accOther vmAccountOther) unpack() (acm.PubKey, []byte) { + return accOther.PubKey, accOther.StorageRoot +} + type vmAccountInfo struct { account *vm.Account removed bool } -func vmUnpack(accInfo vmAccountInfo) (*vm.Account, bool) { +func (accInfo vmAccountInfo) unpack() (*vm.Account, bool) { return accInfo.account, accInfo.removed } diff --git a/Godeps/_workspace/src/github.com/tendermint/tendermint/state/tx_cache_test.go b/Godeps/_workspace/src/github.com/tendermint/tendermint/state/tx_cache_test.go new file mode 100644 index 00000000..ef654492 --- /dev/null +++ b/Godeps/_workspace/src/github.com/tendermint/tendermint/state/tx_cache_test.go @@ -0,0 +1,22 @@ +package state + +import ( + "bytes" + "testing" + + "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/wire" +) + +func TestStateToFromVMAccount(t *testing.T) { + acmAcc1, _ := RandAccount(true, 456) + vmAcc := toVMAccount(acmAcc1) + acmAcc2 := toStateAccount(vmAcc) + + acmAcc1Bytes := wire.BinaryBytes(acmAcc1) + acmAcc2Bytes := wire.BinaryBytes(acmAcc2) + if !bytes.Equal(acmAcc1Bytes, acmAcc2Bytes) { + t.Errorf("Unexpected account wire bytes\n%X vs\n%X", + acmAcc1Bytes, acmAcc2Bytes) + } + +} diff --git a/Godeps/_workspace/src/github.com/tendermint/tendermint/state/validator.go b/Godeps/_workspace/src/github.com/tendermint/tendermint/state/validator.go index 75d430fe..de34d407 100644 --- a/Godeps/_workspace/src/github.com/tendermint/tendermint/state/validator.go +++ b/Godeps/_workspace/src/github.com/tendermint/tendermint/state/validator.go @@ -5,21 +5,22 @@ import ( "fmt" "io" - "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/account" - "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/binary" + acm "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/account" + . "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/common" "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/types" + "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/wire" ) // Persistent (mostly) static data for each Validator type ValidatorInfo struct { - Address []byte `json:"address"` - PubKey account.PubKeyEd25519 `json:"pub_key"` - UnbondTo []*types.TxOutput `json:"unbond_to"` - FirstBondHeight int `json:"first_bond_height"` - FirstBondAmount int64 `json:"first_bond_amount"` - DestroyedHeight int `json:"destroyed_height"` // If destroyed - DestroyedAmount int64 `json:"destroyed_amount"` // If destroyed - ReleasedHeight int `json:"released_height"` // If released + Address []byte `json:"address"` + PubKey acm.PubKeyEd25519 `json:"pub_key"` + UnbondTo []*types.TxOutput `json:"unbond_to"` + FirstBondHeight int `json:"first_bond_height"` + FirstBondAmount int64 `json:"first_bond_amount"` + DestroyedHeight int `json:"destroyed_height"` // If destroyed + DestroyedAmount int64 `json:"destroyed_amount"` // If destroyed + ReleasedHeight int `json:"released_height"` // If released } func (valInfo *ValidatorInfo) Copy() *ValidatorInfo { @@ -28,14 +29,14 @@ func (valInfo *ValidatorInfo) Copy() *ValidatorInfo { } func ValidatorInfoEncoder(o interface{}, w io.Writer, n *int64, err *error) { - binary.WriteBinary(o.(*ValidatorInfo), w, n, err) + wire.WriteBinary(o.(*ValidatorInfo), w, n, err) } func ValidatorInfoDecoder(r io.Reader, n *int64, err *error) interface{} { - return binary.ReadBinary(&ValidatorInfo{}, r, n, err) + return wire.ReadBinary(&ValidatorInfo{}, r, n, err) } -var ValidatorInfoCodec = binary.Codec{ +var ValidatorInfoCodec = wire.Codec{ Encode: ValidatorInfoEncoder, Decode: ValidatorInfoDecoder, } @@ -46,13 +47,13 @@ var ValidatorInfoCodec = binary.Codec{ // Also persisted with the state, but fields change // every height|round so they don't go in merkle.Tree type Validator struct { - Address []byte `json:"address"` - PubKey account.PubKeyEd25519 `json:"pub_key"` - BondHeight int `json:"bond_height"` - UnbondHeight int `json:"unbond_height"` - LastCommitHeight int `json:"last_commit_height"` - VotingPower int64 `json:"voting_power"` - Accum int64 `json:"accum"` + Address []byte `json:"address"` + PubKey acm.PubKeyEd25519 `json:"pub_key"` + BondHeight int `json:"bond_height"` + UnbondHeight int `json:"unbond_height"` + LastCommitHeight int `json:"last_commit_height"` + VotingPower int64 `json:"voting_power"` + Accum int64 `json:"accum"` } // Creates a new copy of the validator so we can mutate accum. @@ -77,8 +78,8 @@ func (v *Validator) CompareAccum(other *Validator) *Validator { } else if bytes.Compare(v.Address, other.Address) > 0 { return other } else { - // SANITY CHECK - panic("Cannot compare identical validators") + PanicSanity("Cannot compare identical validators") + return nil } } } @@ -98,7 +99,7 @@ func (v *Validator) String() string { } func (v *Validator) Hash() []byte { - return binary.BinaryRipemd160(v) + return wire.BinaryRipemd160(v) } //------------------------------------- @@ -108,13 +109,14 @@ var ValidatorCodec = validatorCodec{} type validatorCodec struct{} func (vc validatorCodec) Encode(o interface{}, w io.Writer, n *int64, err *error) { - binary.WriteBinary(o.(*Validator), w, n, err) + wire.WriteBinary(o.(*Validator), w, n, err) } func (vc validatorCodec) Decode(r io.Reader, n *int64, err *error) interface{} { - return binary.ReadBinary(&Validator{}, r, n, err) + return wire.ReadBinary(&Validator{}, r, n, err) } func (vc validatorCodec) Compare(o1 interface{}, o2 interface{}) int { - panic("ValidatorCodec.Compare not implemented") + PanicSanity("ValidatorCodec.Compare not implemented") + return 0 } diff --git a/Godeps/_workspace/src/github.com/tendermint/tendermint/state/validator_set_test.go b/Godeps/_workspace/src/github.com/tendermint/tendermint/state/validator_set_test.go index 210e4834..82b593bb 100644 --- a/Godeps/_workspace/src/github.com/tendermint/tendermint/state/validator_set_test.go +++ b/Godeps/_workspace/src/github.com/tendermint/tendermint/state/validator_set_test.go @@ -9,10 +9,16 @@ import ( "testing" ) +func randPubKey() account.PubKeyEd25519 { + var pubKey [32]byte + copy(pubKey[:], RandBytes(32)) + return account.PubKeyEd25519(pubKey) +} + func randValidator_() *Validator { return &Validator{ Address: RandBytes(20), - PubKey: account.PubKeyEd25519(RandBytes(64)), + PubKey: randPubKey(), BondHeight: RandInt(), VotingPower: RandInt64(), Accum: RandInt64(), @@ -46,21 +52,21 @@ func TestProposerSelection(t *testing.T) { vset := NewValidatorSet([]*Validator{ &Validator{ Address: []byte("foo"), - PubKey: account.PubKeyEd25519(RandBytes(64)), + PubKey: randPubKey(), BondHeight: RandInt(), VotingPower: 1000, Accum: 0, }, &Validator{ Address: []byte("bar"), - PubKey: account.PubKeyEd25519(RandBytes(64)), + PubKey: randPubKey(), BondHeight: RandInt(), VotingPower: 300, Accum: 0, }, &Validator{ Address: []byte("baz"), - PubKey: account.PubKeyEd25519(RandBytes(64)), + PubKey: randPubKey(), BondHeight: RandInt(), VotingPower: 330, Accum: 0, diff --git a/Godeps/_workspace/src/github.com/tendermint/tendermint/types/block.go b/Godeps/_workspace/src/github.com/tendermint/tendermint/types/block.go index 7197f084..f0cbd11d 100644 --- a/Godeps/_workspace/src/github.com/tendermint/tendermint/types/block.go +++ b/Godeps/_workspace/src/github.com/tendermint/tendermint/types/block.go @@ -7,10 +7,10 @@ import ( "strings" "time" - "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/account" - "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/binary" + acm "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/account" . "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/common" "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/merkle" + "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/wire" ) type Block struct { @@ -75,7 +75,7 @@ func (b *Block) Hash() []byte { } func (b *Block) MakePartSet() *PartSet { - return NewPartSetFromData(binary.BinaryBytes(b)) + return NewPartSetFromData(wire.BinaryBytes(b)) } // Convenience. @@ -137,7 +137,7 @@ func (h *Header) Hash() []byte { return nil } - return binary.BinaryRipemd160(h) + return wire.BinaryRipemd160(h) } func (h *Header) StringIndented(indent string) string { @@ -310,7 +310,7 @@ func (data *Data) Hash() []byte { if data.hash == nil { bs := make([]interface{}, len(data.Txs)) for i, tx := range data.Txs { - bs[i] = account.SignBytes(config.GetString("chain_id"), tx) + bs[i] = acm.SignBytes(config.GetString("chain_id"), tx) } data.hash = merkle.SimpleHashFromBinaries(bs) // NOTE: leaves are TxIDs. } diff --git a/Godeps/_workspace/src/github.com/tendermint/tendermint/types/events.go b/Godeps/_workspace/src/github.com/tendermint/tendermint/types/events.go index c6d46bcb..e3502a1a 100644 --- a/Godeps/_workspace/src/github.com/tendermint/tendermint/types/events.go +++ b/Godeps/_workspace/src/github.com/tendermint/tendermint/types/events.go @@ -14,14 +14,18 @@ func EventStringAccOutput(addr []byte) string { return fmt.Sprintf("Acc/%X/Output", addr) } -func EventStringAccReceive(addr []byte) string { - return fmt.Sprintf("Acc/%X/Receive", addr) +func EventStringAccCall(addr []byte) string { + return fmt.Sprintf("Acc/%X/Call", addr) } func EventStringLogEvent(addr []byte) string { return fmt.Sprintf("Log/%X", addr) } +func EventStringPermissions(name string) string { + return fmt.Sprintf("Permissions/%s", name) +} + func EventStringBond() string { return "Bond" } diff --git a/Godeps/_workspace/src/github.com/tendermint/tendermint/types/part_set.go b/Godeps/_workspace/src/github.com/tendermint/tendermint/types/part_set.go index e6c8d509..439da483 100644 --- a/Godeps/_workspace/src/github.com/tendermint/tendermint/types/part_set.go +++ b/Godeps/_workspace/src/github.com/tendermint/tendermint/types/part_set.go @@ -9,9 +9,9 @@ import ( "github.com/eris-ltd/eris-db/Godeps/_workspace/src/code.google.com/p/go.crypto/ripemd160" - "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/binary" . "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/common" "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/merkle" + "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/wire" ) const ( @@ -36,10 +36,7 @@ func (part *Part) Hash() []byte { return part.hash } else { hasher := ripemd160.New() - _, err := hasher.Write(part.Bytes) - if err != nil { - panic(err) - } + hasher.Write(part.Bytes) // doesn't err part.hash = hasher.Sum(nil) return part.hash } @@ -79,7 +76,7 @@ func (psh PartSetHeader) Equals(other PartSetHeader) bool { } func (psh PartSetHeader) WriteSignBytes(w io.Writer, n *int64, err *error) { - binary.WriteTo([]byte(Fmt(`{"hash":"%X","total":%v}`, psh.Hash, psh.Total)), w, n, err) + wire.WriteTo([]byte(Fmt(`{"hash":"%X","total":%v}`, psh.Hash, psh.Total)), w, n, err) } //------------------------------------- @@ -226,7 +223,7 @@ func (ps *PartSet) IsComplete() bool { func (ps *PartSet) GetReader() io.Reader { if !ps.IsComplete() { - panic("Cannot GetReader() on incomplete PartSet") + PanicSanity("Cannot GetReader() on incomplete PartSet") } buf := []byte{} for _, part := range ps.parts { diff --git a/Godeps/_workspace/src/github.com/tendermint/tendermint/types/tx.go b/Godeps/_workspace/src/github.com/tendermint/tendermint/types/tx.go index 724cad93..cf9f611b 100644 --- a/Godeps/_workspace/src/github.com/tendermint/tendermint/types/tx.go +++ b/Godeps/_workspace/src/github.com/tendermint/tendermint/types/tx.go @@ -5,9 +5,10 @@ import ( "errors" "io" - "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/account" - "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/binary" + acm "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/account" . "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/common" + ptypes "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/permission/types" + "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/wire" ) var ( @@ -20,7 +21,7 @@ var ( ErrTxInvalidPubKey = errors.New("Error invalid pubkey") ErrTxInvalidSignature = errors.New("Error invalid signature") ErrTxInvalidString = errors.New("Error invalid string") - ErrIncorrectOwner = errors.New("Error incorrect owner") + ErrTxPermissionDenied = errors.New("Error permission denied") ) type ErrTxInvalidSequence struct { @@ -44,7 +45,11 @@ Validation Txs: - BondTx New validator posts a bond - UnbondTx Validator leaves - DupeoutTx Validator dupes out (equivocates) + +Admin Txs: + - PermissionsTx */ + type Tx interface { WriteSignBytes(chainID string, w io.Writer, n *int64, err *error) } @@ -61,28 +66,32 @@ const ( TxTypeUnbond = byte(0x12) TxTypeRebond = byte(0x13) TxTypeDupeout = byte(0x14) + + // Admin transactions + TxTypePermissions = byte(0x20) ) -// for binary.readReflect -var _ = binary.RegisterInterface( +// for wire.readReflect +var _ = wire.RegisterInterface( struct{ Tx }{}, - binary.ConcreteType{&SendTx{}, TxTypeSend}, - binary.ConcreteType{&CallTx{}, TxTypeCall}, - binary.ConcreteType{&NameTx{}, TxTypeName}, - binary.ConcreteType{&BondTx{}, TxTypeBond}, - binary.ConcreteType{&UnbondTx{}, TxTypeUnbond}, - binary.ConcreteType{&RebondTx{}, TxTypeRebond}, - binary.ConcreteType{&DupeoutTx{}, TxTypeDupeout}, + wire.ConcreteType{&SendTx{}, TxTypeSend}, + wire.ConcreteType{&CallTx{}, TxTypeCall}, + wire.ConcreteType{&NameTx{}, TxTypeName}, + wire.ConcreteType{&BondTx{}, TxTypeBond}, + wire.ConcreteType{&UnbondTx{}, TxTypeUnbond}, + wire.ConcreteType{&RebondTx{}, TxTypeRebond}, + wire.ConcreteType{&DupeoutTx{}, TxTypeDupeout}, + wire.ConcreteType{&PermissionsTx{}, TxTypePermissions}, ) //----------------------------------------------------------------------------- type TxInput struct { - Address []byte `json:"address"` // Hash of the PubKey - Amount int64 `json:"amount"` // Must not exceed account balance - Sequence int `json:"sequence"` // Must be 1 greater than the last committed TxInput - Signature account.Signature `json:"signature"` // Depends on the PubKey type and the whole Tx - PubKey account.PubKey `json:"pub_key"` // Must not be nil, may be nil + Address []byte `json:"address"` // Hash of the PubKey + Amount int64 `json:"amount"` // Must not exceed account balance + Sequence int `json:"sequence"` // Must be 1 greater than the last committed TxInput + Signature acm.Signature `json:"signature"` // Depends on the PubKey type and the whole Tx + PubKey acm.PubKey `json:"pub_key"` // Must not be nil, may be nil } func (txIn *TxInput) ValidateBasic() error { @@ -96,7 +105,7 @@ func (txIn *TxInput) ValidateBasic() error { } func (txIn *TxInput) WriteSignBytes(w io.Writer, n *int64, err *error) { - binary.WriteTo([]byte(Fmt(`{"address":"%X","amount":%v,"sequence":%v}`, txIn.Address, txIn.Amount, txIn.Sequence)), w, n, err) + wire.WriteTo([]byte(Fmt(`{"address":"%X","amount":%v,"sequence":%v}`, txIn.Address, txIn.Amount, txIn.Sequence)), w, n, err) } func (txIn *TxInput) String() string { @@ -121,7 +130,7 @@ func (txOut *TxOutput) ValidateBasic() error { } func (txOut *TxOutput) WriteSignBytes(w io.Writer, n *int64, err *error) { - binary.WriteTo([]byte(Fmt(`{"address":"%X","amount":%v}`, txOut.Address, txOut.Amount)), w, n, err) + wire.WriteTo([]byte(Fmt(`{"address":"%X","amount":%v}`, txOut.Address, txOut.Amount)), w, n, err) } func (txOut *TxOutput) String() string { @@ -136,22 +145,22 @@ type SendTx struct { } func (tx *SendTx) WriteSignBytes(chainID string, w io.Writer, n *int64, err *error) { - binary.WriteTo([]byte(Fmt(`{"chain_id":%s`, jsonEscape(chainID))), w, n, err) - binary.WriteTo([]byte(Fmt(`,"tx":[%v,{"inputs":[`, TxTypeSend)), w, n, err) + wire.WriteTo([]byte(Fmt(`{"chain_id":%s`, jsonEscape(chainID))), w, n, err) + wire.WriteTo([]byte(Fmt(`,"tx":[%v,{"inputs":[`, TxTypeSend)), w, n, err) for i, in := range tx.Inputs { in.WriteSignBytes(w, n, err) if i != len(tx.Inputs)-1 { - binary.WriteTo([]byte(","), w, n, err) + wire.WriteTo([]byte(","), w, n, err) } } - binary.WriteTo([]byte(`],"outputs":[`), w, n, err) + wire.WriteTo([]byte(`],"outputs":[`), w, n, err) for i, out := range tx.Outputs { out.WriteSignBytes(w, n, err) if i != len(tx.Outputs)-1 { - binary.WriteTo([]byte(","), w, n, err) + wire.WriteTo([]byte(","), w, n, err) } } - binary.WriteTo([]byte(`]}]}`), w, n, err) + wire.WriteTo([]byte(`]}]}`), w, n, err) } func (tx *SendTx) String() string { @@ -169,11 +178,11 @@ type CallTx struct { } func (tx *CallTx) WriteSignBytes(chainID string, w io.Writer, n *int64, err *error) { - binary.WriteTo([]byte(Fmt(`{"chain_id":%s`, jsonEscape(chainID))), w, n, err) - binary.WriteTo([]byte(Fmt(`,"tx":[%v,{"address":"%X","data":"%X"`, TxTypeCall, tx.Address, tx.Data)), w, n, err) - binary.WriteTo([]byte(Fmt(`,"fee":%v,"gas_limit":%v,"input":`, tx.Fee, tx.GasLimit)), w, n, err) + wire.WriteTo([]byte(Fmt(`{"chain_id":%s`, jsonEscape(chainID))), w, n, err) + wire.WriteTo([]byte(Fmt(`,"tx":[%v,{"address":"%X","data":"%X"`, TxTypeCall, tx.Address, tx.Data)), w, n, err) + wire.WriteTo([]byte(Fmt(`,"fee":%v,"gas_limit":%v,"input":`, tx.Fee, tx.GasLimit)), w, n, err) tx.Input.WriteSignBytes(w, n, err) - binary.WriteTo([]byte(`}]}`), w, n, err) + wire.WriteTo([]byte(`}]}`), w, n, err) } func (tx *CallTx) String() string { @@ -190,12 +199,12 @@ type NameTx struct { } func (tx *NameTx) WriteSignBytes(chainID string, w io.Writer, n *int64, err *error) { - binary.WriteTo([]byte(Fmt(`{"chain_id":%s`, jsonEscape(chainID))), w, n, err) - binary.WriteTo([]byte(Fmt(`,"tx":[%v,{"data":%s,"fee":%v`, TxTypeName, jsonEscape(tx.Data), tx.Fee)), w, n, err) - binary.WriteTo([]byte(`,"input":`), w, n, err) + wire.WriteTo([]byte(Fmt(`{"chain_id":%s`, jsonEscape(chainID))), w, n, err) + wire.WriteTo([]byte(Fmt(`,"tx":[%v,{"data":%s,"fee":%v`, TxTypeName, jsonEscape(tx.Data), tx.Fee)), w, n, err) + wire.WriteTo([]byte(`,"input":`), w, n, err) tx.Input.WriteSignBytes(w, n, err) - binary.WriteTo([]byte(Fmt(`,"name":%s`, jsonEscape(tx.Name))), w, n, err) - binary.WriteTo([]byte(`}]}`), w, n, err) + wire.WriteTo([]byte(Fmt(`,"name":%s`, jsonEscape(tx.Name))), w, n, err) + wire.WriteTo([]byte(`}]}`), w, n, err) } func (tx *NameTx) ValidateStrings() error { @@ -231,31 +240,31 @@ func (tx *NameTx) String() string { //----------------------------------------------------------------------------- type BondTx struct { - PubKey account.PubKeyEd25519 `json:"pub_key"` - Signature account.SignatureEd25519 `json:"signature"` - Inputs []*TxInput `json:"inputs"` - UnbondTo []*TxOutput `json:"unbond_to"` + PubKey acm.PubKeyEd25519 `json:"pub_key"` + Signature acm.SignatureEd25519 `json:"signature"` + Inputs []*TxInput `json:"inputs"` + UnbondTo []*TxOutput `json:"unbond_to"` } func (tx *BondTx) WriteSignBytes(chainID string, w io.Writer, n *int64, err *error) { - binary.WriteTo([]byte(Fmt(`{"chain_id":%s`, jsonEscape(chainID))), w, n, err) - binary.WriteTo([]byte(Fmt(`,"tx":[%v,{"inputs":[`, TxTypeBond)), w, n, err) + wire.WriteTo([]byte(Fmt(`{"chain_id":%s`, jsonEscape(chainID))), w, n, err) + wire.WriteTo([]byte(Fmt(`,"tx":[%v,{"inputs":[`, TxTypeBond)), w, n, err) for i, in := range tx.Inputs { in.WriteSignBytes(w, n, err) if i != len(tx.Inputs)-1 { - binary.WriteTo([]byte(","), w, n, err) + wire.WriteTo([]byte(","), w, n, err) } } - binary.WriteTo([]byte(Fmt(`],"pub_key":`)), w, n, err) - binary.WriteTo(binary.JSONBytes(tx.PubKey), w, n, err) - binary.WriteTo([]byte(`,"unbond_to":[`), w, n, err) + wire.WriteTo([]byte(Fmt(`],"pub_key":`)), w, n, err) + wire.WriteTo(wire.JSONBytes(tx.PubKey), w, n, err) + wire.WriteTo([]byte(`,"unbond_to":[`), w, n, err) for i, out := range tx.UnbondTo { out.WriteSignBytes(w, n, err) if i != len(tx.UnbondTo)-1 { - binary.WriteTo([]byte(","), w, n, err) + wire.WriteTo([]byte(","), w, n, err) } } - binary.WriteTo([]byte(`]}]}`), w, n, err) + wire.WriteTo([]byte(`]}]}`), w, n, err) } func (tx *BondTx) String() string { @@ -265,14 +274,14 @@ func (tx *BondTx) String() string { //----------------------------------------------------------------------------- type UnbondTx struct { - Address []byte `json:"address"` - Height int `json:"height"` - Signature account.SignatureEd25519 `json:"signature"` + Address []byte `json:"address"` + Height int `json:"height"` + Signature acm.SignatureEd25519 `json:"signature"` } func (tx *UnbondTx) WriteSignBytes(chainID string, w io.Writer, n *int64, err *error) { - binary.WriteTo([]byte(Fmt(`{"chain_id":%s`, jsonEscape(chainID))), w, n, err) - binary.WriteTo([]byte(Fmt(`,"tx":[%v,{"address":"%X","height":%v}]}`, TxTypeUnbond, tx.Address, tx.Height)), w, n, err) + wire.WriteTo([]byte(Fmt(`{"chain_id":%s`, jsonEscape(chainID))), w, n, err) + wire.WriteTo([]byte(Fmt(`,"tx":[%v,{"address":"%X","height":%v}]}`, TxTypeUnbond, tx.Address, tx.Height)), w, n, err) } func (tx *UnbondTx) String() string { @@ -282,14 +291,14 @@ func (tx *UnbondTx) String() string { //----------------------------------------------------------------------------- type RebondTx struct { - Address []byte `json:"address"` - Height int `json:"height"` - Signature account.SignatureEd25519 `json:"signature"` + Address []byte `json:"address"` + Height int `json:"height"` + Signature acm.SignatureEd25519 `json:"signature"` } func (tx *RebondTx) WriteSignBytes(chainID string, w io.Writer, n *int64, err *error) { - binary.WriteTo([]byte(Fmt(`{"chain_id":%s`, jsonEscape(chainID))), w, n, err) - binary.WriteTo([]byte(Fmt(`,"tx":[%v,{"address":"%X","height":%v}]}`, TxTypeRebond, tx.Address, tx.Height)), w, n, err) + wire.WriteTo([]byte(Fmt(`{"chain_id":%s`, jsonEscape(chainID))), w, n, err) + wire.WriteTo([]byte(Fmt(`,"tx":[%v,{"address":"%X","height":%v}]}`, TxTypeRebond, tx.Address, tx.Height)), w, n, err) } func (tx *RebondTx) String() string { @@ -305,7 +314,7 @@ type DupeoutTx struct { } func (tx *DupeoutTx) WriteSignBytes(chainID string, w io.Writer, n *int64, err *error) { - panic("DupeoutTx has no sign bytes") + PanicSanity("DupeoutTx has no sign bytes") } func (tx *DupeoutTx) String() string { @@ -314,10 +323,30 @@ func (tx *DupeoutTx) String() string { //----------------------------------------------------------------------------- +type PermissionsTx struct { + Input *TxInput `json:"input"` + PermArgs ptypes.PermArgs `json:"args"` +} + +func (tx *PermissionsTx) WriteSignBytes(chainID string, w io.Writer, n *int64, err *error) { + wire.WriteTo([]byte(Fmt(`{"chain_id":%s`, jsonEscape(chainID))), w, n, err) + wire.WriteTo([]byte(Fmt(`,"tx":[%v,{"args":"`, TxTypePermissions)), w, n, err) + wire.WriteJSON(tx.PermArgs, w, n, err) + wire.WriteTo([]byte(`","input":`), w, n, err) + tx.Input.WriteSignBytes(w, n, err) + wire.WriteTo([]byte(`}]}`), w, n, err) +} + +func (tx *PermissionsTx) String() string { + return Fmt("PermissionsTx{%v -> %v}", tx.Input, tx.PermArgs) +} + +//----------------------------------------------------------------------------- + // This should match the leaf hashes of Block.Data.Hash()'s SimpleMerkleTree. func TxID(chainID string, tx Tx) []byte { - signBytes := account.SignBytes(chainID, tx) - return binary.BinaryRipemd160(signBytes) + signBytes := acm.SignBytes(chainID, tx) + return wire.BinaryRipemd160(signBytes) } //-------------------------------------------------------------------------------- @@ -326,7 +355,7 @@ func TxID(chainID string, tx Tx) []byte { func jsonEscape(str string) string { escapedBytes, err := json.Marshal(str) if err != nil { - panic(Fmt("Error json-escaping a string", str)) + PanicSanity(Fmt("Error json-escaping a string", str)) } return string(escapedBytes) } diff --git a/Godeps/_workspace/src/github.com/tendermint/tendermint/types/tx_test.go b/Godeps/_workspace/src/github.com/tendermint/tendermint/types/tx_test.go index c98b70d2..a15785cb 100644 --- a/Godeps/_workspace/src/github.com/tendermint/tendermint/types/tx_test.go +++ b/Godeps/_workspace/src/github.com/tendermint/tendermint/types/tx_test.go @@ -3,9 +3,10 @@ package types import ( "testing" - "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/account" + acm "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/account" . "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/common" _ "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/config/tendermint_test" + ptypes "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/permission/types" ) var chainID string @@ -39,7 +40,7 @@ func TestSendTxSignable(t *testing.T) { }, }, } - signBytes := account.SignBytes(chainID, sendTx) + signBytes := acm.SignBytes(chainID, sendTx) signStr := string(signBytes) expected := Fmt(`{"chain_id":"%s","tx":[1,{"inputs":[{"address":"696E70757431","amount":12345,"sequence":67890},{"address":"696E70757432","amount":111,"sequence":222}],"outputs":[{"address":"6F757470757431","amount":333},{"address":"6F757470757432","amount":444}]}]}`, config.GetString("chain_id")) @@ -60,7 +61,7 @@ func TestCallTxSignable(t *testing.T) { Fee: 222, Data: []byte("data1"), } - signBytes := account.SignBytes(chainID, callTx) + signBytes := acm.SignBytes(chainID, callTx) signStr := string(signBytes) expected := Fmt(`{"chain_id":"%s","tx":[2,{"address":"636F6E747261637431","data":"6461746131","fee":222,"gas_limit":111,"input":{"address":"696E70757431","amount":12345,"sequence":67890}}]}`, config.GetString("chain_id")) @@ -69,10 +70,33 @@ func TestCallTxSignable(t *testing.T) { } } +func TestNameTxSignable(t *testing.T) { + nameTx := &NameTx{ + Input: &TxInput{ + Address: []byte("input1"), + Amount: 12345, + Sequence: 250, + }, + Name: "google.com", + Data: "secretly.not.google.com", + Fee: 1000, + } + signBytes := acm.SignBytes(chainID, nameTx) + signStr := string(signBytes) + expected := Fmt(`{"chain_id":"%s","tx":[3,{"data":"secretly.not.google.com","fee":1000,"input":{"address":"696E70757431","amount":12345,"sequence":250},"name":"google.com"}]}`, + config.GetString("chain_id")) + if signStr != expected { + t.Errorf("Got unexpected sign string for CallTx. Expected:\n%v\nGot:\n%v", expected, signStr) + } +} + func TestBondTxSignable(t *testing.T) { - privAccount := account.GenPrivAccountFromPrivKeyBytes(make([]byte, 64)) + privKeyBytes := make([]byte, 64) + var privKeyArray [64]byte + copy(privKeyArray[:], privKeyBytes) + privAccount := acm.GenPrivAccountFromPrivKeyBytes(&privKeyArray) bondTx := &BondTx{ - PubKey: privAccount.PubKey.(account.PubKeyEd25519), + PubKey: privAccount.PubKey.(acm.PubKeyEd25519), Inputs: []*TxInput{ &TxInput{ Address: []byte("input1"), @@ -96,12 +120,12 @@ func TestBondTxSignable(t *testing.T) { }, }, } - signBytes := account.SignBytes(chainID, bondTx) + signBytes := acm.SignBytes(chainID, bondTx) signStr := string(signBytes) expected := Fmt(`{"chain_id":"%s","tx":[17,{"inputs":[{"address":"696E70757431","amount":12345,"sequence":67890},{"address":"696E70757432","amount":111,"sequence":222}],"pub_key":[1,"3B6A27BCCEB6A42D62A3A8D02A6F0D73653215771DE243A63AC048A18B59DA29"],"unbond_to":[{"address":"6F757470757431","amount":333},{"address":"6F757470757432","amount":444}]}]}`, config.GetString("chain_id")) if signStr != expected { - t.Errorf("Got unexpected sign string for BondTx") + t.Errorf("Unexpected sign string for BondTx. \nGot %s\nExpected %s", signStr, expected) } } @@ -110,7 +134,7 @@ func TestUnbondTxSignable(t *testing.T) { Address: []byte("address1"), Height: 111, } - signBytes := account.SignBytes(chainID, unbondTx) + signBytes := acm.SignBytes(chainID, unbondTx) signStr := string(signBytes) expected := Fmt(`{"chain_id":"%s","tx":[18,{"address":"6164647265737331","height":111}]}`, config.GetString("chain_id")) @@ -124,7 +148,7 @@ func TestRebondTxSignable(t *testing.T) { Address: []byte("address1"), Height: 111, } - signBytes := account.SignBytes(chainID, rebondTx) + signBytes := acm.SignBytes(chainID, rebondTx) signStr := string(signBytes) expected := Fmt(`{"chain_id":"%s","tx":[19,{"address":"6164647265737331","height":111}]}`, config.GetString("chain_id")) @@ -132,3 +156,25 @@ func TestRebondTxSignable(t *testing.T) { t.Errorf("Got unexpected sign string for RebondTx") } } + +func TestPermissionsTxSignable(t *testing.T) { + permsTx := &PermissionsTx{ + Input: &TxInput{ + Address: []byte("input1"), + Amount: 12345, + Sequence: 250, + }, + PermArgs: &ptypes.SetBaseArgs{ + Address: []byte("address1"), + Permission: 1, + Value: true, + }, + } + signBytes := acm.SignBytes(chainID, permsTx) + signStr := string(signBytes) + expected := Fmt(`{"chain_id":"%s","tx":[32,{"args":"[2,{"address":"6164647265737331","permission":1,"value":true}]","input":{"address":"696E70757431","amount":12345,"sequence":250}}]}`, + config.GetString("chain_id")) + if signStr != expected { + t.Errorf("Got unexpected sign string for CallTx. Expected:\n%v\nGot:\n%v", expected, signStr) + } +} diff --git a/Godeps/_workspace/src/github.com/tendermint/tendermint/types/tx_utils.go b/Godeps/_workspace/src/github.com/tendermint/tendermint/types/tx_utils.go index e0bc09e1..225c445e 100644 --- a/Godeps/_workspace/src/github.com/tendermint/tendermint/types/tx_utils.go +++ b/Godeps/_workspace/src/github.com/tendermint/tendermint/types/tx_utils.go @@ -2,11 +2,12 @@ package types import ( "fmt" - "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/account" + acm "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/account" + ptypes "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/permission/types" ) type AccountGetter interface { - GetAccount(addr []byte) *account.Account + GetAccount(addr []byte) *acm.Account } //---------------------------------------------------------------------------- @@ -19,7 +20,7 @@ func NewSendTx() *SendTx { } } -func (tx *SendTx) AddInput(st AccountGetter, pubkey account.PubKey, amt int64) error { +func (tx *SendTx) AddInput(st AccountGetter, pubkey acm.PubKey, amt int64) error { addr := pubkey.Address() acc := st.GetAccount(addr) if acc == nil { @@ -28,13 +29,13 @@ func (tx *SendTx) AddInput(st AccountGetter, pubkey account.PubKey, amt int64) e return tx.AddInputWithNonce(pubkey, amt, acc.Sequence+1) } -func (tx *SendTx) AddInputWithNonce(pubkey account.PubKey, amt int64, nonce int) error { +func (tx *SendTx) AddInputWithNonce(pubkey acm.PubKey, amt int64, nonce int) error { addr := pubkey.Address() tx.Inputs = append(tx.Inputs, &TxInput{ Address: addr, Amount: amt, Sequence: nonce, - Signature: account.SignatureEd25519{}, + Signature: acm.SignatureEd25519{}, PubKey: pubkey, }) return nil @@ -48,7 +49,7 @@ func (tx *SendTx) AddOutput(addr []byte, amt int64) error { return nil } -func (tx *SendTx) SignInput(chainID string, i int, privAccount *account.PrivAccount) error { +func (tx *SendTx) SignInput(chainID string, i int, privAccount *acm.PrivAccount) error { if i >= len(tx.Inputs) { return fmt.Errorf("Index %v is greater than number of inputs (%v)", i, len(tx.Inputs)) } @@ -60,7 +61,7 @@ func (tx *SendTx) SignInput(chainID string, i int, privAccount *account.PrivAcco //---------------------------------------------------------------------------- // CallTx interface for creating tx -func NewCallTx(st AccountGetter, from account.PubKey, to, data []byte, amt, gasLimit, fee int64) (*CallTx, error) { +func NewCallTx(st AccountGetter, from acm.PubKey, to, data []byte, amt, gasLimit, fee int64) (*CallTx, error) { addr := from.Address() acc := st.GetAccount(addr) if acc == nil { @@ -71,13 +72,13 @@ func NewCallTx(st AccountGetter, from account.PubKey, to, data []byte, amt, gasL return NewCallTxWithNonce(from, to, data, amt, gasLimit, fee, nonce), nil } -func NewCallTxWithNonce(from account.PubKey, to, data []byte, amt, gasLimit, fee int64, nonce int) *CallTx { +func NewCallTxWithNonce(from acm.PubKey, to, data []byte, amt, gasLimit, fee int64, nonce int) *CallTx { addr := from.Address() input := &TxInput{ Address: addr, Amount: amt, Sequence: nonce, - Signature: account.SignatureEd25519{}, + Signature: acm.SignatureEd25519{}, PubKey: from, } @@ -90,7 +91,7 @@ func NewCallTxWithNonce(from account.PubKey, to, data []byte, amt, gasLimit, fee } } -func (tx *CallTx) Sign(chainID string, privAccount *account.PrivAccount) { +func (tx *CallTx) Sign(chainID string, privAccount *acm.PrivAccount) { tx.Input.PubKey = privAccount.PubKey tx.Input.Signature = privAccount.Sign(chainID, tx) } @@ -98,7 +99,7 @@ func (tx *CallTx) Sign(chainID string, privAccount *account.PrivAccount) { //---------------------------------------------------------------------------- // NameTx interface for creating tx -func NewNameTx(st AccountGetter, from account.PubKey, name, data string, amt, fee int64) (*NameTx, error) { +func NewNameTx(st AccountGetter, from acm.PubKey, name, data string, amt, fee int64) (*NameTx, error) { addr := from.Address() acc := st.GetAccount(addr) if acc == nil { @@ -109,13 +110,13 @@ func NewNameTx(st AccountGetter, from account.PubKey, name, data string, amt, fe return NewNameTxWithNonce(from, name, data, amt, fee, nonce), nil } -func NewNameTxWithNonce(from account.PubKey, name, data string, amt, fee int64, nonce int) *NameTx { +func NewNameTxWithNonce(from acm.PubKey, name, data string, amt, fee int64, nonce int) *NameTx { addr := from.Address() input := &TxInput{ Address: addr, Amount: amt, Sequence: nonce, - Signature: account.SignatureEd25519{}, + Signature: acm.SignatureEd25519{}, PubKey: from, } @@ -127,7 +128,7 @@ func NewNameTxWithNonce(from account.PubKey, name, data string, amt, fee int64, } } -func (tx *NameTx) Sign(chainID string, privAccount *account.PrivAccount) { +func (tx *NameTx) Sign(chainID string, privAccount *acm.PrivAccount) { tx.Input.PubKey = privAccount.PubKey tx.Input.Signature = privAccount.Sign(chainID, tx) } @@ -135,8 +136,8 @@ func (tx *NameTx) Sign(chainID string, privAccount *account.PrivAccount) { //---------------------------------------------------------------------------- // BondTx interface for adding inputs/outputs and adding signatures -func NewBondTx(pubkey account.PubKey) (*BondTx, error) { - pubkeyEd, ok := pubkey.(account.PubKeyEd25519) +func NewBondTx(pubkey acm.PubKey) (*BondTx, error) { + pubkeyEd, ok := pubkey.(acm.PubKeyEd25519) if !ok { return nil, fmt.Errorf("Pubkey must be ed25519") } @@ -147,7 +148,7 @@ func NewBondTx(pubkey account.PubKey) (*BondTx, error) { }, nil } -func (tx *BondTx) AddInput(st AccountGetter, pubkey account.PubKey, amt int64) error { +func (tx *BondTx) AddInput(st AccountGetter, pubkey acm.PubKey, amt int64) error { addr := pubkey.Address() acc := st.GetAccount(addr) if acc == nil { @@ -156,13 +157,13 @@ func (tx *BondTx) AddInput(st AccountGetter, pubkey account.PubKey, amt int64) e return tx.AddInputWithNonce(pubkey, amt, acc.Sequence+1) } -func (tx *BondTx) AddInputWithNonce(pubkey account.PubKey, amt int64, nonce int) error { +func (tx *BondTx) AddInputWithNonce(pubkey acm.PubKey, amt int64, nonce int) error { addr := pubkey.Address() tx.Inputs = append(tx.Inputs, &TxInput{ Address: addr, Amount: amt, Sequence: nonce, - Signature: account.SignatureEd25519{}, + Signature: acm.SignatureEd25519{}, PubKey: pubkey, }) return nil @@ -176,9 +177,9 @@ func (tx *BondTx) AddOutput(addr []byte, amt int64) error { return nil } -func (tx *BondTx) SignBond(chainID string, privAccount *account.PrivAccount) error { +func (tx *BondTx) SignBond(chainID string, privAccount *acm.PrivAccount) error { sig := privAccount.Sign(chainID, tx) - sigEd, ok := sig.(account.SignatureEd25519) + sigEd, ok := sig.(acm.SignatureEd25519) if !ok { return fmt.Errorf("Bond signer must be ED25519") } @@ -186,7 +187,7 @@ func (tx *BondTx) SignBond(chainID string, privAccount *account.PrivAccount) err return nil } -func (tx *BondTx) SignInput(chainID string, i int, privAccount *account.PrivAccount) error { +func (tx *BondTx) SignInput(chainID string, i int, privAccount *acm.PrivAccount) error { if i >= len(tx.Inputs) { return fmt.Errorf("Index %v is greater than number of inputs (%v)", i, len(tx.Inputs)) } @@ -205,8 +206,8 @@ func NewUnbondTx(addr []byte, height int) *UnbondTx { } } -func (tx *UnbondTx) Sign(chainID string, privAccount *account.PrivAccount) { - tx.Signature = privAccount.Sign(chainID, tx).(account.SignatureEd25519) +func (tx *UnbondTx) Sign(chainID string, privAccount *acm.PrivAccount) { + tx.Signature = privAccount.Sign(chainID, tx).(acm.SignatureEd25519) } //---------------------------------------------------------------------- @@ -219,6 +220,41 @@ func NewRebondTx(addr []byte, height int) *RebondTx { } } -func (tx *RebondTx) Sign(chainID string, privAccount *account.PrivAccount) { - tx.Signature = privAccount.Sign(chainID, tx).(account.SignatureEd25519) +func (tx *RebondTx) Sign(chainID string, privAccount *acm.PrivAccount) { + tx.Signature = privAccount.Sign(chainID, tx).(acm.SignatureEd25519) +} + +//---------------------------------------------------------------------------- +// PermissionsTx interface for creating tx + +func NewPermissionsTx(st AccountGetter, from acm.PubKey, args ptypes.PermArgs) (*PermissionsTx, error) { + addr := from.Address() + acc := st.GetAccount(addr) + if acc == nil { + return nil, fmt.Errorf("Invalid address %X from pubkey %X", addr, from) + } + + nonce := acc.Sequence + 1 + return NewPermissionsTxWithNonce(from, args, nonce), nil +} + +func NewPermissionsTxWithNonce(from acm.PubKey, args ptypes.PermArgs, nonce int) *PermissionsTx { + addr := from.Address() + input := &TxInput{ + Address: addr, + Amount: 1, // NOTE: amounts can't be 0 ... + Sequence: nonce, + Signature: acm.SignatureEd25519{}, + PubKey: from, + } + + return &PermissionsTx{ + Input: input, + PermArgs: args, + } +} + +func (tx *PermissionsTx) Sign(chainID string, privAccount *acm.PrivAccount) { + tx.Input.PubKey = privAccount.PubKey + tx.Input.Signature = privAccount.Sign(chainID, tx) } diff --git a/Godeps/_workspace/src/github.com/tendermint/tendermint/types/vote.go b/Godeps/_workspace/src/github.com/tendermint/tendermint/types/vote.go index acacbcee..776ab7d2 100644 --- a/Godeps/_workspace/src/github.com/tendermint/tendermint/types/vote.go +++ b/Godeps/_workspace/src/github.com/tendermint/tendermint/types/vote.go @@ -5,9 +5,9 @@ import ( "fmt" "io" - "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/account" - "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/binary" + acm "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/account" . "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/common" + "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/wire" ) var ( @@ -28,12 +28,12 @@ func (err *ErrVoteConflictingSignature) Error() string { // Represents a prevote, precommit, or commit vote from validators for consensus. type Vote struct { - Height int `json:"height"` - Round int `json:"round"` - Type byte `json:"type"` - BlockHash []byte `json:"block_hash"` // empty if vote is nil. - BlockParts PartSetHeader `json:"block_parts"` // zero if vote is nil. - Signature account.SignatureEd25519 `json:"signature"` + Height int `json:"height"` + Round int `json:"round"` + Type byte `json:"type"` + BlockHash []byte `json:"block_hash"` // empty if vote is nil. + BlockParts PartSetHeader `json:"block_parts"` // zero if vote is nil. + Signature acm.SignatureEd25519 `json:"signature"` } // Types of votes @@ -43,9 +43,9 @@ const ( ) func (vote *Vote) WriteSignBytes(chainID string, w io.Writer, n *int64, err *error) { - binary.WriteTo([]byte(Fmt(`{"chain_id":"%s"`, chainID)), w, n, err) - binary.WriteTo([]byte(Fmt(`,"vote":{"block_hash":"%X","block_parts":%v`, vote.BlockHash, vote.BlockParts)), w, n, err) - binary.WriteTo([]byte(Fmt(`,"height":%v,"round":%v,"type":%v}}`, vote.Height, vote.Round, vote.Type)), w, n, err) + wire.WriteTo([]byte(Fmt(`{"chain_id":"%s"`, chainID)), w, n, err) + wire.WriteTo([]byte(Fmt(`,"vote":{"block_hash":"%X","block_parts":%v`, vote.BlockHash, vote.BlockParts)), w, n, err) + wire.WriteTo([]byte(Fmt(`,"height":%v,"round":%v,"type":%v}}`, vote.Height, vote.Round, vote.Type)), w, n, err) } func (vote *Vote) Copy() *Vote { @@ -64,7 +64,7 @@ func (vote *Vote) String() string { case VoteTypePrecommit: typeString = "Precommit" default: - panic("Unknown vote type") + PanicSanity("Unknown vote type") } return fmt.Sprintf("Vote{%v/%02d/%v(%v) %X#%v %v}", vote.Height, vote.Round, vote.Type, typeString, Fingerprint(vote.BlockHash), vote.BlockParts, vote.Signature) diff --git a/Godeps/_workspace/src/github.com/tendermint/tendermint/vm/gas.go b/Godeps/_workspace/src/github.com/tendermint/tendermint/vm/gas.go index dac978f1..fe4a43d8 100644 --- a/Godeps/_workspace/src/github.com/tendermint/tendermint/vm/gas.go +++ b/Godeps/_workspace/src/github.com/tendermint/tendermint/vm/gas.go @@ -5,6 +5,7 @@ const ( GasGetAccount int64 = 1 GasStorageUpdate int64 = 1 + GasBaseOp int64 = 0 // TODO: make this 1 GasStackOp int64 = 1 GasEcRecover int64 = 1 diff --git a/Godeps/_workspace/src/github.com/tendermint/tendermint/vm/native.go b/Godeps/_workspace/src/github.com/tendermint/tendermint/vm/native.go index 82937344..e0a73bd6 100644 --- a/Godeps/_workspace/src/github.com/tendermint/tendermint/vm/native.go +++ b/Godeps/_workspace/src/github.com/tendermint/tendermint/vm/native.go @@ -8,20 +8,30 @@ import ( "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/vm/sha3" ) -var nativeContracts = make(map[Word256]NativeContract) +var registeredNativeContracts = make(map[Word256]NativeContract) + +func RegisteredNativeContract(addr Word256) bool { + _, ok := registeredNativeContracts[addr] + return ok +} func init() { - nativeContracts[Int64ToWord256(1)] = ecrecoverFunc - nativeContracts[Int64ToWord256(2)] = sha256Func - nativeContracts[Int64ToWord256(3)] = ripemd160Func - nativeContracts[Int64ToWord256(4)] = identityFunc + registerNativeContracts() + registerSNativeContracts() +} + +func registerNativeContracts() { + registeredNativeContracts[Int64ToWord256(1)] = ecrecoverFunc + registeredNativeContracts[Int64ToWord256(2)] = sha256Func + registeredNativeContracts[Int64ToWord256(3)] = ripemd160Func + registeredNativeContracts[Int64ToWord256(4)] = identityFunc } //----------------------------------------------------------------------------- -type NativeContract func(input []byte, gas *int64) (output []byte, err error) +type NativeContract func(appState AppState, caller *Account, input []byte, gas *int64) (output []byte, err error) -func ecrecoverFunc(input []byte, gas *int64) (output []byte, err error) { +func ecrecoverFunc(appState AppState, caller *Account, input []byte, gas *int64) (output []byte, err error) { // Deduct gas gasRequired := GasEcRecover if *gas < gasRequired { @@ -42,7 +52,7 @@ func ecrecoverFunc(input []byte, gas *int64) (output []byte, err error) { return LeftPadBytes(hashed, 32), nil } -func sha256Func(input []byte, gas *int64) (output []byte, err error) { +func sha256Func(appState AppState, caller *Account, input []byte, gas *int64) (output []byte, err error) { // Deduct gas gasRequired := int64((len(input)+31)/32)*GasSha256Word + GasSha256Base if *gas < gasRequired { @@ -57,7 +67,7 @@ func sha256Func(input []byte, gas *int64) (output []byte, err error) { return hasher.Sum(nil), nil } -func ripemd160Func(input []byte, gas *int64) (output []byte, err error) { +func ripemd160Func(appState AppState, caller *Account, input []byte, gas *int64) (output []byte, err error) { // Deduct gas gasRequired := int64((len(input)+31)/32)*GasRipemd160Word + GasRipemd160Base if *gas < gasRequired { @@ -72,7 +82,7 @@ func ripemd160Func(input []byte, gas *int64) (output []byte, err error) { return LeftPadBytes(hasher.Sum(nil), 32), nil } -func identityFunc(input []byte, gas *int64) (output []byte, err error) { +func identityFunc(appState AppState, caller *Account, input []byte, gas *int64) (output []byte, err error) { // Deduct gas gasRequired := int64((len(input)+31)/32)*GasIdentityWord + GasIdentityBase if *gas < gasRequired { diff --git a/Godeps/_workspace/src/github.com/tendermint/tendermint/vm/snative.go b/Godeps/_workspace/src/github.com/tendermint/tendermint/vm/snative.go index 8a9f2fd8..a9a5c9ee 100644 --- a/Godeps/_workspace/src/github.com/tendermint/tendermint/vm/snative.go +++ b/Godeps/_workspace/src/github.com/tendermint/tendermint/vm/snative.go @@ -7,36 +7,31 @@ import ( ptypes "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/permission/types" ) +// TODO: ABI //------------------------------------------------------------------------------------------------ // Registered SNative contracts -var RegisteredSNativeContracts = map[Word256]SNativeContract{ - LeftPadWord256([]byte("hasBasePerm")): hasBasePerm, - LeftPadWord256([]byte("setBasePerm")): setBasePerm, - LeftPadWord256([]byte("unsetBasePerm")): unsetBasePerm, - LeftPadWord256([]byte("setGlobalPerm")): setGlobalPerm, - LeftPadWord256([]byte("hasRole")): hasRole, - LeftPadWord256([]byte("addRole")): addRole, - LeftPadWord256([]byte("rmRole")): rmRole, +func registerSNativeContracts() { + registeredNativeContracts[LeftPadWord256([]byte("has_base"))] = hasBasePerm + registeredNativeContracts[LeftPadWord256([]byte("set_base"))] = setBasePerm + registeredNativeContracts[LeftPadWord256([]byte("unset_base"))] = unsetBasePerm + registeredNativeContracts[LeftPadWord256([]byte("set_global"))] = setGlobalPerm + registeredNativeContracts[LeftPadWord256([]byte("has_role"))] = hasRole + registeredNativeContracts[LeftPadWord256([]byte("add_role"))] = addRole + registeredNativeContracts[LeftPadWord256([]byte("rm_role"))] = rmRole } -// Takes an appState so it can lookup/update accounts, -// an account to check for permission to access the snative contract -// and some input bytes (presumably 32byte words) -type SNativeContract func(appState AppState, acc *Account, input []byte) (output []byte, err error) - //----------------------------------------------------------------------------- -// snative are native contracts that can access and manipulate the chain state -// (in particular the permissions values) +// snative are native contracts that can access and modify an account's permissions // TODO: catch errors, log em, return 0s to the vm (should some errors cause exceptions though?) -func hasBasePerm(appState AppState, acc *Account, args []byte) (output []byte, err error) { - if !HasPermission(appState, acc, ptypes.HasBasePerm) { - return nil, ErrInvalidPermission{acc.Address, "HasBasePerm"} +func hasBasePerm(appState AppState, caller *Account, args []byte, gas *int64) (output []byte, err error) { + if !HasPermission(appState, caller, ptypes.HasBase) { + return nil, ErrInvalidPermission{caller.Address, "has_base"} } if len(args) != 2*32 { - return nil, fmt.Errorf("hasBasePerm() takes two arguments (address, permission number)") + return nil, fmt.Errorf("hasBasePerm() takes two arguments (address, permFlag)") } addr, permNum := returnTwoArgs(args) vmAcc := appState.GetAccount(addr) @@ -57,12 +52,12 @@ func hasBasePerm(appState AppState, acc *Account, args []byte) (output []byte, e return LeftPadWord256([]byte{permInt}).Bytes(), nil } -func setBasePerm(appState AppState, acc *Account, args []byte) (output []byte, err error) { - if !HasPermission(appState, acc, ptypes.SetBasePerm) { - return nil, ErrInvalidPermission{acc.Address, "SetBasePerm"} +func setBasePerm(appState AppState, caller *Account, args []byte, gas *int64) (output []byte, err error) { + if !HasPermission(appState, caller, ptypes.SetBase) { + return nil, ErrInvalidPermission{caller.Address, "set_base"} } if len(args) != 3*32 { - return nil, fmt.Errorf("setBasePerm() takes three arguments (address, permission number, permission value)") + return nil, fmt.Errorf("setBase() takes three arguments (address, permFlag, permission value)") } addr, permNum, perm := returnThreeArgs(args) vmAcc := appState.GetAccount(addr) @@ -82,12 +77,12 @@ func setBasePerm(appState AppState, acc *Account, args []byte) (output []byte, e return perm.Bytes(), nil } -func unsetBasePerm(appState AppState, acc *Account, args []byte) (output []byte, err error) { - if !HasPermission(appState, acc, ptypes.UnsetBasePerm) { - return nil, ErrInvalidPermission{acc.Address, "UnsetBasePerm"} +func unsetBasePerm(appState AppState, caller *Account, args []byte, gas *int64) (output []byte, err error) { + if !HasPermission(appState, caller, ptypes.UnsetBase) { + return nil, ErrInvalidPermission{caller.Address, "unset_base"} } if len(args) != 2*32 { - return nil, fmt.Errorf("unsetBasePerm() takes two arguments (address, permission number)") + return nil, fmt.Errorf("unsetBase() takes two arguments (address, permFlag)") } addr, permNum := returnTwoArgs(args) vmAcc := appState.GetAccount(addr) @@ -106,17 +101,17 @@ func unsetBasePerm(appState AppState, acc *Account, args []byte) (output []byte, return permNum.Bytes(), nil } -func setGlobalPerm(appState AppState, acc *Account, args []byte) (output []byte, err error) { - if !HasPermission(appState, acc, ptypes.SetGlobalPerm) { - return nil, ErrInvalidPermission{acc.Address, "SetGlobalPerm"} +func setGlobalPerm(appState AppState, caller *Account, args []byte, gas *int64) (output []byte, err error) { + if !HasPermission(appState, caller, ptypes.SetGlobal) { + return nil, ErrInvalidPermission{caller.Address, "set_global"} } if len(args) != 2*32 { - return nil, fmt.Errorf("setGlobalPerm() takes two arguments (permission number, permission value)") + return nil, fmt.Errorf("setGlobal() takes two arguments (permFlag, permission value)") } permNum, perm := returnTwoArgs(args) vmAcc := appState.GetAccount(ptypes.GlobalPermissionsAddress256) if vmAcc == nil { - panic("cant find the global permissions account") + PanicSanity("cant find the global permissions account") } permN := ptypes.PermFlag(Uint64FromWord256(permNum)) if !ValidPermN(permN) { @@ -131,17 +126,9 @@ func setGlobalPerm(appState AppState, acc *Account, args []byte) (output []byte, return perm.Bytes(), nil } -// TODO: needs access to an iterator ... -func clearPerm(appState AppState, acc *Account, args []byte) (output []byte, err error) { - if !HasPermission(appState, acc, ptypes.ClearBasePerm) { - return nil, ErrInvalidPermission{acc.Address, "ClearPerm"} - } - return nil, nil -} - -func hasRole(appState AppState, acc *Account, args []byte) (output []byte, err error) { - if !HasPermission(appState, acc, ptypes.HasRole) { - return nil, ErrInvalidPermission{acc.Address, "HasRole"} +func hasRole(appState AppState, caller *Account, args []byte, gas *int64) (output []byte, err error) { + if !HasPermission(appState, caller, ptypes.HasRole) { + return nil, ErrInvalidPermission{caller.Address, "has_role"} } if len(args) != 2*32 { return nil, fmt.Errorf("hasRole() takes two arguments (address, role)") @@ -162,9 +149,9 @@ func hasRole(appState AppState, acc *Account, args []byte) (output []byte, err e return LeftPadWord256([]byte{permInt}).Bytes(), nil } -func addRole(appState AppState, acc *Account, args []byte) (output []byte, err error) { - if !HasPermission(appState, acc, ptypes.AddRole) { - return nil, ErrInvalidPermission{acc.Address, "AddRole"} +func addRole(appState AppState, caller *Account, args []byte, gas *int64) (output []byte, err error) { + if !HasPermission(appState, caller, ptypes.AddRole) { + return nil, ErrInvalidPermission{caller.Address, "add_role"} } if len(args) != 2*32 { return nil, fmt.Errorf("addRole() takes two arguments (address, role)") @@ -186,9 +173,9 @@ func addRole(appState AppState, acc *Account, args []byte) (output []byte, err e return LeftPadWord256([]byte{permInt}).Bytes(), nil } -func rmRole(appState AppState, acc *Account, args []byte) (output []byte, err error) { - if !HasPermission(appState, acc, ptypes.RmRole) { - return nil, ErrInvalidPermission{acc.Address, "RmRole"} +func rmRole(appState AppState, caller *Account, args []byte, gas *int64) (output []byte, err error) { + if !HasPermission(appState, caller, ptypes.RmRole) { + return nil, ErrInvalidPermission{caller.Address, "rm_role"} } if len(args) != 2*32 { return nil, fmt.Errorf("rmRole() takes two arguments (address, role)") @@ -224,36 +211,23 @@ func (e ErrInvalidPermission) Error() string { // Checks if a permission flag is valid (a known base chain or snative permission) func ValidPermN(n ptypes.PermFlag) bool { - if n > ptypes.TopBasePermFlag && n < ptypes.FirstSNativePermFlag { - return false - } else if n > ptypes.TopSNativePermFlag { + if n > ptypes.TopPermFlag { return false } return true } -// assumes length has already been checked +// CONTRACT: length has already been checked func returnTwoArgs(args []byte) (a Word256, b Word256) { copy(a[:], args[:32]) copy(b[:], args[32:64]) return } -// assumes length has already been checked +// CONTRACT: length has already been checked func returnThreeArgs(args []byte) (a Word256, b Word256, c Word256) { copy(a[:], args[:32]) copy(b[:], args[32:64]) copy(c[:], args[64:96]) return } - -// mostly a convenience for testing -var RegisteredSNativePermissions = map[Word256]ptypes.PermFlag{ - LeftPadWord256([]byte("hasBasePerm")): ptypes.HasBasePerm, - LeftPadWord256([]byte("setBasePerm")): ptypes.SetBasePerm, - LeftPadWord256([]byte("unsetBasePerm")): ptypes.UnsetBasePerm, - LeftPadWord256([]byte("setGlobalPerm")): ptypes.SetGlobalPerm, - LeftPadWord256([]byte("hasRole")): ptypes.HasRole, - LeftPadWord256([]byte("addRole")): ptypes.AddRole, - LeftPadWord256([]byte("rmRole")): ptypes.RmRole, -} diff --git a/Godeps/_workspace/src/github.com/tendermint/tendermint/vm/stack.go b/Godeps/_workspace/src/github.com/tendermint/tendermint/vm/stack.go index 1a7d3d9d..9667de10 100644 --- a/Godeps/_workspace/src/github.com/tendermint/tendermint/vm/stack.go +++ b/Godeps/_workspace/src/github.com/tendermint/tendermint/vm/stack.go @@ -50,7 +50,7 @@ func (st *Stack) Push(d Word256) { // currently only called after Sha3 func (st *Stack) PushBytes(bz []byte) { if len(bz) != 32 { - panic("Invalid bytes size: expected 32") + PanicSanity("Invalid bytes size: expected 32") } st.Push(LeftPadWord256(bz)) } diff --git a/Godeps/_workspace/src/github.com/tendermint/tendermint/vm/test/fake_app_state.go b/Godeps/_workspace/src/github.com/tendermint/tendermint/vm/test/fake_app_state.go index ca4e72c9..a0a65cf5 100644 --- a/Godeps/_workspace/src/github.com/tendermint/tendermint/vm/test/fake_app_state.go +++ b/Godeps/_workspace/src/github.com/tendermint/tendermint/vm/test/fake_app_state.go @@ -36,11 +36,10 @@ func (fas *FakeAppState) CreateAccount(creator *Account) *Account { account := fas.accounts[addr.String()] if account == nil { return &Account{ - Address: addr, - Balance: 0, - Code: nil, - Nonce: 0, - StorageRoot: Zero256, + Address: addr, + Balance: 0, + Code: nil, + Nonce: 0, } } else { panic(Fmt("Invalid account addr: %X", addr)) diff --git a/Godeps/_workspace/src/github.com/tendermint/tendermint/vm/test/log_event_test.go b/Godeps/_workspace/src/github.com/tendermint/tendermint/vm/test/log_event_test.go index db01cfcc..bb31c603 100644 --- a/Godeps/_workspace/src/github.com/tendermint/tendermint/vm/test/log_event_test.go +++ b/Godeps/_workspace/src/github.com/tendermint/tendermint/vm/test/log_event_test.go @@ -35,7 +35,7 @@ func TestLog4(t *testing.T) { ourVm := NewVM(st, newParams(), Zero256, nil) - eventSwitch := &events.EventSwitch{} + eventSwitch := events.NewEventSwitch() eventSwitch.Start() eventId := types.EventStringLogEvent(account2.Address.Postfix(20)) diff --git a/Godeps/_workspace/src/github.com/tendermint/tendermint/vm/test/vm_test.go b/Godeps/_workspace/src/github.com/tendermint/tendermint/vm/test/vm_test.go index f5de60f3..684d7324 100644 --- a/Godeps/_workspace/src/github.com/tendermint/tendermint/vm/test/vm_test.go +++ b/Godeps/_workspace/src/github.com/tendermint/tendermint/vm/test/vm_test.go @@ -151,14 +151,14 @@ func TestSendCall(t *testing.T) { } } -// subscribes to an AccReceive, runs the vm, returns the exception +// subscribes to an AccCall, runs the vm, returns the exception func runVMWaitEvents(t *testing.T, ourVm *VM, caller, callee *Account, subscribeAddr, contractCode []byte, gas int64) string { // we need to catch the event from the CALL to check for exceptions - evsw := new(events.EventSwitch) + evsw := events.NewEventSwitch() evsw.Start() ch := make(chan interface{}) fmt.Printf("subscribe to %x\n", subscribeAddr) - evsw.AddListenerForEvent("test", types.EventStringAccReceive(subscribeAddr), func(msg interface{}) { + evsw.AddListenerForEvent("test", types.EventStringAccCall(subscribeAddr), func(msg interface{}) { ch <- msg }) evc := events.NewEventCache(evsw) diff --git a/Godeps/_workspace/src/github.com/tendermint/tendermint/vm/types.go b/Godeps/_workspace/src/github.com/tendermint/tendermint/vm/types.go index 9af090b1..50154205 100644 --- a/Godeps/_workspace/src/github.com/tendermint/tendermint/vm/types.go +++ b/Godeps/_workspace/src/github.com/tendermint/tendermint/vm/types.go @@ -10,21 +10,25 @@ const ( ) type Account struct { - Address Word256 - Balance int64 - Code []byte - Nonce int64 - StorageRoot Word256 - Other interface{} // For holding all other data. + Address Word256 + Balance int64 + Code []byte + Nonce int64 + Other interface{} // For holding all other data. Permissions ptypes.AccountPermissions } func (acc *Account) String() string { - return Fmt("VMAccount{%X B:%v C:%X N:%v S:%X}", - acc.Address, acc.Balance, acc.Code, acc.Nonce, acc.StorageRoot) + if acc == nil { + return "nil-VMAccount" + } + return Fmt("VMAccount{%X B:%v C:%X N:%v}", + acc.Address, acc.Balance, acc.Code, acc.Nonce) } +// NOTE: This is serialized as an event from vm/vm. +// See: EventStringLogEvent type Log struct { Address Word256 `json:"address"` Topics []Word256 `json:"topics"` diff --git a/Godeps/_workspace/src/github.com/tendermint/tendermint/vm/vm.go b/Godeps/_workspace/src/github.com/tendermint/tendermint/vm/vm.go index d08cf3b9..c0ea1b0e 100644 --- a/Godeps/_workspace/src/github.com/tendermint/tendermint/vm/vm.go +++ b/Godeps/_workspace/src/github.com/tendermint/tendermint/vm/vm.go @@ -95,6 +95,19 @@ func HasPermission(appState AppState, acc *Account, perm ptypes.PermFlag) bool { return v } +func (vm *VM) fireCallEvent(exception *string, output *[]byte, caller, callee *Account, input []byte, value int64, gas *int64) { + // fire the post call event (including exception if applicable) + if vm.evc != nil { + vm.evc.FireEvent(types.EventStringAccCall(callee.Address.Postfix(20)), types.EventMsgCall{ + &types.CallData{caller.Address.Postfix(20), callee.Address.Postfix(20), input, value, *gas}, + vm.origin.Postfix(20), + vm.txid, + *output, + *exception, + }) + } +} + // CONTRACT appState is aware of caller and callee, so we can just mutate them. // value: To be transferred from caller to callee. Refunded upon error. // gas: Available gas. No refunds for gas. @@ -102,30 +115,8 @@ func HasPermission(appState AppState, acc *Account, perm ptypes.PermFlag) bool { func (vm *VM) Call(caller, callee *Account, code, input []byte, value int64, gas *int64) (output []byte, err error) { exception := new(string) - defer func() { - if vm.evc != nil { - vm.evc.FireEvent(types.EventStringAccReceive(callee.Address.Postfix(20)), types.EventMsgCall{ - &types.CallData{caller.Address.Postfix(20), callee.Address.Postfix(20), input, value, *gas}, - vm.origin.Postfix(20), - vm.txid, - output, - *exception, - }) - } - }() - - // SNATIVE ACCESS - // if code is empty, callee may be snative contract - if len(code) == 0 { - if snativeContract, ok := RegisteredSNativeContracts[callee.Address]; ok { - output, err = snativeContract(vm.appState, caller, input) - if err != nil { - *exception = err.Error() - } - return - } - } - // SNATIVE ACCESS END + // fire the post call event (including exception if applicable) + defer vm.fireCallEvent(exception, &output, caller, callee, input, value, gas) if err = transfer(caller, callee, value); err != nil { *exception = err.Error() @@ -141,7 +132,7 @@ func (vm *VM) Call(caller, callee *Account, code, input []byte, value int64, gas err := transfer(callee, caller, value) if err != nil { // data has been corrupted in ram - panic("Could not return value to caller") + PanicCrisis("Could not return value to caller") } } } @@ -149,6 +140,18 @@ func (vm *VM) Call(caller, callee *Account, code, input []byte, value int64, gas return } +// Try to deduct gasToUse from gasLeft. If ok return false, otherwise +// set err and return true. +func useGasNegative(gasLeft *int64, gasToUse int64, err *error) bool { + if *gasLeft >= gasToUse { + *gasLeft -= gasToUse + return false + } else if *err == nil { + *err = ErrInsufficientGas + } + return true +} + // Just like Call() but does not transfer 'value' or modify the callDepth. func (vm *VM) call(caller, callee *Account, code, input []byte, value int64, gas *int64) (output []byte, err error) { dbg.Printf("(%d) (%X) %X (code=%d) gas: %v (d) %X\n", vm.callDepth, caller.Address[:4], callee.Address, len(callee.Code), *gas, input) @@ -157,12 +160,12 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value int64, gas pc int64 = 0 stack = NewStack(dataStackCapacity, gas, &err) memory = make([]byte, memoryCapacity) - ok = false // convenience ) for { - // If there is an error, return - if err != nil { + + // Use BaseOp gas. + if useGasNegative(gas, GasBaseOp, &err) { return nil, err } @@ -433,8 +436,8 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value int64, gas dbg.Printf(" => 0x%X\n", res) case SHA3: // 0x20 - if ok = useGas(gas, GasSha3); !ok { - return nil, firstErr(err, ErrInsufficientGas) + if useGasNegative(gas, GasSha3, &err) { + return nil, err } offset, size := stack.Pop64(), stack.Pop64() data, ok := subslice(memory, offset, size) @@ -451,8 +454,8 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value int64, gas case BALANCE: // 0x31 addr := stack.Pop() - if ok = useGas(gas, GasGetAccount); !ok { - return nil, firstErr(err, ErrInsufficientGas) + if useGasNegative(gas, GasGetAccount, &err) { + return nil, err } acc := vm.appState.GetAccount(addr) if acc == nil { @@ -529,8 +532,8 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value int64, gas case EXTCODESIZE: // 0x3B addr := stack.Pop() - if ok = useGas(gas, GasGetAccount); !ok { - return nil, firstErr(err, ErrInsufficientGas) + if useGasNegative(gas, GasGetAccount, &err) { + return nil, err } acc := vm.appState.GetAccount(addr) if acc == nil { @@ -543,8 +546,8 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value int64, gas case EXTCODECOPY: // 0x3C addr := stack.Pop() - if ok = useGas(gas, GasGetAccount); !ok { - return nil, firstErr(err, ErrInsufficientGas) + if useGasNegative(gas, GasGetAccount, &err) { + return nil, err } acc := vm.appState.GetAccount(addr) if acc == nil { @@ -588,8 +591,8 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value int64, gas dbg.Printf(" => %v\n", vm.params.GasLimit) case POP: // 0x50 - stack.Pop() - dbg.Printf(" => %v\n", vm.params.GasLimit) + popped := stack.Pop() + dbg.Printf(" => 0x%X\n", popped) case MLOAD: // 0x51 offset := stack.Pop64() @@ -625,8 +628,10 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value int64, gas case SSTORE: // 0x55 loc, data := stack.Pop(), stack.Pop() + if useGasNegative(gas, GasStorageUpdate, &err) { + return nil, err + } vm.appState.SetStorage(callee.Address, loc, data) - useGas(gas, GasStorageUpdate) dbg.Printf(" {0x%X : 0x%X}\n", loc, data) case JUMP: // 0x56 @@ -759,13 +764,20 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value int64, gas // Begin execution var ret []byte var err error - if nativeContract := nativeContracts[addr]; nativeContract != nil { + if nativeContract := registeredNativeContracts[addr]; nativeContract != nil { // Native contract - ret, err = nativeContract(args, &gasLimit) + ret, err = nativeContract(vm.appState, callee, args, &gasLimit) + + // for now we fire the Call event. maybe later we'll fire more particulars + var exception string + if err != nil { + exception = err.Error() + } + vm.fireCallEvent(&exception, &ret, callee, &Account{Address: addr}, args, value, gas) } else { // EVM contract - if ok = useGas(gas, GasGetAccount); !ok { - return nil, firstErr(err, ErrInsufficientGas) + if useGasNegative(gas, GasGetAccount, &err) { + return nil, err } acc := vm.appState.GetAccount(addr) // since CALL is used also for sending funds, @@ -779,19 +791,18 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value int64, gas ret, err = vm.Call(callee, callee, acc.Code, args, value, gas) } else { if acc == nil { - if _, ok := RegisteredSNativeContracts[addr]; ok { - acc = &Account{Address: addr} - } else { - // if we have not seen the account before, create it - // so we can send funds - if !HasPermission(vm.appState, caller, ptypes.CreateAccount) { - return nil, ErrPermission{"create_account"} - } - acc = &Account{Address: addr} + // nil account means we're sending funds to a new account + if !HasPermission(vm.appState, caller, ptypes.CreateAccount) { + return nil, ErrPermission{"create_account"} } + acc = &Account{Address: addr} vm.appState.UpdateAccount(acc) + // send funds to new account + ret, err = vm.Call(callee, acc, acc.Code, args, value, gas) + } else { + // call standard contract + ret, err = vm.Call(callee, acc, acc.Code, args, value, gas) } - ret, err = vm.Call(callee, acc, acc.Code, args, value, gas) } } @@ -824,8 +835,8 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value int64, gas case SUICIDE: // 0xFF addr := stack.Pop() - if ok = useGas(gas, GasGetAccount); !ok { - return nil, firstErr(err, ErrInsufficientGas) + if useGasNegative(gas, GasGetAccount, &err) { + return nil, err } // TODO if the receiver is , then make it the fee. receiver := vm.appState.GetAccount(addr) @@ -896,15 +907,6 @@ func firstErr(errA, errB error) error { } } -func useGas(gas *int64, gasToUse int64) bool { - if *gas > gasToUse { - *gas -= gasToUse - return true - } else { - return false - } -} - func transfer(from, to *Account, amount int64) error { if from.Balance < amount { return ErrInsufficientBalance diff --git a/Godeps/_workspace/src/github.com/tendermint/tendermint/binary/README.md b/Godeps/_workspace/src/github.com/tendermint/tendermint/wire/README.md similarity index 99% rename from Godeps/_workspace/src/github.com/tendermint/tendermint/binary/README.md rename to Godeps/_workspace/src/github.com/tendermint/tendermint/wire/README.md index 9a4fa714..3108505e 100644 --- a/Godeps/_workspace/src/github.com/tendermint/tendermint/binary/README.md +++ b/Godeps/_workspace/src/github.com/tendermint/tendermint/wire/README.md @@ -6,7 +6,7 @@ This documentation is out of date. * Pointers that don't have a declared TypeByte() are encoded with a leading 0x00 (nil) or 0x01. -# `tendermint/binary` +# `tendermint/wire` The `binary` submodule encodes primary types and structs into bytes. diff --git a/Godeps/_workspace/src/github.com/tendermint/tendermint/binary/binary.go b/Godeps/_workspace/src/github.com/tendermint/tendermint/wire/binary.go similarity index 92% rename from Godeps/_workspace/src/github.com/tendermint/tendermint/binary/binary.go rename to Godeps/_workspace/src/github.com/tendermint/tendermint/wire/binary.go index 8a4abd6a..6584558c 100644 --- a/Godeps/_workspace/src/github.com/tendermint/tendermint/binary/binary.go +++ b/Godeps/_workspace/src/github.com/tendermint/tendermint/wire/binary.go @@ -1,10 +1,12 @@ -package binary +package wire import ( "encoding/json" "errors" "io" "reflect" + + . "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/common" ) // TODO document and maybe make it configurable. @@ -37,10 +39,10 @@ func ReadBinaryPtr(o interface{}, r io.Reader, n *int64, err *error) interface{} rv, rt := reflect.ValueOf(o), reflect.TypeOf(o) if rv.Kind() == reflect.Ptr { readReflectBinary(rv.Elem(), rt.Elem(), Options{}, r, n, err) - return o } else { - panic("ReadBinaryPtr expects o to be a pointer") + PanicSanity("ReadBinaryPtr expects o to be a pointer") } + return o } func WriteBinary(o interface{}, w io.Writer, n *int64, err *error) { @@ -93,10 +95,10 @@ func ReadJSONObjectPtr(o interface{}, object interface{}, err *error) interface{ rv, rt := reflect.ValueOf(o), reflect.TypeOf(o) if rv.Kind() == reflect.Ptr { readReflectJSON(rv.Elem(), rt.Elem(), object, err) - return o } else { - panic("ReadJSON(Object)Ptr expects o to be a pointer") + PanicSanity("ReadJSON(Object)Ptr expects o to be a pointer") } + return o } func WriteJSON(o interface{}, w io.Writer, n *int64, err *error) { diff --git a/Godeps/_workspace/src/github.com/tendermint/tendermint/binary/byteslice.go b/Godeps/_workspace/src/github.com/tendermint/tendermint/wire/byteslice.go similarity index 98% rename from Godeps/_workspace/src/github.com/tendermint/tendermint/binary/byteslice.go rename to Godeps/_workspace/src/github.com/tendermint/tendermint/wire/byteslice.go index e797eb63..8aaedd8d 100644 --- a/Godeps/_workspace/src/github.com/tendermint/tendermint/binary/byteslice.go +++ b/Godeps/_workspace/src/github.com/tendermint/tendermint/wire/byteslice.go @@ -1,4 +1,4 @@ -package binary +package wire import ( "io" diff --git a/Godeps/_workspace/src/github.com/tendermint/tendermint/binary/codec.go b/Godeps/_workspace/src/github.com/tendermint/tendermint/wire/codec.go similarity index 94% rename from Godeps/_workspace/src/github.com/tendermint/tendermint/binary/codec.go rename to Godeps/_workspace/src/github.com/tendermint/tendermint/wire/codec.go index a60569b1..c032d76a 100644 --- a/Godeps/_workspace/src/github.com/tendermint/tendermint/binary/codec.go +++ b/Godeps/_workspace/src/github.com/tendermint/tendermint/wire/codec.go @@ -1,4 +1,4 @@ -package binary +package wire import ( "bytes" @@ -40,8 +40,7 @@ const ( func BasicCodecEncoder(o interface{}, w io.Writer, n *int64, err *error) { switch o := o.(type) { case nil: - // SANITY CHECK - panic("nil type unsupported") + PanicSanity("nil type unsupported") case byte: WriteByte(typeByte, w, n, err) WriteByte(o, w, n, err) @@ -85,8 +84,7 @@ func BasicCodecEncoder(o interface{}, w io.Writer, n *int64, err *error) { WriteByte(typeTime, w, n, err) WriteTime(o, w, n, err) default: - // SANITY CHECK - panic(fmt.Sprintf("Unsupported type: %v", reflect.TypeOf(o))) + PanicSanity(fmt.Sprintf("Unsupported type: %v", reflect.TypeOf(o))) } } @@ -161,8 +159,7 @@ func BasicCodecComparator(o1 interface{}, o2 interface{}) int { case time.Time: return int(o1.(time.Time).UnixNano() - o2.(time.Time).UnixNano()) default: - // SANITY CHECK - panic(Fmt("Unsupported type: %v", reflect.TypeOf(o1))) + PanicSanity(Fmt("Unsupported type: %v", reflect.TypeOf(o1))) } return 0 } diff --git a/Godeps/_workspace/src/github.com/tendermint/tendermint/binary/int.go b/Godeps/_workspace/src/github.com/tendermint/tendermint/wire/int.go similarity index 99% rename from Godeps/_workspace/src/github.com/tendermint/tendermint/binary/int.go rename to Godeps/_workspace/src/github.com/tendermint/tendermint/wire/int.go index 3be5f224..c63666fa 100644 --- a/Godeps/_workspace/src/github.com/tendermint/tendermint/binary/int.go +++ b/Godeps/_workspace/src/github.com/tendermint/tendermint/wire/int.go @@ -1,4 +1,4 @@ -package binary +package wire import ( "encoding/binary" diff --git a/Godeps/_workspace/src/github.com/tendermint/tendermint/binary/int_test.go b/Godeps/_workspace/src/github.com/tendermint/tendermint/wire/int_test.go similarity index 99% rename from Godeps/_workspace/src/github.com/tendermint/tendermint/binary/int_test.go rename to Godeps/_workspace/src/github.com/tendermint/tendermint/wire/int_test.go index 49348fae..3baceaa4 100644 --- a/Godeps/_workspace/src/github.com/tendermint/tendermint/binary/int_test.go +++ b/Godeps/_workspace/src/github.com/tendermint/tendermint/wire/int_test.go @@ -1,4 +1,4 @@ -package binary +package wire import ( "bytes" diff --git a/Godeps/_workspace/src/github.com/tendermint/tendermint/binary/log.go b/Godeps/_workspace/src/github.com/tendermint/tendermint/wire/log.go similarity index 96% rename from Godeps/_workspace/src/github.com/tendermint/tendermint/binary/log.go rename to Godeps/_workspace/src/github.com/tendermint/tendermint/wire/log.go index a688997b..3591db3d 100644 --- a/Godeps/_workspace/src/github.com/tendermint/tendermint/binary/log.go +++ b/Godeps/_workspace/src/github.com/tendermint/tendermint/wire/log.go @@ -1,4 +1,4 @@ -package binary +package wire import ( "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/log15" diff --git a/Godeps/_workspace/src/github.com/tendermint/tendermint/binary/reflect.go b/Godeps/_workspace/src/github.com/tendermint/tendermint/wire/reflect.go similarity index 90% rename from Godeps/_workspace/src/github.com/tendermint/tendermint/binary/reflect.go rename to Godeps/_workspace/src/github.com/tendermint/tendermint/wire/reflect.go index a72b2342..efde6162 100644 --- a/Godeps/_workspace/src/github.com/tendermint/tendermint/binary/reflect.go +++ b/Godeps/_workspace/src/github.com/tendermint/tendermint/wire/reflect.go @@ -1,4 +1,4 @@ -package binary +package wire import ( "encoding/hex" @@ -70,8 +70,7 @@ func (info StructFieldInfo) unpack() (int, reflect.Type, Options) { func GetTypeFromStructDeclaration(o interface{}) reflect.Type { rt := reflect.TypeOf(o) if rt.NumField() != 1 { - // SANITY CHECK - panic("Unexpected number of fields in struct-wrapped declaration of type") + PanicSanity("Unexpected number of fields in struct-wrapped declaration of type") } return rt.Field(0).Type } @@ -79,8 +78,7 @@ func GetTypeFromStructDeclaration(o interface{}) reflect.Type { func SetByteForType(typeByte byte, rt reflect.Type) { typeInfo := GetTypeInfo(rt) if typeInfo.Byte != 0x00 && typeInfo.Byte != typeByte { - // SANITY CHECK - panic(Fmt("Type %v already registered with type byte %X", rt, typeByte)) + PanicSanity(Fmt("Type %v already registered with type byte %X", rt, typeByte)) } typeInfo.Byte = typeByte // If pointer, we need to set it for the concrete type as well. @@ -124,8 +122,7 @@ type ConcreteType struct { func RegisterInterface(o interface{}, ctypes ...ConcreteType) *TypeInfo { it := GetTypeFromStructDeclaration(o) if it.Kind() != reflect.Interface { - // SANITY CHECK - panic("RegisterInterface expects an interface") + PanicSanity("RegisterInterface expects an interface") } toType := make(map[byte]reflect.Type, 0) toByte := make(map[reflect.Type]byte, 0) @@ -134,12 +131,10 @@ func RegisterInterface(o interface{}, ctypes ...ConcreteType) *TypeInfo { typeByte := ctype.Byte SetByteForType(typeByte, crt) if typeByte == 0x00 { - // SANITY CHECK - panic(Fmt("Byte of 0x00 is reserved for nil (%v)", ctype)) + PanicSanity(Fmt("Byte of 0x00 is reserved for nil (%v)", ctype)) } if toType[typeByte] != nil { - // SANITY CHECK - panic(Fmt("Duplicate Byte for type %v and %v", ctype, toType[typeByte])) + PanicSanity(Fmt("Duplicate Byte for type %v and %v", ctype, toType[typeByte])) } toType[typeByte] = crt toByte[crt] = typeByte @@ -260,7 +255,7 @@ func readReflectBinary(rv reflect.Value, rt reflect.Type, opts Options, r io.Rea if *err != nil { return } - log.Debug("Read bytearray", "bytes", buf) + log.Info("Read bytearray", "bytes", buf) reflect.Copy(rv, reflect.ValueOf(buf)) } else { for i := 0; i < length; i++ { @@ -274,7 +269,7 @@ func readReflectBinary(rv reflect.Value, rt reflect.Type, opts Options, r io.Rea return } } - log.Debug(Fmt("Read %v-array", elemRt), "length", length) + log.Info(Fmt("Read %v-array", elemRt), "length", length) } case reflect.Slice: @@ -282,13 +277,13 @@ func readReflectBinary(rv reflect.Value, rt reflect.Type, opts Options, r io.Rea if elemRt.Kind() == reflect.Uint8 { // Special case: Byteslices byteslice := ReadByteSlice(r, n, err) - log.Debug("Read byteslice", "bytes", byteslice) + log.Info("Read byteslice", "bytes", byteslice) rv.Set(reflect.ValueOf(byteslice)) } else { var sliceRv reflect.Value // Read length length := ReadVarint(r, n, err) - log.Debug(Fmt("Read length: %v", length)) + log.Info(Fmt("Read length: %v", length)) sliceRv = reflect.MakeSlice(rt, 0, 0) // read one ReflectSliceChunk at a time and append for i := 0; i*ReflectSliceChunk < length; i++ { @@ -315,7 +310,7 @@ func readReflectBinary(rv reflect.Value, rt reflect.Type, opts Options, r io.Rea if rt == timeType { // Special case: time.Time t := ReadTime(r, n, err) - log.Debug(Fmt("Read time: %v", t)) + log.Info(Fmt("Read time: %v", t)) rv.Set(reflect.ValueOf(t)) } else { for _, fieldInfo := range typeInfo.Fields { @@ -327,79 +322,78 @@ func readReflectBinary(rv reflect.Value, rt reflect.Type, opts Options, r io.Rea case reflect.String: str := ReadString(r, n, err) - log.Debug(Fmt("Read string: %v", str)) + log.Info(Fmt("Read string: %v", str)) rv.SetString(str) case reflect.Int64: if opts.Varint { num := ReadVarint(r, n, err) - log.Debug(Fmt("Read num: %v", num)) + log.Info(Fmt("Read num: %v", num)) rv.SetInt(int64(num)) } else { num := ReadInt64(r, n, err) - log.Debug(Fmt("Read num: %v", num)) + log.Info(Fmt("Read num: %v", num)) rv.SetInt(int64(num)) } case reflect.Int32: num := ReadUint32(r, n, err) - log.Debug(Fmt("Read num: %v", num)) + log.Info(Fmt("Read num: %v", num)) rv.SetInt(int64(num)) case reflect.Int16: num := ReadUint16(r, n, err) - log.Debug(Fmt("Read num: %v", num)) + log.Info(Fmt("Read num: %v", num)) rv.SetInt(int64(num)) case reflect.Int8: num := ReadUint8(r, n, err) - log.Debug(Fmt("Read num: %v", num)) + log.Info(Fmt("Read num: %v", num)) rv.SetInt(int64(num)) case reflect.Int: num := ReadVarint(r, n, err) - log.Debug(Fmt("Read num: %v", num)) + log.Info(Fmt("Read num: %v", num)) rv.SetInt(int64(num)) case reflect.Uint64: if opts.Varint { num := ReadVarint(r, n, err) - log.Debug(Fmt("Read num: %v", num)) + log.Info(Fmt("Read num: %v", num)) rv.SetUint(uint64(num)) } else { num := ReadUint64(r, n, err) - log.Debug(Fmt("Read num: %v", num)) + log.Info(Fmt("Read num: %v", num)) rv.SetUint(uint64(num)) } case reflect.Uint32: num := ReadUint32(r, n, err) - log.Debug(Fmt("Read num: %v", num)) + log.Info(Fmt("Read num: %v", num)) rv.SetUint(uint64(num)) case reflect.Uint16: num := ReadUint16(r, n, err) - log.Debug(Fmt("Read num: %v", num)) + log.Info(Fmt("Read num: %v", num)) rv.SetUint(uint64(num)) case reflect.Uint8: num := ReadUint8(r, n, err) - log.Debug(Fmt("Read num: %v", num)) + log.Info(Fmt("Read num: %v", num)) rv.SetUint(uint64(num)) case reflect.Uint: num := ReadVarint(r, n, err) - log.Debug(Fmt("Read num: %v", num)) + log.Info(Fmt("Read num: %v", num)) rv.SetUint(uint64(num)) case reflect.Bool: num := ReadUint8(r, n, err) - log.Debug(Fmt("Read bool: %v", num)) + log.Info(Fmt("Read bool: %v", num)) rv.SetBool(num > 0) default: - // SANITY CHECK - panic(Fmt("Unknown field type %v", rt.Kind())) + PanicSanity(Fmt("Unknown field type %v", rt.Kind())) } } @@ -447,6 +441,9 @@ func writeReflectBinary(rv reflect.Value, rt reflect.Type, opts Options, w io.Wr rv, rt = rv.Elem(), rt.Elem() typeInfo = GetTypeInfo(rt) if !rv.IsValid() { + // For better compatibility with other languages, + // as far as tendermint/wire is concerned, + // pointers to nil values are the same as nil. WriteByte(0x00, w, n, err) return } @@ -564,8 +561,7 @@ func writeReflectBinary(rv reflect.Value, rt reflect.Type, opts Options, w io.Wr } default: - // SANITY CHECK - panic(Fmt("Unknown field type %v", rt.Kind())) + PanicSanity(Fmt("Unknown field type %v", rt.Kind())) } } @@ -669,8 +665,8 @@ func readReflectJSON(rv reflect.Value, rt reflect.Type, o interface{}, err *erro *err = errors.New(Fmt("Expected bytearray of length %v but got %v", length, len(buf))) return } - log.Debug("Read bytearray", "bytes", buf) - rv.Set(reflect.ValueOf(buf)) + log.Info("Read bytearray", "bytes", buf) + reflect.Copy(rv, reflect.ValueOf(buf)) } else { oSlice, ok := o.([]interface{}) if !ok { @@ -685,7 +681,7 @@ func readReflectJSON(rv reflect.Value, rt reflect.Type, o interface{}, err *erro elemRv := rv.Index(i) readReflectJSON(elemRv, elemRt, oSlice[i], err) } - log.Debug(Fmt("Read %v-array", elemRt), "length", length) + log.Info(Fmt("Read %v-array", elemRt), "length", length) } case reflect.Slice: @@ -702,7 +698,7 @@ func readReflectJSON(rv reflect.Value, rt reflect.Type, o interface{}, err *erro *err = err_ return } - log.Debug("Read byteslice", "bytes", byteslice) + log.Info("Read byteslice", "bytes", byteslice) rv.Set(reflect.ValueOf(byteslice)) } else { // Read length @@ -712,7 +708,7 @@ func readReflectJSON(rv reflect.Value, rt reflect.Type, o interface{}, err *erro return } length := len(oSlice) - log.Debug(Fmt("Read length: %v", length)) + log.Info(Fmt("Read length: %v", length)) sliceRv := reflect.MakeSlice(rt, length, length) // Read elems for i := 0; i < length; i++ { @@ -730,7 +726,7 @@ func readReflectJSON(rv reflect.Value, rt reflect.Type, o interface{}, err *erro *err = errors.New(Fmt("Expected string but got type %v", reflect.TypeOf(o))) return } - log.Debug(Fmt("Read time: %v", str)) + log.Info(Fmt("Read time: %v", str)) t, err_ := time.Parse(rfc2822, str) if err_ != nil { *err = err_ @@ -762,7 +758,7 @@ func readReflectJSON(rv reflect.Value, rt reflect.Type, o interface{}, err *erro *err = errors.New(Fmt("Expected string but got type %v", reflect.TypeOf(o))) return } - log.Debug(Fmt("Read string: %v", str)) + log.Info(Fmt("Read string: %v", str)) rv.SetString(str) case reflect.Int64, reflect.Int32, reflect.Int16, reflect.Int8, reflect.Int: @@ -771,7 +767,7 @@ func readReflectJSON(rv reflect.Value, rt reflect.Type, o interface{}, err *erro *err = errors.New(Fmt("Expected numeric but got type %v", reflect.TypeOf(o))) return } - log.Debug(Fmt("Read num: %v", num)) + log.Info(Fmt("Read num: %v", num)) rv.SetInt(int64(num)) case reflect.Uint64, reflect.Uint32, reflect.Uint16, reflect.Uint8, reflect.Uint: @@ -784,7 +780,7 @@ func readReflectJSON(rv reflect.Value, rt reflect.Type, o interface{}, err *erro *err = errors.New(Fmt("Expected unsigned numeric but got %v", num)) return } - log.Debug(Fmt("Read num: %v", num)) + log.Info(Fmt("Read num: %v", num)) rv.SetUint(uint64(num)) case reflect.Bool: @@ -793,17 +789,16 @@ func readReflectJSON(rv reflect.Value, rt reflect.Type, o interface{}, err *erro *err = errors.New(Fmt("Expected boolean but got type %v", reflect.TypeOf(o))) return } - log.Debug(Fmt("Read boolean: %v", bl)) + log.Info(Fmt("Read boolean: %v", bl)) rv.SetBool(bl) default: - // SANITY CHECK - panic(Fmt("Unknown field type %v", rt.Kind())) + PanicSanity(Fmt("Unknown field type %v", rt.Kind())) } } func writeReflectJSON(rv reflect.Value, rt reflect.Type, w io.Writer, n *int64, err *error) { - log.Debug(Fmt("writeReflectJSON(%v, %v, %v, %v, %v)", rv, rt, w, n, err)) + log.Info(Fmt("writeReflectJSON(%v, %v, %v, %v, %v)", rv, rt, w, n, err)) // Get typeInfo typeInfo := GetTypeInfo(rt) @@ -845,6 +840,9 @@ func writeReflectJSON(rv reflect.Value, rt reflect.Type, w io.Writer, n *int64, rv, rt = rv.Elem(), rt.Elem() typeInfo = GetTypeInfo(rt) if !rv.IsValid() { + // For better compatibility with other languages, + // as far as tendermint/wire is concerned, + // pointers to nil values are the same as nil. WriteTo([]byte("null"), w, n, err) return } @@ -864,8 +862,9 @@ func writeReflectJSON(rv reflect.Value, rt reflect.Type, w io.Writer, n *int64, length := rt.Len() if elemRt.Kind() == reflect.Uint8 { // Special case: Bytearray - bytearray := rv.Interface() - WriteTo([]byte(Fmt("\"%X\"", bytearray)), w, n, err) + bytearray := reflect.ValueOf(make([]byte, length)) + reflect.Copy(bytearray, rv) + WriteTo([]byte(Fmt("\"%X\"", bytearray.Interface())), w, n, err) } else { WriteTo([]byte("["), w, n, err) // Write elems @@ -942,8 +941,7 @@ func writeReflectJSON(rv reflect.Value, rt reflect.Type, w io.Writer, n *int64, WriteTo(jsonBytes, w, n, err) default: - // SANITY CHECK - panic(Fmt("Unknown field type %v", rt.Kind())) + PanicSanity(Fmt("Unknown field type %v", rt.Kind())) } } diff --git a/Godeps/_workspace/src/github.com/tendermint/tendermint/binary/reflect_test.go b/Godeps/_workspace/src/github.com/tendermint/tendermint/wire/reflect_test.go similarity index 88% rename from Godeps/_workspace/src/github.com/tendermint/tendermint/binary/reflect_test.go rename to Godeps/_workspace/src/github.com/tendermint/tendermint/wire/reflect_test.go index 5d35fff0..bfaaa3be 100644 --- a/Godeps/_workspace/src/github.com/tendermint/tendermint/binary/reflect_test.go +++ b/Godeps/_workspace/src/github.com/tendermint/tendermint/wire/reflect_test.go @@ -1,4 +1,4 @@ -package binary +package wire import ( "bytes" @@ -16,8 +16,6 @@ type SimpleStruct struct { Time time.Time } -//------------------------------------- - type Animal interface{} const ( @@ -265,6 +263,9 @@ func validateComplex2(o interface{}, t *testing.T) { type ComplexStructArray struct { Animals []Animal + Bytes [5]byte + Ints [5]int + Array SimpleArray } func constructComplexArray() interface{} { @@ -287,6 +288,9 @@ func constructComplexArray() interface{} { Bytes: []byte("hizz"), }, }, + Bytes: [5]byte{1, 10, 50, 100, 200}, + Ints: [5]int{1, 2, 3, 4, 5}, + Array: SimpleArray([5]byte{1, 10, 50, 100, 200}), } return c } @@ -352,7 +356,7 @@ func TestBinary(t *testing.T) { for i, testCase := range testCases { - log.Info(fmt.Sprintf("Running test case %v", i)) + log.Notice(fmt.Sprintf("Running test case %v", i)) // Construct an object o := testCase.Constructor() @@ -394,7 +398,7 @@ func TestJSON(t *testing.T) { for i, testCase := range testCases { - log.Info(fmt.Sprintf("Running test case %v", i)) + log.Notice(fmt.Sprintf("Running test case %v", i)) // Construct an object o := testCase.Constructor() @@ -464,3 +468,40 @@ func TestBadAlloc(t *testing.T) { res := ReadBinary(instance, b, n, err) fmt.Println(res, *err) } + +//------------------------------------------------------------------------------ + +type SimpleArray [5]byte + +func TestSimpleArray(t *testing.T) { + var foo SimpleArray + + // Type of pointer to array + rt := reflect.TypeOf(&foo) + fmt.Printf("rt: %v\n", rt) // *binary.SimpleArray + + // Type of array itself. + // NOTE: normally this is acquired through other means + // like introspecting on method signatures, or struct fields. + rte := rt.Elem() + fmt.Printf("rte: %v\n", rte) // binary.SimpleArray + + // Get a new pointer to the array + // NOTE: calling .Interface() is to get the actual value, + // instead of reflection values. + ptr := reflect.New(rte).Interface() + fmt.Printf("ptr: %v\n", ptr) // &[0 0 0 0 0] + + // Make a simple int aray + fooArray := SimpleArray([5]byte{1, 10, 50, 100, 200}) + fooBytes := BinaryBytes(fooArray) + fooReader := bytes.NewReader(fooBytes) + + // Now you can read it. + n, err := new(int64), new(error) + it := ReadBinary(foo, fooReader, n, err).(SimpleArray) + + if !bytes.Equal(it[:], fooArray[:]) { + t.Errorf("Expected %v but got %v", fooArray, it) + } +} diff --git a/Godeps/_workspace/src/github.com/tendermint/tendermint/binary/string.go b/Godeps/_workspace/src/github.com/tendermint/tendermint/wire/string.go similarity index 97% rename from Godeps/_workspace/src/github.com/tendermint/tendermint/binary/string.go rename to Godeps/_workspace/src/github.com/tendermint/tendermint/wire/string.go index f1085619..c0c586f3 100644 --- a/Godeps/_workspace/src/github.com/tendermint/tendermint/binary/string.go +++ b/Godeps/_workspace/src/github.com/tendermint/tendermint/wire/string.go @@ -1,4 +1,4 @@ -package binary +package wire import ( "io" diff --git a/Godeps/_workspace/src/github.com/tendermint/tendermint/binary/time.go b/Godeps/_workspace/src/github.com/tendermint/tendermint/wire/time.go similarity index 94% rename from Godeps/_workspace/src/github.com/tendermint/tendermint/binary/time.go rename to Godeps/_workspace/src/github.com/tendermint/tendermint/wire/time.go index 9c678046..c4a57334 100644 --- a/Godeps/_workspace/src/github.com/tendermint/tendermint/binary/time.go +++ b/Godeps/_workspace/src/github.com/tendermint/tendermint/wire/time.go @@ -1,4 +1,4 @@ -package binary +package wire import ( "io" diff --git a/Godeps/_workspace/src/github.com/tendermint/tendermint/binary/util.go b/Godeps/_workspace/src/github.com/tendermint/tendermint/wire/util.go similarity index 87% rename from Godeps/_workspace/src/github.com/tendermint/tendermint/binary/util.go rename to Godeps/_workspace/src/github.com/tendermint/tendermint/wire/util.go index 18b5229b..91aa6f5c 100644 --- a/Godeps/_workspace/src/github.com/tendermint/tendermint/binary/util.go +++ b/Godeps/_workspace/src/github.com/tendermint/tendermint/wire/util.go @@ -1,18 +1,18 @@ -package binary +package wire import ( "bytes" "crypto/sha256" "github.com/eris-ltd/eris-db/Godeps/_workspace/src/code.google.com/p/go.crypto/ripemd160" -) -// THESE PANICS ARE SANITY CHECKS + . "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/common" +) func BinaryBytes(o interface{}) []byte { w, n, err := new(bytes.Buffer), new(int64), new(error) WriteBinary(o, w, n, err) if *err != nil { - panic(*err) + PanicSanity(*err) } return w.Bytes() } @@ -21,7 +21,7 @@ func JSONBytes(o interface{}) []byte { w, n, err := new(bytes.Buffer), new(int64), new(error) WriteJSON(o, w, n, err) if *err != nil { - panic(*err) + PanicSanity(*err) } return w.Bytes() } @@ -45,7 +45,7 @@ func BinarySha256(o interface{}) []byte { hasher, n, err := sha256.New(), new(int64), new(error) WriteBinary(o, hasher, n, err) if *err != nil { - panic(*err) + PanicSanity(*err) } return hasher.Sum(nil) } @@ -55,7 +55,7 @@ func BinaryRipemd160(o interface{}) []byte { hasher, n, err := ripemd160.New(), new(int64), new(error) WriteBinary(o, hasher, n, err) if *err != nil { - panic(*err) + PanicSanity(*err) } return hasher.Sum(nil) } diff --git a/api.md b/api.md index 3ecc791e..53ffe63c 100644 --- a/api.md +++ b/api.md @@ -1,6 +1,6 @@ # Eris DB web APIs (draft) -### for eris-db version 0.10.x +### for eris-db version 0.11.x Eris DB allows remote access to its functionality over http and websocket. It currently supports [JSON-RPC 2.0](http://www.jsonrpc.org/specification), and REST-like http. There is also javascript bindings available in the [erisdb-js](TODO) library. @@ -12,6 +12,7 @@ Eris DB allows remote access to its functionality over http and websocket. It cu - [Common objects and formatting](#formatting-conventions) - [Event-system](#event-system) - [Methods](#methods) +- [NameReg](#namereg) - [Filters](#queries-filters) <a name="http-requests"></a> @@ -535,7 +536,6 @@ NOTE: Get peer is not fully implemented. ####Unsafe | Name | RPC method name | HTTP method | HTTP endpoint | | :--- | :-------------- | :---------: | :------------ | -| [SignTx](#sign-tx) | erisdb.signTx | POST | `/unsafe/tx_signer` | | [Transact](#transact) | erisdb.transact | POST | `/unsafe/txpool` | | [TransactNameReg](#transact-name-reg) | erisdb.transactNameReg | POST | `/unsafe/namereg/txpool` | | [GenPrivAccount](#gen-priv-account) | erisdb.genPrivAccount | GET | `/unsafe/pa_generator` | @@ -1583,9 +1583,11 @@ TODO *** <a name="broadcast-tx"></a> -####BroadcastTx +####BroadcastTx -Broadcast a given (signed) transaction to the node. It will be added to the tx pool if there are no issues, and if it is accepted by all validators it will eventually be committed to a block. +Broadcast a given (signed) transaction to the node. It will be added to the tx pool if there are no issues, and if it is accepted by all validators it will eventually be committed to a block. + +WARNING: BroadcastTx will not be useful until we add a client-side signing solution. #####HTTP @@ -1705,7 +1707,7 @@ Parameters: #####Additional info -`data` is a string of data formatted in accordance with the [contract ABI](TODO). +`data` is a string of data formatted in accordance with the. *** @@ -1758,43 +1760,6 @@ These methods are unsafe because they require that a private key is either trans *** -<a name="sign-tx"></a> -####SignTx - -Send an unsigned transaction to the node for signing. - -#####HTTP - -Method: POST - -Endpoint: `/unsafe/tx_signer` - -Body: - -``` -<Tx> -``` - -#####JSON-RPC - -Method: `erisdb.SignTx` - -Parameters: - -``` -<Tx> -``` - -#####Return value - -The same transaction but signed. - -#####Additional info - -See [The transaction types](#the-transaction-types) for more info on the `Tx` types. - -*** - <a name="transact"></a> ####Transact diff --git a/erisdb/codec.go b/erisdb/codec.go index 3d7bece6..04055df1 100644 --- a/erisdb/codec.go +++ b/erisdb/codec.go @@ -1,7 +1,7 @@ package erisdb import ( - "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/binary" + "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/wire" rpc "github.com/eris-ltd/eris-db/rpc" "io" "io/ioutil" @@ -20,13 +20,13 @@ func NewTCodec() rpc.Codec { func (this *TCodec) Encode(v interface{}, w io.Writer) error { var err error var n int64 - binary.WriteJSON(v, w, &n, &err) + wire.WriteJSON(v, w, &n, &err) return err } // Encode to a byte array. func (this *TCodec) EncodeBytes(v interface{}) ([]byte, error) { - return binary.JSONBytes(v), nil + return wire.JSONBytes(v), nil } // Decode from an io.Reader. @@ -36,13 +36,13 @@ func (this *TCodec) Decode(v interface{}, r io.Reader) error { return errR } var err error - binary.ReadJSON(v, bts, &err) + wire.ReadJSON(v, bts, &err) return err } // Decode from a byte array. func (this *TCodec) DecodeBytes(v interface{}, bts []byte) error { var err error - binary.ReadJSON(v, bts, &err) + wire.ReadJSON(v, bts, &err) return err } diff --git a/erisdb/erisdbss/http.go b/erisdb/erisdbss/http.go index b1ad26a7..753b7f0a 100644 --- a/erisdb/erisdbss/http.go +++ b/erisdb/erisdbss/http.go @@ -4,9 +4,9 @@ import ( "bytes" "encoding/json" "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/gin-gonic/gin" - "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/binary" . "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/common" "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/state" + "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/wire" "github.com/eris-ltd/eris-db/server" "net/http" "os" @@ -96,7 +96,7 @@ func (this *ServerServer) handleFunc(c *gin.Context) { bts := buf.Bytes() var errDC error reqData := &RequestData{} - binary.ReadJSON(reqData, bts, &errDC) + wire.ReadJSON(reqData, bts, &errDC) if errDC != nil { http.Error(c.Writer, "Failed to decode json.", 400) return diff --git a/erisdb/erisdbss/server_manager.go b/erisdb/erisdbss/server_manager.go index 5d5d8099..59d33405 100644 --- a/erisdb/erisdbss/server_manager.go +++ b/erisdb/erisdbss/server_manager.go @@ -3,8 +3,8 @@ package erisdbss import ( "bufio" "fmt" - "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/binary" . "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/common" + "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/wire" "github.com/eris-ltd/eris-db/files" "github.com/eris-ltd/eris-db/server" "os" @@ -266,7 +266,7 @@ func writeJSON(file string, v interface{}) error { if errC != nil { return errC } - binary.WriteJSON(v, fo, &n, &errW) + wire.WriteJSON(v, fo, &n, &errW) if errW != nil { return errW } diff --git a/erisdb/methods.go b/erisdb/methods.go index d3be7483..8bd12e3c 100644 --- a/erisdb/methods.go +++ b/erisdb/methods.go @@ -439,7 +439,6 @@ func (this *ErisDbMethods) SignTx(request *rpc.RPCRequest, requester interface{} return txRet, 0, nil } - // *************************************** Name Registry *************************************** func (this *ErisDbMethods) NameRegEntry(request *rpc.RPCRequest, requester interface{}) (interface{}, int, error) { diff --git a/erisdb/pipe/accounts.go b/erisdb/pipe/accounts.go index efd9f2f8..1afc8c3c 100644 --- a/erisdb/pipe/accounts.go +++ b/erisdb/pipe/accounts.go @@ -48,7 +48,12 @@ func (this *accounts) GenPrivAccountFromKey(privKey []byte) (*account.PrivAccoun if len(privKey) != 64 { return nil, fmt.Errorf("Private key is not 64 bytes long.") } - pa := account.GenPrivAccountFromPrivKeyBytes(privKey) + pk := &[64]byte{} + for i := 0; i < 64; i++ { + pk[i] = privKey[i] + } + fmt.Printf("PK BYTES FROM ACCOUNTS: %x\n", pk) + pa := account.GenPrivAccountFromPrivKeyBytes(pk) return pa, nil } @@ -200,4 +205,4 @@ func (this *AccountBalanceFilter) Match(v interface{}) bool { return false } return this.match(int64(acc.Balance), this.value) -} \ No newline at end of file +} diff --git a/erisdb/pipe/consensus.go b/erisdb/pipe/consensus.go index 7595caf2..8f63b835 100644 --- a/erisdb/pipe/consensus.go +++ b/erisdb/pipe/consensus.go @@ -1,10 +1,10 @@ package pipe import ( - "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/binary" cm "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/consensus" "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/p2p" "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/state" + "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/wire" ) // The consensus struct. @@ -25,7 +25,7 @@ func (this *consensus) State() (*ConsensusState, error) { // TODO: clean this up? peerState := peer.Data.Get(cm.PeerStateKey).(*cm.PeerState) peerRoundState := peerState.GetRoundState() - peerRoundStateStr := peer.Key + ":" + string(binary.JSONBytes(peerRoundState)) + peerRoundStateStr := peer.Key + ":" + string(wire.JSONBytes(peerRoundState)) peerRoundStates = append(peerRoundStates, peerRoundStateStr) } return FromRoundState(roundState), nil diff --git a/erisdb/pipe/namereg.go b/erisdb/pipe/namereg.go index 3a820f0f..267f6be7 100644 --- a/erisdb/pipe/namereg.go +++ b/erisdb/pipe/namereg.go @@ -17,7 +17,7 @@ type namereg struct { } func newNamereg(consensusState *cm.ConsensusState) *namereg { - + ff := NewFilterFactory() ff.RegisterFilterPool("name", &sync.Pool{ @@ -67,7 +67,7 @@ func (this *namereg) Entries(filters []*FilterData) (*ctypes.ResponseListNames, } state.GetNames().Iterate(func(key interface{}, value interface{}) bool { nre := value.(*types.NameRegEntry) - if filter.Match(nre){ + if filter.Match(nre) { names = append(names, nre) } return false diff --git a/erisdb/pipe/pipe.go b/erisdb/pipe/pipe.go index 340aa925..29c59f3d 100644 --- a/erisdb/pipe/pipe.go +++ b/erisdb/pipe/pipe.go @@ -49,10 +49,10 @@ type ( Subscribe(subId, event string, callback func(interface{})) (bool, error) Unsubscribe(subId string) (bool, error) } - + NameReg interface { - Entry(key string) (*types.NameRegEntry, error) - Entries([]*FilterData) (*ctypes.ResponseListNames, error) + Entry(key string) (*types.NameRegEntry, error) + Entries([]*FilterData) (*ctypes.ResponseListNames, error) } Net interface { @@ -135,4 +135,4 @@ func (this *PipeImpl) Net() Net { func (this *PipeImpl) Transactor() Transactor { return this.txs -} \ No newline at end of file +} diff --git a/erisdb/pipe/transactor.go b/erisdb/pipe/transactor.go index 91089a04..1103de32 100644 --- a/erisdb/pipe/transactor.go +++ b/erisdb/pipe/transactor.go @@ -134,8 +134,12 @@ func (this *transactor) Transact(privKey, address, data []byte, gasLimit, fee in if len(privKey) != 64 { return nil, fmt.Errorf("Private key is not of the right length: %d\n", len(privKey)) } - - pa := account.GenPrivAccountFromPrivKeyBytes(privKey) + pk := &[64]byte{} + for i := 0; i < 64; i++ { + pk[i] = privKey[i] + } + fmt.Printf("PK BYTES FROM TRANSACT: %x\n", pk) + pa := account.GenPrivAccountFromPrivKeyBytes(pk) cache := this.mempoolReactor.Mempool.GetCache() acc := cache.GetAccount(pa.Address) var sequence int @@ -166,12 +170,16 @@ func (this *transactor) Transact(privKey, address, data []byte, gasLimit, fee in } func (this *transactor) TransactNameReg(privKey []byte, name, data string, amount, fee int64) (*Receipt, error) { - + if len(privKey) != 64 { return nil, fmt.Errorf("Private key is not of the right length: %d\n", len(privKey)) } - - pa := account.GenPrivAccountFromPrivKeyBytes(privKey) + pk := &[64]byte{} + for i := 0; i < 64; i++ { + pk[i] = privKey[i] + } + fmt.Printf("PK BYTES FROM TRANSACT NAMEREG: %x\n", pk) + pa := account.GenPrivAccountFromPrivKeyBytes(pk) cache := this.mempoolReactor.Mempool.GetCache() acc := cache.GetAccount(pa.Address) var sequence int @@ -243,11 +251,10 @@ func (this *transactor) SignTx(tx types.Tx, privAccounts []*account.PrivAccount) // No idea what this does. func toVMAccount(acc *account.Account) *vm.Account { return &vm.Account{ - Address: cmn.LeftPadWord256(acc.Address), - Balance: acc.Balance, - Code: acc.Code, // This is crazy. - Nonce: int64(acc.Sequence), - StorageRoot: cmn.LeftPadWord256(acc.StorageRoot), - Other: acc.PubKey, + Address: cmn.LeftPadWord256(acc.Address), + Balance: acc.Balance, + Code: acc.Code, + Nonce: int64(acc.Sequence), + Other: acc.PubKey, } } diff --git a/erisdb/serve.go b/erisdb/serve.go index 7078f9a2..713cbe91 100644 --- a/erisdb/serve.go +++ b/erisdb/serve.go @@ -94,7 +94,7 @@ func startNode(nd *node.Node, ready chan struct{}, shutDown <-chan struct{}) { if len(tmConfig.GetString("seeds")) > 0 { nd.DialSeed() } - + if len(tmConfig.GetString("rpc_laddr")) > 0 { nd.StartRPC() } @@ -102,4 +102,4 @@ func startNode(nd *node.Node, ready chan struct{}, shutDown <-chan struct{}) { // Block until everything is shut down. <-shutDown nd.Stop() -} \ No newline at end of file +} diff --git a/test/mock/mock_web_api_test.go b/test/mock/mock_web_api_test.go index e48be250..17f63630 100644 --- a/test/mock/mock_web_api_test.go +++ b/test/mock/mock_web_api_test.go @@ -9,8 +9,8 @@ import ( "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/stretchr/testify/suite" "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/log15" "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/account" - "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/types" ctypes "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/rpc/core/types" + "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/types" edb "github.com/eris-ltd/eris-db/erisdb" ep "github.com/eris-ltd/eris-db/erisdb/pipe" "github.com/eris-ltd/eris-db/rpc" @@ -168,7 +168,6 @@ func (this *MockSuite) TestGetValidators() { this.Equal(ret, this.testData.GetValidators.Output) } - // ********************************************* NameReg ********************************************* func (this *MockSuite) TestGetNameRegEntry() { diff --git a/test/mock/pipe.go b/test/mock/pipe.go index 9e2837be..3f331ad8 100644 --- a/test/mock/pipe.go +++ b/test/mock/pipe.go @@ -2,8 +2,8 @@ package mock import ( "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/account" - "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/types" ctypes "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/rpc/core/types" + "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/types" ep "github.com/eris-ltd/eris-db/erisdb/pipe" td "github.com/eris-ltd/eris-db/test/testdata/testdata" ) @@ -66,7 +66,6 @@ func (this *MockPipe) NameReg() ep.NameReg { return this.namereg } - func (this *MockPipe) Net() ep.Net { return this.net } @@ -165,7 +164,6 @@ func (this *events) Unsubscribe(subId string) (bool, error) { return true, nil } - // NameReg type namereg struct { testData *td.TestData diff --git a/test/testdata/filters/testdata_filters.go b/test/testdata/filters/testdata_filters.go index 378649d4..fd002c97 100644 --- a/test/testdata/filters/testdata_filters.go +++ b/test/testdata/filters/testdata_filters.go @@ -137,20 +137,22 @@ var testDataJson = `{ "output": { "accounts": [ { - "address": "0000000000000000000000000000000000000000", - "balance": 1337, - "code": "", - "permissions": { - "base": { - "perms": 126, - "set": 1095216660607 - }, - "roles": [] - }, - "pub_key": null, - "sequence": 0, - "storage_root": "" - }, + "address": "0000000000000000000000000000000000000000", + "pub_key": null, + "sequence": 0, + "balance": 1337, + "code": "", + "storage_root": "", + "permissions": { + "base": { + "perms": 2302, + "set": 16383 + }, + "roles": [ + + ] + } + }, { "address": "000000000000000000000000000000000000000D", "pub_key": null, @@ -294,4 +296,4 @@ func LoadTestData() *TestData { panic(err) } return testData -} +} \ No newline at end of file diff --git a/test/testdata/helpers.go b/test/testdata/helpers.go index d3943838..ee85fa23 100644 --- a/test/testdata/helpers.go +++ b/test/testdata/helpers.go @@ -2,9 +2,9 @@ package testdata import ( "fmt" - "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/binary" - . "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/common" - "github.com/eris-ltd/eris-db/Godeps/_workspace/src/github.com/tendermint/tendermint/state" + "github.com/tendermint/tendermint/binary" + . "github.com/tendermint/tendermint/common" + "github.com/tendermint/tendermint/state" "github.com/eris-ltd/eris-db/files" "github.com/eris-ltd/eris-db/server" "os" diff --git a/test/testdata/testdata/testdata.go b/test/testdata/testdata/testdata.go index eb1a799b..f1bc9452 100644 --- a/test/testdata/testdata/testdata.go +++ b/test/testdata/testdata/testdata.go @@ -93,20 +93,22 @@ var testDataJson = `{ "output": { "accounts": [ { - "address": "0000000000000000000000000000000000000000", - "balance": 1337, - "code": "", - "permissions": { - "base": { - "perms": 126, - "set": 1095216660607 - }, - "roles": [] - }, - "pub_key": null, - "sequence": 0, - "storage_root": "" - }, + "address": "0000000000000000000000000000000000000000", + "pub_key": null, + "sequence": 0, + "balance": 1337, + "code": "", + "storage_root": "", + "permissions": { + "base": { + "perms": 2302, + "set": 16383 + }, + "roles": [ + + ] + } + }, { "address": "0000000000000000000000000000000000000002", "pub_key": null, @@ -209,18 +211,18 @@ var testDataJson = `{ "address": "", "pub_key": [ 1, - "" + "0000000000000000000000000000000000000000000000000000000000000000" ], "priv_key": [ 1, - "" + "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" ] } }, "GetBlockchainInfo": { "output": { "chain_id": "my_tests", - "genesis_hash": "59A43DA6B4C9685E2D8840158768746093A71925", + "genesis_hash": "B901B9254D84CB509492E6C82245C54F1D84856D", "latest_block_height": 0, "latest_block": null } @@ -232,7 +234,7 @@ var testDataJson = `{ }, "GetGenesisHash": { "output": { - "hash": "59A43DA6B4C9685E2D8840158768746093A71925" + "hash": "B901B9254D84CB509492E6C82245C54F1D84856D" } }, "GetLatestBlockHeight": { -- GitLab