diff --git a/Godeps/Godeps.json b/Godeps/Godeps.json index c1ef66eabc1efc9157b2298a847859261f92e655..54eeae2b9c87d483454b237dcff7c8b58ea4d6b7 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 0ed58fb51be12eec4c780a98f1fa84510590b417..f89e6bcd37ef751c508d83fbae3b42fc39a527ac 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 f656f42199b1916facf2016f28df7c0f12df9e13..e064e78f533fc5619213f47dd5dfaee990b70e89 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 6ea8c81b727edd0d076937fe9f64185422d728cf..740433b3c00968225c59fec38155a8040476ee76 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 dcd7cf8dba28bbf7a251f4a045fed323ab0eec8b..325448d218b1d476af1efca14ec11845ff8a6dfc 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 0c442acee75d88453db694e735a372c2c4146aad..7034447afaeab3524567b74eb98c7bd3c65f7d7e 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 36c12b11f7a7d98d9c74377ddb08dda7379fda67..4b16e2b27a47fe87a4b9fb944549c859eedd22ad 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 637417cdb9e366ed70792ee134eab37449f39321..d69be6e76984c195a6c235fc515cbf700614909b 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 36d107b505fc41881f056fd66172f74e92bc71e0..42a650e6999ffeb84775c56f0e866a0ea1105ca7 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 80d54bba2bd6a85b37e5d73939a05d546bd511f8..3597060b52e15e9035807660e4cc2c6275e2125e 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 28eabe1fa9e0e04ee939db65be60bcc92abc43bf..c4bdc328946efd2923b1562dd18f1e4df94b8f9f 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 0e0e18d4a38bbbfa1f9ac52cd9a471faee92d939..2c0b816cddfdb4f84ba1547f92721af49dec9a1f 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 edd8745093410bd67bf0b079c33f5c39a4adc1e9..8c08dde865c652c0949d6c673510193e464a36d6 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 9d42f20434eefbcd1170d40fc0f0afc20b05f705..95b33b88fd4ed65198c15e20265fcec41f0bdfb4 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 7e8f2f0472a973458a62161e4e0c60081b340cae..33840b49eb73a6e0c691df490970da0860e5a3e1 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 40d55e049b65d065334da13016c6566f45d1671e..c9cfc5b755811dd972e0715ae2fb93bf6d8f0b4c 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 33e92d3a71926b0a41b24447e7ae83f8cda03fab..d56b606d70964433de5a1f15ca66ecbcfb9e1584 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 320b629ef12bfd0b8e4844542f946cf0c11691a5..dc006f0ebc95ad5bd43ee02c96e981a13e5c17c1 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 da42db81054a3ee6920633519c54f560dab1914d..be828f0655885a92fa0ce6daee26a52f5dbb57ae 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 a3312e97f37cce57d4eed5462af52f74b511ef9c..e168a75b7f258a16bac954875e0f37941d2a143c 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 e1d6046d668de40323cb20626e20329b32846573..645601154c0d861215b998db2e6a3ab34811790b 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 2822b9683dd5a1c22b7f16034a72269843b83227..e2aa18ea8a41a2b9a7d2117b1556dfc93453b4ed 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 0000000000000000000000000000000000000000..fd6f8546630845101c5827cd03e9b569f62e23ae --- /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 c1c012a010abae1b09021dbd15d1ba3ede5665fb..0b40a60c2e0a5da7688744d1d4d56744b965777a 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 39e4dbb1c7bb02a72d2ec119d8b3f421fc72d23f..4072482b82ddc8bb8a9052f8587f7e0c8d8f9eea 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 885d6c291925e31274a802fec9f43c27432d6f2e..802a27cd4e0980ed08a22dd1ef7f527d3062eb22 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 6a99de084c33ad789966f442d3ad37ee240ed143..f3eb7316cc8173f531ad7b2986163c907e0b1a55 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 01ea9b15c3466785043fd530084aaa081bb25a89..691c8d74a305b8c896dc4129f5c1aa5c0c397b16 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 98c133807fcf1143275d161458569735da4d2337..b1157ef7f422b0d59128c72fd769f93d03dd7798 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 0174d54ddf47669f95a9b19b94628dfed2b42ed6..c92867723bfdce886a4f134e796802c8a2729bbb 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 54e0413810e214091072d5ad35eb43f06e9438ff..5e9c508992c3dfdbb973a0c8fc9be3afd4b91be5 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 a9f435c84bbb5a2d9e46f06eb5609459fd8fdc69..ccba09ad7a02d3acfdfef141920ff3135c2bc6e0 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 075817bb625a43d0094d527eb863905851e5525d..aebcd6434f18e3a42eb76effc76726a9cb103708 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 f27e4c21eb74a8de5b318259f56c95db647e0905..1e4933cf89a8c2d140fa4983e9282ea6db0d6c59 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 0bf65f42549e7fd32e4b920326059a30cc70c0b0..66cf9190a9f773a6b432bd379ab9ddcaead54415 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 13aca2dac8e26184893f7c8444a6f98c8bd0733e..07ef12b9711f78bcad5fd717577b40baa331ee36 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 0000000000000000000000000000000000000000..232ef667b8edc6a3ced8d579b8ae13fb7a09a07f --- /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 2fa6999c858b7274ba856b1da8ffc5050852f965..c1b580f481742ec2a078a971e329749f5f372140 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 570c4d08bb3d8964551c64c39ecfbc396038d8a9..6db4053986472d39c354c732da20d1f142e88639 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 1e71bb1c03ed118eff0dcbf865faa380e99b9dce..884842a60140204e424116e42496ce450ba4b01f 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 a2f63197d1655874fbea3e8a234092556c26eafe..f86efe467c415334c053a6e558b378527b94b4e1 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 4861257029f0fbb6dd8aa0d41bba7298a9017e78..bf97067f995205d5e655bc8ef3b68f38f7125ca4 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 84e548a6df46010eabd8189f5c5accae87f550c2..b8177f6a2499ffa210631bda37227cf1c4d97b10 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 a37cd7015a163c54e1ecbf4b49649045365ca4b9..be2837c8bbd7748362cd973e7919c52ab3f977d7 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 b025cb341b0acd5ea049455465ad15462f08ff8d..246a214b1e5028628529cea0eddef12886b49c6d 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 0000000000000000000000000000000000000000..aa30a96be112e4ab9db5df9ef788bee32efdaf26 --- /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 cfbbf5c7d492ad9088acdafeb82c64f218d0a764..a7324b71405b62c6e2f855dd4334f263019a042f 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 541faa311e716411356ec58d65df47fc496a6c21..bd6b410d084488a6b0a071b1342a4d134b279662 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 55268fa6d253a2bea5a9ab38193ba1d163faa3f6..fdcb092de6313ac35a24a544bc5393b02f1111f7 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 dadac2f5585d9ac0fa0c5eadb8e0789176db3391..26ecf24aa9c6895786bcdf09cc523c08235f007d 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 39979fdcdaacf74955528b495eb939c489c3c43a..8588ff73b82a3f2276698b1f8127a652f726e5c6 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 4b62861cdee704fbdcf4b466309331f2db6a0d86..8b0819e5eb7a51dc9136352d6f7a92657a7d1093 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 f1a1e57137b8404b2b4877be922b58b648cf7ab4..f678a662b4748dd508f63a8396859fc84f2d66aa 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 355cee22530cf4ede51e5bb253228f936dde9887..d00cba0e5ba6c7e1806e28db67dff27e8f3a287a 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 bd2504c0f642974e06bc6038cac363986ffe123c..32bf1aac1de263bfb7f0e1abbadab39257c59de0 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 bce10b04eac4fe3e534d909b6e0e5b63d154990c..7d9fcb521524a455465c2cad96be57761b3cba31 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 48511e8fc8659e072b3f65d8038f0d19869751d3..d770a778facc639f70e926ce52067c306c4f4ef5 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 6c2147ba6ffe7df476b5d56c4536295df5bc27f4..4de2f8ca84d153f410d17a90ded11c5cb0b1c34d 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 7aff240baaa83a66e7b13cd0ada28c7ddd5cb63e..3d6c550350a575aa730fffaf219eaecfef8494b5 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 0588d4f35a901bf4db6ded76ec733bbd5be44651..3fa8f3dc7e60042b49e692d75727c861e7a49e42 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 be1d0b2498255c4e6b122469e20e31889103aabb..0b612bd316fb1f7f1505788b114e546bd24cbe8b 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 f50b2ebb4612086f78b65cee5e07f16756f1c99d..0e109e6cd8e7b324a948c264436622a8c3172b28 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 69efc084d48337ff521a7a876e06028abbd5dd79..4840dbca080f25d035d71b287d5e90dbcc344ea1 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 5ad50d6f17b882b4772e0789745f65fb8c65962b..af7687abf5526c3eb3646e2b4d21e90385183061 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 83aee445aa4bae846d3b9f710ae0a2ac3790e952..266bc6d11296e49737f23efe2b194c91425a1163 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 bd1e88b8da71f44eaee4bac7f66898c24ff65917..cc0363bdbf170026b59860d52ad5705eb6d4132c 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 cae908aa3835d84c3772e0fdb66666d55135b725..aca3addf548afd789a535c800876d46501b03b8b 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 1c0148e46e054ce292ffee28c010eb06d14a1dc6..acf5b4c8ca6203752172f80af105e18f9c75853e 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 8520fba92d8ef20956a352260f7ac62bf9e43559..b8d91fb3ed60ed2a2bedbebb08794f4ba3baf914 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 f3c14bbd8dc91a095de6f059d56e003aaab2c504..47cea1c570986becc3eae3d7bc83a69389da2208 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 a388fd7d7ba98fb9692bc7235beb61cb77ed286e..823681b8abd5628588361f9afe648a17ced6ebee 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 0cde469a4caa06f4dbd4d52b0006fc24b194740a..bb0f91ed8e3d993504ea14d0694b62af4b3afa6a 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 8e03a142894503d721acaf78c8c6a859e7f6aca4..5a1e587a81338069de386acb22014e0aa156c997 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 0a29f9619d589c1c31ac6e5bbc00c5b4d73e3d06..e150754c4a4e3e69287f9b4475527e3f9ef76cb4 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 61887f337dcfb046afaa2b1fc988dabcec3eb825..dc51d8bd2416d786c5430e37501b68c389471efb 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 c0aba08a59ae61ce6b17c0f0eeb8281217109c5d..1a9019bff8174ceefa58a0987270128e8ea943d7 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 263f5c2486a733f22e2f421e6047876996560ad9..395c01fff7084c52f6654a2784f66e45973e4400 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 dddcbf45a56b5bdee22b385706c04f251334aa6c..e26aa3a3a1d9afe52e656b4ab5fcaf0074837c04 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 e3f4752c7bdd92e7d99cf2e9f9e9263e3e7a2d3e..422ae7dfacdd6561656b20cfdc9c78a1132bdf5e 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 0000000000000000000000000000000000000000..ef6544925948eab6ddaad9b681f4331bf2454cfa --- /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 75d430fe03fa174cb23c6142d773db0e2bcac79f..de34d407c409982462bcc70c5f9d7331e037cfd6 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 210e483431146d3f187a61d04b5ee55c932ae50f..82b593bb77055ac1995a84669111126c5a019dee 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 7197f084b72997d7f93d245eb854c4aac5092bdf..f0cbd11d9810ec199785ba8710325fcdd417718e 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 c6d46bcbbb2d8ae5d190d26c4d330de327a25243..e3502a1a5e057022081d99fbb1d3610752c12963 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 e6c8d509b81422e499985e2cfa817a4fcb549efe..439da4835b675e348623714bb0438754b8adc662 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 724cad9394034489585300e076e35d617779b45a..cf9f611bcac76ea48d3919e336eb83ac449d5a20 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 c98b70d2d8586293a71974eeabba0eef98428212..a15785cb4550d50c664fcecd8dc6ffeabe76df9c 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 e0bc09e16a7f9f3bbbbe306c205d0e8019b8a198..225c445e6792f2e828eb43cba61054b4c69499c9 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 acacbceea6d8fb69405d629dd762cd33958c842e..776ab7d2a461e80f958200db517935857b4be2a2 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 dac978f1490b0c8381d2e78a712148db9499a05b..fe4a43d80d5ae2ffddbb75b44f0a5633d70bb43e 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 82937344b553ec6cd128e63f202eec54a79944df..e0a73bd6c5e848b6a60309da312ed3c6e7cd67e7 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 8a9f2fd80cd0b0120b45afa1f9424bf4e4abda59..a9a5c9ee4dee933b043464852a53972c79eb25ff 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 1a7d3d9d76826c7d30b5970c9c5eaedf92701db0..9667de10fbfb03e5ec1ef16c67e385de3611890d 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 ca4e72c9981350df78eef54786e44cb5aac6360d..a0a65cf553bbd8151178a751db20dd55b65bbb83 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 db01cfcc1b603edd189047335377e2c4ec5a7d53..bb31c603d6397bb7dbc49312670ac5b47c0e5c35 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 f5de60f34fdc7a8d8344e644cbd49425ad6db134..684d7324f9f2f20b34dc4620c7adee4788fff6a7 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 9af090b1ff83e81ab90682ec3fb3296de97ed4d7..5015420599bbd645be41244962d7f6909f4bffa7 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 d08cf3b946df563996ac7d07b49ce128ec27c143..c0ea1b0ee75eb77f6c878e7930c3c334a574d5b9 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 9a4fa714f676924dfed17556d4857712492b6b80..3108505ed9779ea00a92b3637be3c8c4c081f707 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 8a4abd6a0c38dae28e54396a1ec043c0abf0957a..6584558c64c01ba4ae4161fe965a5d1e863aea1a 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 e797eb63531779ea26b7f49a6d97ac432ef189a3..8aaedd8d10f21fb520db2eaa90a973e2e41c7f54 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 a60569b18afcd5711e0a5856c64018ce21e4f375..c032d76a7c6be57195c7f260c07bc15bbdf91e88 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 3be5f224a8567604699e97130eb88667aace6098..c63666faf3bf512c328a3c82878f1bc0d1c55198 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 49348fae7f2b304e37e11c914a9bbefcfb9397ef..3baceaa4d9c85f7e270e17f7c760d872e14c6f94 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 a688997b722ec243d969807f77bafe56218bf37d..3591db3d59596f3056cd2450bfcd58f1d7abb615 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 a72b234295299aefca0d276b59b076eeadcd2cc7..efde6162d9466fd3284fd99dcfb1e603a1993e2b 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 5d35fff041ccf333e27a723dd9f910d1f48d32c6..bfaaa3bee2baa500bc1f6b13984230ad9908af7b 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 f1085619bc4bd2b500a51a4c06b80aa04a6b4a1c..c0c586f309c73a00adb0cbb40c3225229c949b59 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 9c678046a3c16297fc20e1c2f778d35a160e43d7..c4a573345e6345d7a1bbd1ab63e12ef7681a9598 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 18b5229b2a4bccd84350f2d1206869fff8f8977f..91aa6f5c31526aec683c6346381c766ebfe7b836 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 3ecc791eeee7d5e2a4edbbee6340594974078197..53ffe63c4e96645dd75821dfbdd3be30f45f056f 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 3d7bece602f1135d16d21eff23c7c31904119f1e..04055df146a93af48b05a10abe4e1e71f5814979 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 b1ad26a76025a15d68292c67555ed43ea83147a5..753b7f0ae47b2a8fdb25e5ca688b0d4270d953b3 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 5d5d8099724a4f43ebb8f5e89f0f51b0738cab4a..59d334053d4f3cfbdd80cefad1f1982151a7cab8 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 d3be7483c5d29e9f8e3bdc2aac72546b3a4415fa..8bd12e3cf8e232216750ed6b0087cd06772453f2 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 efd9f2f8d74c50df6e5483de935f797489e15b9a..1afc8c3c7d673d75f495f0d69666d34441064cc0 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 7595caf29d818f82ed10b543c5ab1002fe901545..8f63b835f7ace13935f75e9ef6a0b25be2c7782d 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 3a820f0faf3c9db65cd864654bf7818fb9224cb1..267f6be774b3ffe3f66cdb2f0ad7b4ae94c14fe2 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 340aa9257cda12b093a6d8a82ebda59b8d3ec26f..29c59f3d1e47abd75db76bbd64bd755abd6cc89b 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 91089a0446c0106991039d65343be1322625fc5e..1103de32c9c1df66ead4d16e2283f8a1fc9ca2e0 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 7078f9a280a710d731a63ab08ade309588115f9b..713cbe91a6da245939351c5e64568e9da42760ec 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 e48be250c5ec58419a3f9ced34c29d7b15319024..17f636305561bde208000d0a9adc295558695c48 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 9e2837be997ce4221f139dc2f993b5db7155726b..3f331ad8f129056fd8921639970e6819fcd7c154 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 378649d4fa06b22a25cc1d38b40ddbe1522d1113..fd002c972ef6370ebe66ad9686392a8463a34e37 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 d3943838cb746bacca996da7b8057851a94ed71b..ee85fa23b3468cbe5c907b76e344e904d50df46a 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 eb1a799b7a4248b6e1f21aaecc5c1c888fcaa328..f1bc9452156f10911829d79a4c698b8bde508cde 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": {