diff --git a/block/miniblock.go b/block/miniblock.go index ab91583..d21ad15 100644 --- a/block/miniblock.go +++ b/block/miniblock.go @@ -18,6 +18,8 @@ package block import "fmt" import "time" +import "hash" +import "sync" import "strings" import "encoding/binary" @@ -28,6 +30,10 @@ import "github.com/deroproject/derohe/pow" const MINIBLOCK_SIZE = 68 +var hasherPool = sync.Pool{ + New: func() interface{} { return sha3.New256() }, +} + // it should be exactly 68 bytes after serialization // structure size 1 + 6 + 4 + 4 + 16 +32 + 5 bytes type MiniBlock struct { @@ -91,9 +97,17 @@ func (mbl *MiniBlock) GetMiniID() uint32 { } // this function gets the block identifier hash, this is only used to deduplicate mini blocks -func (mbl *MiniBlock) GetHash() (hash crypto.Hash) { +func (mbl *MiniBlock) GetHash() (result crypto.Hash) { ser := mbl.Serialize() - return sha3.Sum256(ser[:]) + sha := hasherPool.Get().(hash.Hash) + sha.Reset() + sha.Write(ser[:]) + x := sha.Sum(nil) + copy(result[:], x[:]) + hasherPool.Put(sha) + return result + + // return sha3.Sum256(ser[:]) } // Get PoW hash , this is very slow function diff --git a/block/miniblockdag.go b/block/miniblockdag.go index b67d1e8..4d66cf7 100644 --- a/block/miniblockdag.go +++ b/block/miniblockdag.go @@ -192,7 +192,7 @@ func (c *MiniBlocksCollection) GetAllTips() (mbls []MiniBlock) { clone := map[uint32]MiniBlock{} - var clone_list []MiniBlock + clone_list := make([]MiniBlock, 0, 64) for k, v := range c.Collection { clone[k] = v clone_list = append(clone_list, v) @@ -273,6 +273,8 @@ func (c *MiniBlocksCollection) GetGenesisFromMiniBlock(mbl MiniBlock) (genesis [ // this works in all cases, but it may return truncated history,all returns must be checked for connectivity func (c *MiniBlocksCollection) GetEntireMiniBlockHistory(mbl MiniBlock) (history []MiniBlock) { + + history = make([]MiniBlock, 0, 128) if mbl.Genesis { history = append(history, mbl) return @@ -301,6 +303,7 @@ func (c *MiniBlocksCollection) GetEntireMiniBlockHistory(mbl MiniBlock) (history // gets the genesis from the tips // this function only works, if the miniblock has been expanded func GetGenesisFromMiniBlock(mbl MiniBlock) (genesis []MiniBlock) { + if mbl.Genesis { genesis = append(genesis, mbl) return @@ -325,20 +328,36 @@ func GetGenesisFromMiniBlock(mbl MiniBlock) (genesis []MiniBlock) { // get entire history,its in sorted form func GetEntireMiniBlockHistory(mbls ...MiniBlock) (history []MiniBlock) { - var queue []MiniBlock + queue := make([]MiniBlock, 0, 128) queue = append(queue, mbls...) + history = make([]MiniBlock, 0, 128) + unique := make([]MiniBlock, 0, 128) + + unique_map := map[crypto.Hash]MiniBlock{} for len(queue) > 0 { item := queue[0] queue = queue[1:] // Dequeue - history = append(history, item) //mini blocks might be duplicated - if !item.Genesis { - queue = append(queue, item.PastMiniBlocks...) + if _, ok := unique_map[item.GetHash()]; !ok { + unique_map[item.GetHash()] = item + history = append(history, item) //mini blocks might be duplicated + if !item.Genesis { + queue = append(queue, item.PastMiniBlocks...) + } } } + for _, v := range unique_map { + unique = append(unique, v) + } + history = MiniBlocks_Unique(history) + + if len(unique) != len(history) { + panic("result mismatch") + } + history = MiniBlocks_SortByTimeAsc(history) // sort on the basis of timestamps return @@ -347,6 +366,7 @@ func GetEntireMiniBlockHistory(mbls ...MiniBlock) (history []MiniBlock) { // this sorts by distance, in descending order // if distance is equal, then it sorts by its id which is collision free func MiniBlocks_SortByDistanceDesc(mbls []MiniBlock) (sorted []MiniBlock) { + sorted = make([]MiniBlock, 0, len(mbls)) sorted = append(sorted, mbls...) sort.SliceStable(sorted, func(i, j int) bool { // sort descending on the basis of Distance if sorted[i].Distance == sorted[j].Distance { @@ -360,6 +380,7 @@ func MiniBlocks_SortByDistanceDesc(mbls []MiniBlock) (sorted []MiniBlock) { // this sorts by timestamp,ascending order // if timestamp is equal, then it sorts by its id which is collision free func MiniBlocks_SortByTimeAsc(mbls []MiniBlock) (sorted []MiniBlock) { + sorted = make([]MiniBlock, 0, len(mbls)) sorted = append(sorted, mbls...) sort.SliceStable(sorted, func(i, j int) bool { // sort on the basis of timestamps if sorted[i].Timestamp == sorted[j].Timestamp { @@ -371,6 +392,7 @@ func MiniBlocks_SortByTimeAsc(mbls []MiniBlock) (sorted []MiniBlock) { } func MiniBlocks_Unique(mbls []MiniBlock) (unique []MiniBlock) { + unique = make([]MiniBlock, 0, len(mbls)) unique_map := map[crypto.Hash]MiniBlock{} for _, mbl := range mbls { unique_map[mbl.GetHash()] = mbl diff --git a/blockchain/blockchain.go b/blockchain/blockchain.go index 925ee83..27f74a5 100644 --- a/blockchain/blockchain.go +++ b/blockchain/blockchain.go @@ -71,6 +71,7 @@ type Blockchain struct { cache_Get_Difficulty_At_Tips *lru.Cache // used to cache some outputs cache_BlockPast *lru.Cache // used to cache a blocks past cache_BlockHeight *lru.Cache // used to cache a blocks past + cache_VersionMerkle *lru.Cache // used to cache a versions merkle root integrator_address rpc.Address // integrator rewards will be given to this address @@ -153,11 +154,15 @@ func Blockchain_Start(params map[string]interface{}) (*Blockchain, error) { return nil, err } - if chain.cache_BlockPast, err = lru.New(100 * 1024); err != nil { // temporary cache for a blocks past + if chain.cache_BlockPast, err = lru.New(1024); err != nil { // temporary cache for a blocks past return nil, err } - if chain.cache_BlockHeight, err = lru.New(100 * 1024); err != nil { // temporary cache for a blocks height + if chain.cache_BlockHeight, err = lru.New(10 * 1024); err != nil { // temporary cache for a blocks height + return nil, err + } + + if chain.cache_VersionMerkle, err = lru.New(1024); err != nil { // temporary cache for a snapshot version return nil, err } @@ -231,11 +236,11 @@ func Blockchain_Start(params map[string]interface{}) (*Blockchain, error) { top_block_topo_index := chain.Load_TOPO_HEIGHT() - if top_block_topo_index < 10 { + if top_block_topo_index < 4 { return } - top_block_topo_index -= 10 + top_block_topo_index -= 4 blid, err := chain.Load_Block_Topological_order_at_index(top_block_topo_index) if err != nil { @@ -689,7 +694,7 @@ func (chain *Blockchain) Add_Complete_Block(cbl *block.Complete_Block) (err erro if tx.SCDATA.Has(rpc.SCACTION, rpc.DataUint64) { if rpc.SC_INSTALL == rpc.SC_ACTION(tx.SCDATA.Value(rpc.SCACTION, rpc.DataUint64).(uint64)) { txid := tx.GetHash() - if txid[31] < 0x80 { // last byte should be more than 0x80 + if txid[0] < 0x80 || txid[31] < 0x80 { // last byte should be more than 0x80 block_logger.Error(fmt.Errorf("Invalid SCID"), "SCID installing tx must end with >0x80 byte", "txid", cbl.Txs[i].GetHash()) return errormsg.ErrTXDoubleSpend, false } @@ -1188,6 +1193,17 @@ func (chain *Blockchain) Add_TX_To_Pool(tx *transaction.Transaction) error { return err } + if tx.TransactionType == transaction.SC_TX { + if tx.SCDATA.Has(rpc.SCACTION, rpc.DataUint64) { + if rpc.SC_INSTALL == rpc.SC_ACTION(tx.SCDATA.Value(rpc.SCACTION, rpc.DataUint64).(uint64)) { + txid := tx.GetHash() + if txid[0] < 0x80 || txid[31] < 0x80 { // last byte should be more than 0x80 + return fmt.Errorf("Invalid SCID ID,it must not start with 0x80") + } + } + } + } + if err := chain.Verify_Transaction_NonCoinbase_CheckNonce_Tips(hf_version, tx, chain.Get_TIPS()); err != nil { // transaction verification failed logger.V(1).Error(err, "Incoming TX nonce verification failed", "txid", txhash, "stacktrace", globals.StackTrace(false)) return fmt.Errorf("Incoming TX %s nonce verification failed, err %s", txhash, err) diff --git a/blockchain/store.go b/blockchain/store.go index 8f59485..0924d48 100644 --- a/blockchain/store.go +++ b/blockchain/store.go @@ -18,7 +18,6 @@ package blockchain import "fmt" import "math/big" -import "crypto/rand" import "path/filepath" import "github.com/deroproject/derohe/globals" @@ -55,9 +54,7 @@ func (s *storage) Initialize(params map[string]interface{}) (err error) { } func (s *storage) IsBalancesIntialized() bool { - var err error - var buf [64]byte var balancehash, random_hash [32]byte balance_ss, _ := s.Balance_store.LoadSnapshot(0) // load most recent snapshot @@ -65,12 +62,10 @@ func (s *storage) IsBalancesIntialized() bool { // avoid hardcoding any hash if balancehash, err = balancetree.Hash(); err == nil { - if _, err = rand.Read(buf[:]); err == nil { - random_tree, _ := balance_ss.GetTree(string(buf[:])) - if random_hash, err = random_tree.Hash(); err == nil { - if random_hash == balancehash { - return false - } + random_tree, _ := balance_ss.GetTree(config.SC_META) + if random_hash, err = random_tree.Hash(); err == nil { + if random_hash == balancehash { + return false } } } @@ -300,6 +295,11 @@ func (chain *Blockchain) Load_Block_Topological_order_at_index(index_pos int64) //load store hash from 2 tree func (chain *Blockchain) Load_Merkle_Hash(version uint64) (hash crypto.Hash, err error) { + if hashi, ok := chain.cache_VersionMerkle.Get(version); ok { + hash = hashi.(crypto.Hash) + return + } + ss, err := chain.Store.Balance_store.LoadSnapshot(version) if err != nil { return @@ -324,5 +324,9 @@ func (chain *Blockchain) Load_Merkle_Hash(version uint64) (hash crypto.Hash, err for i := range balance_merkle_hash { hash[i] = balance_merkle_hash[i] ^ meta_merkle_hash[i] } + + if chain.cache_enabled { //set in cache + chain.cache_VersionMerkle.Add(version, hash) + } return hash, nil } diff --git a/blockchain/transaction_verify.go b/blockchain/transaction_verify.go index 9aab297..65097c9 100644 --- a/blockchain/transaction_verify.go +++ b/blockchain/transaction_verify.go @@ -49,7 +49,7 @@ func clean_up_valid_cache() { current_time := time.Now() transaction_valid_cache.Range(func(k, value interface{}) bool { first_seen := value.(time.Time) - if current_time.Sub(first_seen).Round(time.Second).Seconds() > 3600 { + if current_time.Sub(first_seen).Round(time.Second).Seconds() > 360 { transaction_valid_cache.Delete(k) } return true diff --git a/cmd/derod/main.go b/cmd/derod/main.go index 9a50f5a..bbd7a5f 100644 --- a/cmd/derod/main.go +++ b/cmd/derod/main.go @@ -26,6 +26,7 @@ import "bufio" import "strings" import "strconv" import "runtime" +import "runtime/debug" import "math/big" import "os/signal" import "io/ioutil" @@ -89,9 +90,24 @@ var Exit_In_Progress = make(chan bool) var logger logr.Logger +func dump(filename string) { + f, err := os.Create(filename) + if err != nil { + fmt.Printf("err creating file %s\n", err) + return + } + + runtime.GC() + debug.WriteHeapDump(f.Fd()) + + err = f.Close() + if err != nil { + fmt.Printf("err closing file %s\n", err) + } +} + func main() { var err error - globals.Arguments, err = docopt.Parse(command_line, nil, true, config.Version.String(), false) if err != nil { @@ -781,6 +797,12 @@ restart_loop: case command == "gc": runtime.GC() + case command == "heap": + if len(line_parts) == 1 { + fmt.Printf("heap needs a filename to write\n") + break + } + dump(line_parts[1]) case command == "ban": diff --git a/config/config.go b/config/config.go index 88c3f20..51b76fb 100644 --- a/config/config.go +++ b/config/config.go @@ -103,7 +103,7 @@ var Mainnet = CHAIN_CONFIG{Name: "mainnet", } var Testnet = CHAIN_CONFIG{Name: "testnet", // testnet will always have last 3 bytes 0 - Network_ID: uuid.FromBytesOrNil([]byte{0x59, 0xd7, 0xf7, 0xe9, 0xdd, 0x48, 0xd5, 0xfd, 0x13, 0x0a, 0xf6, 0xe0, 0x70, 0x00, 0x00, 0x00}), + Network_ID: uuid.FromBytesOrNil([]byte{0x59, 0xd7, 0xf7, 0xe9, 0xdd, 0x48, 0xd5, 0xfd, 0x13, 0x0a, 0xf6, 0xe0, 0x71, 0x00, 0x00, 0x00}), P2P_Default_Port: 40401, RPC_Default_Port: 40402, Wallet_RPC_Default_Port: 40403, diff --git a/config/seed_nodes.go b/config/seed_nodes.go index 92837e9..66a1cb9 100644 --- a/config/seed_nodes.go +++ b/config/seed_nodes.go @@ -30,4 +30,5 @@ var Mainnet_seed_nodes = []string{ // some seed node for testnet var Testnet_seed_nodes = []string{ "68.183.12.117:40401", + "167.99.145.53:40401", } diff --git a/config/version.go b/config/version.go index 6b08ad0..cdf9989 100644 --- a/config/version.go +++ b/config/version.go @@ -20,4 +20,4 @@ import "github.com/blang/semver/v4" // right now it has to be manually changed // do we need to include git commitsha?? -var Version = semver.MustParse("3.4.87-1.DEROHE.STARGATE+24112021") +var Version = semver.MustParse("3.4.89-1.DEROHE.STARGATE+22112021") diff --git a/vendor/github.com/creachadair/jrpc2/base.go b/vendor/github.com/creachadair/jrpc2/base.go index 2b225f9..c595a9c 100644 --- a/vendor/github.com/creachadair/jrpc2/base.go +++ b/vendor/github.com/creachadair/jrpc2/base.go @@ -14,6 +14,8 @@ import ( // no method is available to handle the request. type Assigner interface { // Assign returns the handler for the named method, or nil. + // The implementation can obtain the complete request from ctx using the + // jrpc2.InboundRequest function. Assign(ctx context.Context, method string) Handler // Names returns a slice of all known method names for the assigner. The diff --git a/vendor/github.com/creachadair/jrpc2/channel/channel.go b/vendor/github.com/creachadair/jrpc2/channel/channel.go index 1519a8c..6bae36f 100644 --- a/vendor/github.com/creachadair/jrpc2/channel/channel.go +++ b/vendor/github.com/creachadair/jrpc2/channel/channel.go @@ -1,6 +1,8 @@ -// Package channel defines a communications channel that can encode/transmit -// and decode/receive data records with a configurable framing discipline, and -// provides some simple framing implementations. +// Package channel defines a basic communications channel. +// +// A Channel encodes/transmits and decodes/receives data records over an +// unstructured stream, using a configurable framing discipline. This package +// provides some basic framing implementations. // // Channels // diff --git a/vendor/github.com/creachadair/jrpc2/channel/json.go b/vendor/github.com/creachadair/jrpc2/channel/json.go index 6fe33e4..13639f0 100644 --- a/vendor/github.com/creachadair/jrpc2/channel/json.go +++ b/vendor/github.com/creachadair/jrpc2/channel/json.go @@ -10,6 +10,10 @@ const bufSize = 4096 // RawJSON is a framing that transmits and receives records on r and wc, in which // each record is defined by being a complete JSON value. No padding or other // separation is added. +// +// A RawJSON channel has no out-of-band framing, so the channel cannot usually +// recover after a message that is not syntactically valid JSON. Applications +// that need a channel to survive invalid JSON should avoid this framing. func RawJSON(r io.Reader, wc io.WriteCloser) Channel { return jsonc{wc: wc, dec: json.NewDecoder(r), buf: make([]byte, bufSize)} } diff --git a/vendor/github.com/creachadair/jrpc2/code/code.go b/vendor/github.com/creachadair/jrpc2/code/code.go index ece0f4a..ac3e09f 100644 --- a/vendor/github.com/creachadair/jrpc2/code/code.go +++ b/vendor/github.com/creachadair/jrpc2/code/code.go @@ -57,18 +57,16 @@ func (c Code) Err() error { return codeError(c) } -// Pre-defined standard error codes defined by the JSON-RPC specification. +// Error codes from and including -32768 to -32000 are reserved for pre-defined +// errors by the JSON-RPC specification. These constants cover the standard +// codes and implementation-specific codes used by the jrpc2 module. const ( - ParseError Code = -32700 // Invalid JSON received by the server - InvalidRequest Code = -32600 // The JSON sent is not a valid request object - MethodNotFound Code = -32601 // The method does not exist or is unavailable - InvalidParams Code = -32602 // Invalid method parameters - InternalError Code = -32603 // Internal JSON-RPC error -) + ParseError Code = -32700 // [std] Invalid JSON received by the server + InvalidRequest Code = -32600 // [std] The JSON sent is not a valid request object + MethodNotFound Code = -32601 // [std] The method does not exist or is unavailable + InvalidParams Code = -32602 // [std] Invalid method parameters + InternalError Code = -32603 // [std] Internal JSON-RPC error -// The JSON-RPC 2.0 specification reserves the range -32000 to -32099 for -// implementation-defined server errors. These are used by the jrpc2 package. -const ( NoError Code = -32099 // Denotes a nil error (used by FromError) SystemError Code = -32098 // Errors from the operating environment Cancelled Code = -32097 // Request cancelled (context.Canceled) @@ -91,6 +89,10 @@ var stdError = map[Code]string{ // Register adds a new Code value with the specified message string. This // function will panic if the proposed value is already registered with a // different string. +// +// Registering a code allows you to control the string returned by the String +// method for the code value you specify. It is not necessary to register a +// code before using it. An unregistered code renders a generic string. func Register(value int32, message string) Code { code := Code(value) if s, ok := stdError[code]; ok && s != message { @@ -102,7 +104,7 @@ func Register(value int32, message string) Code { // FromError returns a Code to categorize the specified error. // If err == nil, it returns code.NoError. -// If err is an ErrCoder, it returns the reported code value. +// If err is (or wraps) an ErrCoder, it returns the reported code value. // If err is context.Canceled, it returns code.Cancelled. // If err is context.DeadlineExceeded, it returns code.DeadlineExceeded. // Otherwise it returns code.SystemError. diff --git a/vendor/github.com/creachadair/jrpc2/doc.go b/vendor/github.com/creachadair/jrpc2/doc.go index 80366b3..013f994 100644 --- a/vendor/github.com/creachadair/jrpc2/doc.go +++ b/vendor/github.com/creachadair/jrpc2/doc.go @@ -84,7 +84,7 @@ To create a client we need a channel: conn, err := net.Dial("tcp", "localhost:8080") ... - ch := channel.RawJSON(conn, conn) + ch := channel.Line(conn, conn) cli := jrpc2.NewClient(ch, nil) // nil for default options To send a single RPC, use the Call method: diff --git a/vendor/github.com/creachadair/jrpc2/error.go b/vendor/github.com/creachadair/jrpc2/error.go index 39c9a54..161429d 100644 --- a/vendor/github.com/creachadair/jrpc2/error.go +++ b/vendor/github.com/creachadair/jrpc2/error.go @@ -47,10 +47,6 @@ var errEmptyMethod = &Error{Code: code.InvalidRequest, Message: "empty method na // errInvalidRequest is the error reported for an invalid request object or batch. var errInvalidRequest = &Error{Code: code.ParseError, Message: "invalid request value"} -// errChannelClosed is the error reported to a pending callback when the client -// channel has closed before the call completed. -var errChannelClosed = &Error{Code: code.Cancelled, Message: "client channel terminated"} - // errEmptyBatch is the error reported for an empty request batch. var errEmptyBatch = &Error{Code: code.InvalidRequest, Message: "empty request batch"} diff --git a/vendor/github.com/creachadair/jrpc2/examples_test.go b/vendor/github.com/creachadair/jrpc2/examples_test.go index 3f96071..61c46ed 100644 --- a/vendor/github.com/creachadair/jrpc2/examples_test.go +++ b/vendor/github.com/creachadair/jrpc2/examples_test.go @@ -7,52 +7,44 @@ import ( "fmt" "log" "strings" - "sync" "github.com/creachadair/jrpc2" - "github.com/creachadair/jrpc2/channel" "github.com/creachadair/jrpc2/code" "github.com/creachadair/jrpc2/handler" + "github.com/creachadair/jrpc2/server" ) var ( - s *jrpc2.Server - - ctx = context.Background() - sch, cch = channel.Direct() - cli = jrpc2.NewClient(cch, nil) - - setup sync.Once + ctx = context.Background() ) type Msg struct { Text string `json:"msg"` } -func startServer() { - setup.Do(func() { - s = jrpc2.NewServer(handler.Map{ - "Hello": handler.New(func(ctx context.Context) string { - return "Hello, world!" - }), - "Echo": handler.New(func(_ context.Context, args []json.RawMessage) []json.RawMessage { - return args - }), - "Log": handler.New(func(ctx context.Context, msg Msg) (bool, error) { - fmt.Println("Log:", msg.Text) - return true, nil - }), - }, nil).Start(sch) - }) +func startServer() server.Local { + return server.NewLocal(handler.Map{ + "Hello": handler.New(func(ctx context.Context) string { + return "Hello, world!" + }), + "Echo": handler.New(func(_ context.Context, args []json.RawMessage) []json.RawMessage { + return args + }), + "Log": handler.New(func(ctx context.Context, msg Msg) (bool, error) { + fmt.Println("Log:", msg.Text) + return true, nil + }), + }, nil) } func ExampleNewServer() { // Construct a new server with methods "Hello" and "Log". - startServer() + loc := startServer() + defer loc.Close() // We can query the server for its current status information, including a // list of its methods. - si := s.ServerInfo() + si := loc.Server.ServerInfo() fmt.Println(strings.Join(si.Methods, "\n")) // Output: @@ -62,10 +54,10 @@ func ExampleNewServer() { } func ExampleClient_Call() { - startServer() + loc := startServer() + defer loc.Close() - // var cli = jrpc2.NewClient(cch, nil) - rsp, err := cli.Call(ctx, "Hello", nil) + rsp, err := loc.Client.Call(ctx, "Hello", nil) if err != nil { log.Fatalf("Call: %v", err) } @@ -79,11 +71,11 @@ func ExampleClient_Call() { } func ExampleClient_CallResult() { - startServer() + loc := startServer() + defer loc.Close() - // var cli = jrpc2.NewClient(cch, nil) var msg string - if err := cli.CallResult(ctx, "Hello", nil, &msg); err != nil { + if err := loc.Client.CallResult(ctx, "Hello", nil, &msg); err != nil { log.Fatalf("CallResult: %v", err) } fmt.Println(msg) @@ -92,10 +84,10 @@ func ExampleClient_CallResult() { } func ExampleClient_Batch() { - startServer() + loc := startServer() + defer loc.Close() - // var cli = jrpc2.NewClient(cch, nil) - rsps, err := cli.Batch(ctx, []jrpc2.Spec{ + rsps, err := loc.Client.Batch(ctx, []jrpc2.Spec{ {Method: "Hello"}, {Method: "Log", Params: Msg{"Sing it!"}, Notify: true}, }) @@ -172,8 +164,10 @@ type strictParams struct { func (strictParams) DisallowUnknownFields() {} func ExampleResponse_UnmarshalResult() { - // var cli = jrpc2.NewClient(cch, nil) - rsp, err := cli.Call(ctx, "Echo", []string{"alpha", "oscar", "kilo"}) + loc := startServer() + defer loc.Close() + + rsp, err := loc.Client.Call(ctx, "Echo", []string{"alpha", "oscar", "kilo"}) if err != nil { log.Fatalf("Call: %v", err) } diff --git a/vendor/github.com/creachadair/jrpc2/handler/handler.go b/vendor/github.com/creachadair/jrpc2/handler/handler.go index 921d18a..6478fe7 100644 --- a/vendor/github.com/creachadair/jrpc2/handler/handler.go +++ b/vendor/github.com/creachadair/jrpc2/handler/handler.go @@ -88,6 +88,17 @@ func New(fn interface{}) Func { return fi.Wrap() } +// NewStrict acts as New, but enforces strict field checking on an argument of +// struct type. +func NewStrict(fn interface{}) Func { + fi, err := Check(fn) + if err != nil { + panic(err) + } + fi.strictFields = true + return fi.Wrap() +} + var ( ctxType = reflect.TypeOf((*context.Context)(nil)).Elem() // type context.Context errType = reflect.TypeOf((*error)(nil)).Elem() // type error @@ -355,8 +366,8 @@ func (o Obj) UnmarshalJSON(data []byte) error { if err := json.Unmarshal(data, &base); err != nil { return filterJSONError("decoding", "object", err) } - for key, val := range base { - arg, ok := o[key] + for key, arg := range o { + val, ok := base[key] if !ok { continue } else if err := json.Unmarshal(val, arg); err != nil { diff --git a/vendor/github.com/creachadair/jrpc2/handler/handler_test.go b/vendor/github.com/creachadair/jrpc2/handler/handler_test.go index c2aaaac..47fe0cb 100644 --- a/vendor/github.com/creachadair/jrpc2/handler/handler_test.go +++ b/vendor/github.com/creachadair/jrpc2/handler/handler_test.go @@ -7,6 +7,7 @@ import ( "testing" "github.com/creachadair/jrpc2" + "github.com/creachadair/jrpc2/code" "github.com/creachadair/jrpc2/handler" "github.com/google/go-cmp/cmp" ) @@ -111,6 +112,26 @@ func TestPositional(t *testing.T) { } } +func TestNewStrict(t *testing.T) { + type arg struct { + A, B string + } + fn := handler.NewStrict(func(ctx context.Context, arg *arg) error { return nil }) + + req := mustParseRequest(t, `{ + "jsonrpc": "2.0", + "id": 100, + "method": "f", + "params": { + "A": "foo", + "Z": 25 + }}`) + rsp, err := fn(context.Background(), req) + if got := code.FromError(err); got != code.InvalidParams { + t.Errorf("Handler returned (%+v, %v), want InvalidParms", rsp, err) + } +} + // Verify that the handling of pointer-typed arguments does not incorrectly // introduce another pointer indirection. func TestNew_pointerRegression(t *testing.T) { @@ -120,18 +141,15 @@ func TestNew_pointerRegression(t *testing.T) { t.Logf("Got argument struct: %+v", got) return nil }) - req, err := jrpc2.ParseRequests([]byte(`{ + req := mustParseRequest(t, `{ "jsonrpc": "2.0", "id": "foo", "method": "bar", "params":{ "alpha": "xyzzy", "bravo": 23 - }}`)) - if err != nil { - t.Fatalf("Parse request failed: %v", err) - } - if _, err := call.Handle(context.Background(), req[0]); err != nil { + }}`) + if _, err := call.Handle(context.Background(), req); err != nil { t.Errorf("Handle failed: %v", err) } want := argStruct{A: "xyzzy", B: 23} @@ -165,11 +183,8 @@ func TestPositional_decode(t *testing.T) { {`{"jsonrpc":"2.0","id":6,"method":"add","params":{"unknown":"field"}}`, 0, true}, } for _, test := range tests { - req, err := jrpc2.ParseRequests([]byte(test.input)) - if err != nil { - t.Fatalf("ParseRequests %#q: unexpected error: %v", test.input, err) - } - got, err := call(context.Background(), req[0]) + req := mustParseRequest(t, test.input) + got, err := call(context.Background(), req) if !test.bad { if err != nil { t.Errorf("Call %#q: unexpected error: %v", test.input, err) @@ -360,3 +375,14 @@ func TestObjUnmarshal(t *testing.T) { } } } + +func mustParseRequest(t *testing.T, text string) *jrpc2.Request { + t.Helper() + req, err := jrpc2.ParseRequests([]byte(text)) + if err != nil { + t.Fatalf("ParseRequests: %v", err) + } else if len(req) != 1 { + t.Fatalf("Wrong number of requests: got %d, want 1", len(req)) + } + return req[0] +} diff --git a/vendor/github.com/creachadair/jrpc2/opts.go b/vendor/github.com/creachadair/jrpc2/opts.go index e74dfa7..33ef88b 100644 --- a/vendor/github.com/creachadair/jrpc2/opts.go +++ b/vendor/github.com/creachadair/jrpc2/opts.go @@ -278,7 +278,7 @@ func (lg Logger) Printf(msg string, args ...interface{}) { } // StdLogger adapts a *log.Logger to a Logger. If logger == nil, the returned -// function sends logs to the default logger . +// function sends logs to the default logger. func StdLogger(logger *log.Logger) Logger { if logger == nil { return func(text string) { log.Output(2, text) } diff --git a/vendor/github.com/creachadair/jrpc2/server.go b/vendor/github.com/creachadair/jrpc2/server.go index edc5aae..eaac58f 100644 --- a/vendor/github.com/creachadair/jrpc2/server.go +++ b/vendor/github.com/creachadair/jrpc2/server.go @@ -465,14 +465,15 @@ func (s *Server) pushReq(ctx context.Context, wantID bool, method string, params id := strconv.FormatInt(s.callID, 10) s.callID++ + cbctx, cancel := context.WithCancel(ctx) jid = json.RawMessage(id) rsp = &Response{ ch: make(chan *jmessage, 1), id: id, - cancel: func() {}, + cancel: cancel, } s.call[id] = rsp - go s.waitCallback(ctx, id, rsp) + go s.waitCallback(cbctx, id, rsp) } s.log("Posting server %s %q %s", kind, method, string(bits)) @@ -575,11 +576,8 @@ func (s *Server) stop(err error) { // Cancel any in-flight requests that made it out of the queue, and // terminate any pending callback invocations. for id, rsp := range s.call { - rsp.ch <- &jmessage{ - ID: json.RawMessage(id), - E: errChannelClosed, - } delete(s.call, id) + rsp.cancel() } for id, cancel := range s.used { cancel() diff --git a/vendor/github.com/creachadair/jrpc2/tools/examples/client/client.go b/vendor/github.com/creachadair/jrpc2/tools/examples/client/client.go index f89e378..da56f35 100644 --- a/vendor/github.com/creachadair/jrpc2/tools/examples/client/client.go +++ b/vendor/github.com/creachadair/jrpc2/tools/examples/client/client.go @@ -65,7 +65,7 @@ func main() { log.Printf("Connected to %v", conn.RemoteAddr()) // Start up the client, and enable logging to stderr. - cli := jrpc2.NewClient(channel.RawJSON(conn, conn), &jrpc2.ClientOptions{ + cli := jrpc2.NewClient(channel.Line(conn, conn), &jrpc2.ClientOptions{ OnNotify: func(req *jrpc2.Request) { var params json.RawMessage req.UnmarshalParams(¶ms) diff --git a/vendor/github.com/creachadair/jrpc2/tools/examples/server/server.go b/vendor/github.com/creachadair/jrpc2/tools/examples/server/server.go index a466640..e5db2e0 100644 --- a/vendor/github.com/creachadair/jrpc2/tools/examples/server/server.go +++ b/vendor/github.com/creachadair/jrpc2/tools/examples/server/server.go @@ -96,7 +96,7 @@ func main() { log.Fatalln("Listen:", err) } log.Printf("Listening at %v...", lst.Addr()) - acc := server.NetAccepter(lst, channel.RawJSON) + acc := server.NetAccepter(lst, channel.Line) server.Loop(acc, server.Static(mux), &server.LoopOptions{ ServerOptions: &jrpc2.ServerOptions{ Logger: jrpc2.StdLogger(nil), diff --git a/vendor/github.com/creachadair/jrpc2/tools/go.mod b/vendor/github.com/creachadair/jrpc2/tools/go.mod index 53cb9ad..465ade4 100644 --- a/vendor/github.com/creachadair/jrpc2/tools/go.mod +++ b/vendor/github.com/creachadair/jrpc2/tools/go.mod @@ -3,8 +3,8 @@ module github.com/creachadair/jrpc2/tools go 1.17 require ( - github.com/creachadair/jrpc2 v0.30.1 - github.com/creachadair/wschannel v0.0.0-20210930050814-ee1a57283ef3 + github.com/creachadair/jrpc2 v0.30.3 + github.com/creachadair/wschannel v0.0.0-20211118152247-10d58f4f0def ) require ( diff --git a/vendor/github.com/creachadair/jrpc2/tools/go.sum b/vendor/github.com/creachadair/jrpc2/tools/go.sum index e134828..a9443f1 100644 --- a/vendor/github.com/creachadair/jrpc2/tools/go.sum +++ b/vendor/github.com/creachadair/jrpc2/tools/go.sum @@ -1,8 +1,7 @@ -github.com/creachadair/jrpc2 v0.26.0/go.mod h1:w+GXZGc+NwsH0xsUOgeLBIIRM0jBOSTXhv28KaWGRZU= -github.com/creachadair/jrpc2 v0.30.1 h1:brsyJY1US3f5mxS3IaYoc8kH2O1MNcWUKiBmGswUeE8= -github.com/creachadair/jrpc2 v0.30.1/go.mod h1:w+GXZGc+NwsH0xsUOgeLBIIRM0jBOSTXhv28KaWGRZU= -github.com/creachadair/wschannel v0.0.0-20210930050814-ee1a57283ef3 h1:b0LJF4h+tv81wui0UKrszHi+yny5B/UJA10bHimYy0Y= -github.com/creachadair/wschannel v0.0.0-20210930050814-ee1a57283ef3/go.mod h1:ZW4LjPekGnPGBDEgssmCLAOIObRDGv2SQay/pT+5ZwM= +github.com/creachadair/jrpc2 v0.30.3 h1:fz8xYfTmIgxJXvr9HAoz0XBOpNklyixE7Hnh6iQP/4o= +github.com/creachadair/jrpc2 v0.30.3/go.mod h1:w+GXZGc+NwsH0xsUOgeLBIIRM0jBOSTXhv28KaWGRZU= +github.com/creachadair/wschannel v0.0.0-20211118152247-10d58f4f0def h1:FV0vHCqItsi0b3LwaEKyxj0su3VKdvbenCOkXnCAXnI= +github.com/creachadair/wschannel v0.0.0-20211118152247-10d58f4f0def/go.mod h1:/9Csuxj8r9h0YXexL0WmkahIhd85BleYWz7nt42ZgDc= github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= diff --git a/walletapi/transaction_build.go b/walletapi/transaction_build.go index 57cac46..4ac8195 100644 --- a/walletapi/transaction_build.go +++ b/walletapi/transaction_build.go @@ -280,7 +280,7 @@ rebuild_tx: if tx.SCDATA.Has(rpc.SCACTION, rpc.DataUint64) { if rpc.SC_INSTALL == rpc.SC_ACTION(tx.SCDATA.Value(rpc.SCACTION, rpc.DataUint64).(uint64)) { txid := tx.GetHash() - if txid[31] < 0x80 { // last byte should be more than 0x80 + if txid[0] < 0x80 || txid[31] < 0x80 { // last byte should be more than 0x80 if retry_count <= 20 { //fmt.Printf("rebuilding tx %s retry_count %d\n", txid, retry_count) goto rebuild_tx