mirror of
https://github.com/kaspanet/kaspad.git
synced 2025-03-30 15:08:33 +00:00
Merge branch 'dev' into bug-block-verbosedata
This commit is contained in:
commit
f8dec0e81f
@ -28,7 +28,8 @@ func HandleSubmitTransaction(context *rpccontext.Context, _ *router.Router, requ
|
|||||||
}
|
}
|
||||||
|
|
||||||
log.Debugf("Rejected transaction %s: %s", transactionID, err)
|
log.Debugf("Rejected transaction %s: %s", transactionID, err)
|
||||||
errorMessage := &appmessage.SubmitTransactionResponseMessage{}
|
// Return the ID also in the case of error, so that clients can match the response to the correct transaction submit request
|
||||||
|
errorMessage := appmessage.NewSubmitTransactionResponseMessage(transactionID.String())
|
||||||
errorMessage.Error = appmessage.RPCErrorf("Rejected transaction %s: %s", transactionID, err)
|
errorMessage.Error = appmessage.RPCErrorf("Rejected transaction %s: %s", transactionID, err)
|
||||||
return errorMessage, nil
|
return errorMessage, nil
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,30 @@
|
|||||||
|
Kaspad v0.12.17 - 2024-02-19
|
||||||
|
===========================
|
||||||
|
|
||||||
|
* Wallet-related improvements and fixes (#2253, #2257, #2258, #2262)
|
||||||
|
|
||||||
|
Kaspad v0.12.16 - 2023-12-25
|
||||||
|
===========================
|
||||||
|
|
||||||
|
* Adapt wallet UTXO selection to dust patch (#2254)
|
||||||
|
|
||||||
|
Kaspad v0.12.15 - 2023-12-16
|
||||||
|
===========================
|
||||||
|
|
||||||
|
* Update ECDSA address test to use a valid public key (#2202)
|
||||||
|
* Fix off by small amounts in sent amount kaspa (#2220)
|
||||||
|
* Use removeRedeemers correctly by (#2235)
|
||||||
|
* Fix windows asset building by increasing go version (#2245)
|
||||||
|
* Added a mainnet dnsseeder (#2247)
|
||||||
|
* Fix extract atomic swap data pushes (#2203)
|
||||||
|
* Adapt kaspawallet to support testnet 11 (#2211)
|
||||||
|
* Fix type detection in RemoveInvalidTransactions (#2252)
|
||||||
|
|
||||||
|
Kaspad v0.12.14 - 2023-09-26
|
||||||
|
===========================
|
||||||
|
|
||||||
|
* Anti-spam measurements against dust attack (#2223)
|
||||||
|
|
||||||
Kaspad v0.12.13 - 2023-03-06
|
Kaspad v0.12.13 - 2023-03-06
|
||||||
===========================
|
===========================
|
||||||
|
|
||||||
|
@ -1,10 +1,9 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"os"
|
|
||||||
|
|
||||||
"github.com/kaspanet/kaspad/infrastructure/config"
|
"github.com/kaspanet/kaspad/infrastructure/config"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
|
"os"
|
||||||
|
|
||||||
"github.com/jessevdk/go-flags"
|
"github.com/jessevdk/go-flags"
|
||||||
)
|
)
|
||||||
@ -22,6 +21,8 @@ const (
|
|||||||
newAddressSubCmd = "new-address"
|
newAddressSubCmd = "new-address"
|
||||||
dumpUnencryptedDataSubCmd = "dump-unencrypted-data"
|
dumpUnencryptedDataSubCmd = "dump-unencrypted-data"
|
||||||
startDaemonSubCmd = "start-daemon"
|
startDaemonSubCmd = "start-daemon"
|
||||||
|
versionSubCmd = "version"
|
||||||
|
getDaemonVersionSubCmd = "get-daemon-version"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -30,6 +31,7 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type configFlags struct {
|
type configFlags struct {
|
||||||
|
ShowVersion bool `short:"V" long:"version" description:"Display version information and exit"`
|
||||||
config.NetworkFlags
|
config.NetworkFlags
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -56,9 +58,9 @@ type sendConfig struct {
|
|||||||
Password string `long:"password" short:"p" description:"Wallet password"`
|
Password string `long:"password" short:"p" description:"Wallet password"`
|
||||||
DaemonAddress string `long:"daemonaddress" short:"d" description:"Wallet daemon server to connect to"`
|
DaemonAddress string `long:"daemonaddress" short:"d" description:"Wallet daemon server to connect to"`
|
||||||
ToAddress string `long:"to-address" short:"t" description:"The public address to send Kaspa to" required:"true"`
|
ToAddress string `long:"to-address" short:"t" description:"The public address to send Kaspa to" required:"true"`
|
||||||
FromAddresses []string `long:"from-address" short:"a" description:"Specific public address to send Kaspa from. Use multiple times to accept several addresses" required:"false"`
|
FromAddresses []string `long:"from-address" short:"a" description:"Specific public address to send Kaspa from. Repeat multiple times (adding -a before each) to accept several addresses" required:"false"`
|
||||||
SendAmount string `long:"send-amount" short:"v" description:"An amount to send in Kaspa (e.g. 1234.12345678)"`
|
SendAmount string `long:"send-amount" short:"v" description:"An amount to send in Kaspa (e.g. 1234.12345678)"`
|
||||||
IsSendAll bool `long:"send-all" description:"Send all the Kaspa in the wallet (mutually exclusive with --send-amount)"`
|
IsSendAll bool `long:"send-all" description:"Send all the Kaspa in the wallet (mutually exclusive with --send-amount). If --from-address was used, will send all only from the specified addresses."`
|
||||||
UseExistingChangeAddress bool `long:"use-existing-change-address" short:"u" description:"Will use an existing change address (in case no change address was ever used, it will use a new one)"`
|
UseExistingChangeAddress bool `long:"use-existing-change-address" short:"u" description:"Will use an existing change address (in case no change address was ever used, it will use a new one)"`
|
||||||
Verbose bool `long:"show-serialized" short:"s" description:"Show a list of hex encoded sent transactions"`
|
Verbose bool `long:"show-serialized" short:"s" description:"Show a list of hex encoded sent transactions"`
|
||||||
config.NetworkFlags
|
config.NetworkFlags
|
||||||
@ -129,6 +131,13 @@ type dumpUnencryptedDataConfig struct {
|
|||||||
config.NetworkFlags
|
config.NetworkFlags
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type versionConfig struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
type getDaemonVersionConfig struct {
|
||||||
|
DaemonAddress string `long:"daemonaddress" short:"d" description:"Wallet daemon server to connect to"`
|
||||||
|
}
|
||||||
|
|
||||||
func parseCommandLine() (subCommand string, config interface{}) {
|
func parseCommandLine() (subCommand string, config interface{}) {
|
||||||
cfg := &configFlags{}
|
cfg := &configFlags{}
|
||||||
parser := flags.NewParser(cfg, flags.PrintErrors|flags.HelpFlag)
|
parser := flags.NewParser(cfg, flags.PrintErrors|flags.HelpFlag)
|
||||||
@ -185,6 +194,9 @@ func parseCommandLine() (subCommand string, config interface{}) {
|
|||||||
Listen: defaultListen,
|
Listen: defaultListen,
|
||||||
}
|
}
|
||||||
parser.AddCommand(startDaemonSubCmd, "Start the wallet daemon", "Start the wallet daemon", startDaemonConf)
|
parser.AddCommand(startDaemonSubCmd, "Start the wallet daemon", "Start the wallet daemon", startDaemonConf)
|
||||||
|
parser.AddCommand(versionSubCmd, "Get the wallet version", "Get the wallet version", &versionConfig{})
|
||||||
|
getDaemonVersionConf := &getDaemonVersionConfig{DaemonAddress: defaultListen}
|
||||||
|
parser.AddCommand(getDaemonVersionSubCmd, "Get the wallet daemon version", "Get the wallet daemon version", getDaemonVersionConf)
|
||||||
|
|
||||||
_, err := parser.Parse()
|
_, err := parser.Parse()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -290,6 +302,9 @@ func parseCommandLine() (subCommand string, config interface{}) {
|
|||||||
printErrorAndExit(err)
|
printErrorAndExit(err)
|
||||||
}
|
}
|
||||||
config = startDaemonConf
|
config = startDaemonConf
|
||||||
|
case versionSubCmd:
|
||||||
|
case getDaemonVersionSubCmd:
|
||||||
|
config = getDaemonVersionConf
|
||||||
}
|
}
|
||||||
|
|
||||||
return parser.Command.Active.Name, config
|
return parser.Command.Active.Name, config
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// protoc-gen-go v1.26.0
|
// protoc-gen-go v1.27.1
|
||||||
// protoc v3.21.12
|
// protoc v3.12.3
|
||||||
// source: kaspawalletd.proto
|
// source: kaspawalletd.proto
|
||||||
|
|
||||||
package pb
|
package pb
|
||||||
@ -1242,6 +1242,91 @@ func (x *SignResponse) GetSignedTransactions() [][]byte {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type GetVersionRequest struct {
|
||||||
|
state protoimpl.MessageState
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *GetVersionRequest) Reset() {
|
||||||
|
*x = GetVersionRequest{}
|
||||||
|
if protoimpl.UnsafeEnabled {
|
||||||
|
mi := &file_kaspawalletd_proto_msgTypes[23]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *GetVersionRequest) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*GetVersionRequest) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *GetVersionRequest) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_kaspawalletd_proto_msgTypes[23]
|
||||||
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use GetVersionRequest.ProtoReflect.Descriptor instead.
|
||||||
|
func (*GetVersionRequest) Descriptor() ([]byte, []int) {
|
||||||
|
return file_kaspawalletd_proto_rawDescGZIP(), []int{23}
|
||||||
|
}
|
||||||
|
|
||||||
|
type GetVersionResponse struct {
|
||||||
|
state protoimpl.MessageState
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
|
Version string `protobuf:"bytes,1,opt,name=version,proto3" json:"version,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *GetVersionResponse) Reset() {
|
||||||
|
*x = GetVersionResponse{}
|
||||||
|
if protoimpl.UnsafeEnabled {
|
||||||
|
mi := &file_kaspawalletd_proto_msgTypes[24]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *GetVersionResponse) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*GetVersionResponse) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *GetVersionResponse) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_kaspawalletd_proto_msgTypes[24]
|
||||||
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use GetVersionResponse.ProtoReflect.Descriptor instead.
|
||||||
|
func (*GetVersionResponse) Descriptor() ([]byte, []int) {
|
||||||
|
return file_kaspawalletd_proto_rawDescGZIP(), []int{24}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *GetVersionResponse) GetVersion() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.Version
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
var File_kaspawalletd_proto protoreflect.FileDescriptor
|
var File_kaspawalletd_proto protoreflect.FileDescriptor
|
||||||
|
|
||||||
var file_kaspawalletd_proto_rawDesc = []byte{
|
var file_kaspawalletd_proto_rawDesc = []byte{
|
||||||
@ -1371,62 +1456,72 @@ var file_kaspawalletd_proto_rawDesc = []byte{
|
|||||||
0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2e, 0x0a, 0x12, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x54, 0x72,
|
0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2e, 0x0a, 0x12, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x54, 0x72,
|
||||||
0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0c,
|
0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0c,
|
||||||
0x52, 0x12, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74,
|
0x52, 0x12, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74,
|
||||||
0x69, 0x6f, 0x6e, 0x73, 0x32, 0xb3, 0x06, 0x0a, 0x0c, 0x6b, 0x61, 0x73, 0x70, 0x61, 0x77, 0x61,
|
0x69, 0x6f, 0x6e, 0x73, 0x22, 0x13, 0x0a, 0x11, 0x47, 0x65, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69,
|
||||||
0x6c, 0x6c, 0x65, 0x74, 0x64, 0x12, 0x51, 0x0a, 0x0a, 0x47, 0x65, 0x74, 0x42, 0x61, 0x6c, 0x61,
|
0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x2e, 0x0a, 0x12, 0x47, 0x65, 0x74,
|
||||||
0x6e, 0x63, 0x65, 0x12, 0x1f, 0x2e, 0x6b, 0x61, 0x73, 0x70, 0x61, 0x77, 0x61, 0x6c, 0x6c, 0x65,
|
0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12,
|
||||||
0x74, 0x64, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x52, 0x65, 0x71,
|
0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
|
||||||
0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x6b, 0x61, 0x73, 0x70, 0x61, 0x77, 0x61, 0x6c, 0x6c,
|
0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x32, 0x86, 0x07, 0x0a, 0x0c, 0x6b, 0x61,
|
||||||
0x65, 0x74, 0x64, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x52, 0x65,
|
0x73, 0x70, 0x61, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x64, 0x12, 0x51, 0x0a, 0x0a, 0x47, 0x65,
|
||||||
0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x7e, 0x0a, 0x19, 0x47, 0x65, 0x74, 0x45,
|
0x74, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x1f, 0x2e, 0x6b, 0x61, 0x73, 0x70, 0x61,
|
||||||
0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x53, 0x70, 0x65, 0x6e, 0x64, 0x61, 0x62, 0x6c, 0x65,
|
0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x64, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x61, 0x6c, 0x61, 0x6e,
|
||||||
0x55, 0x54, 0x58, 0x4f, 0x73, 0x12, 0x2e, 0x2e, 0x6b, 0x61, 0x73, 0x70, 0x61, 0x77, 0x61, 0x6c,
|
0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x6b, 0x61, 0x73, 0x70,
|
||||||
0x6c, 0x65, 0x74, 0x64, 0x2e, 0x47, 0x65, 0x74, 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c,
|
0x61, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x64, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x61, 0x6c, 0x61,
|
||||||
0x53, 0x70, 0x65, 0x6e, 0x64, 0x61, 0x62, 0x6c, 0x65, 0x55, 0x54, 0x58, 0x4f, 0x73, 0x52, 0x65,
|
0x6e, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x7e, 0x0a,
|
||||||
0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2f, 0x2e, 0x6b, 0x61, 0x73, 0x70, 0x61, 0x77, 0x61, 0x6c,
|
0x19, 0x47, 0x65, 0x74, 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x53, 0x70, 0x65, 0x6e,
|
||||||
0x6c, 0x65, 0x74, 0x64, 0x2e, 0x47, 0x65, 0x74, 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c,
|
0x64, 0x61, 0x62, 0x6c, 0x65, 0x55, 0x54, 0x58, 0x4f, 0x73, 0x12, 0x2e, 0x2e, 0x6b, 0x61, 0x73,
|
||||||
0x53, 0x70, 0x65, 0x6e, 0x64, 0x61, 0x62, 0x6c, 0x65, 0x55, 0x54, 0x58, 0x4f, 0x73, 0x52, 0x65,
|
0x70, 0x61, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x64, 0x2e, 0x47, 0x65, 0x74, 0x45, 0x78, 0x74,
|
||||||
0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x81, 0x01, 0x0a, 0x1a, 0x43, 0x72, 0x65,
|
0x65, 0x72, 0x6e, 0x61, 0x6c, 0x53, 0x70, 0x65, 0x6e, 0x64, 0x61, 0x62, 0x6c, 0x65, 0x55, 0x54,
|
||||||
|
0x58, 0x4f, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2f, 0x2e, 0x6b, 0x61, 0x73,
|
||||||
|
0x70, 0x61, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x64, 0x2e, 0x47, 0x65, 0x74, 0x45, 0x78, 0x74,
|
||||||
|
0x65, 0x72, 0x6e, 0x61, 0x6c, 0x53, 0x70, 0x65, 0x6e, 0x64, 0x61, 0x62, 0x6c, 0x65, 0x55, 0x54,
|
||||||
|
0x58, 0x4f, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x81, 0x01,
|
||||||
|
0x0a, 0x1a, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x55, 0x6e, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64,
|
||||||
|
0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x2f, 0x2e, 0x6b,
|
||||||
|
0x61, 0x73, 0x70, 0x61, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x64, 0x2e, 0x43, 0x72, 0x65, 0x61,
|
||||||
|
0x74, 0x65, 0x55, 0x6e, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61,
|
||||||
|
0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x30, 0x2e,
|
||||||
|
0x6b, 0x61, 0x73, 0x70, 0x61, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x64, 0x2e, 0x43, 0x72, 0x65,
|
||||||
0x61, 0x74, 0x65, 0x55, 0x6e, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x54, 0x72, 0x61, 0x6e, 0x73,
|
0x61, 0x74, 0x65, 0x55, 0x6e, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x54, 0x72, 0x61, 0x6e, 0x73,
|
||||||
0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x2f, 0x2e, 0x6b, 0x61, 0x73, 0x70, 0x61, 0x77,
|
0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22,
|
||||||
0x61, 0x6c, 0x6c, 0x65, 0x74, 0x64, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x55, 0x6e, 0x73,
|
0x00, 0x12, 0x5a, 0x0a, 0x0d, 0x53, 0x68, 0x6f, 0x77, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73,
|
||||||
0x69, 0x67, 0x6e, 0x65, 0x64, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e,
|
0x65, 0x73, 0x12, 0x22, 0x2e, 0x6b, 0x61, 0x73, 0x70, 0x61, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74,
|
||||||
0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x30, 0x2e, 0x6b, 0x61, 0x73, 0x70, 0x61,
|
0x64, 0x2e, 0x53, 0x68, 0x6f, 0x77, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52,
|
||||||
0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x64, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x55, 0x6e,
|
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x6b, 0x61, 0x73, 0x70, 0x61, 0x77, 0x61,
|
||||||
0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f,
|
0x6c, 0x6c, 0x65, 0x74, 0x64, 0x2e, 0x53, 0x68, 0x6f, 0x77, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73,
|
||||||
0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x5a, 0x0a, 0x0d,
|
0x73, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x51, 0x0a,
|
||||||
0x53, 0x68, 0x6f, 0x77, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x12, 0x22, 0x2e,
|
0x0a, 0x4e, 0x65, 0x77, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x1f, 0x2e, 0x6b, 0x61,
|
||||||
0x6b, 0x61, 0x73, 0x70, 0x61, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x64, 0x2e, 0x53, 0x68, 0x6f,
|
0x73, 0x70, 0x61, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x64, 0x2e, 0x4e, 0x65, 0x77, 0x41, 0x64,
|
||||||
0x77, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
|
0x64, 0x72, 0x65, 0x73, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x6b,
|
||||||
0x74, 0x1a, 0x23, 0x2e, 0x6b, 0x61, 0x73, 0x70, 0x61, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x64,
|
0x61, 0x73, 0x70, 0x61, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x64, 0x2e, 0x4e, 0x65, 0x77, 0x41,
|
||||||
0x2e, 0x53, 0x68, 0x6f, 0x77, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65,
|
0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00,
|
||||||
0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x51, 0x0a, 0x0a, 0x4e, 0x65, 0x77, 0x41,
|
0x12, 0x4b, 0x0a, 0x08, 0x53, 0x68, 0x75, 0x74, 0x64, 0x6f, 0x77, 0x6e, 0x12, 0x1d, 0x2e, 0x6b,
|
||||||
0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x1f, 0x2e, 0x6b, 0x61, 0x73, 0x70, 0x61, 0x77, 0x61,
|
0x61, 0x73, 0x70, 0x61, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x64, 0x2e, 0x53, 0x68, 0x75, 0x74,
|
||||||
0x6c, 0x6c, 0x65, 0x74, 0x64, 0x2e, 0x4e, 0x65, 0x77, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73,
|
0x64, 0x6f, 0x77, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x6b, 0x61,
|
||||||
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x6b, 0x61, 0x73, 0x70, 0x61, 0x77,
|
0x73, 0x70, 0x61, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x64, 0x2e, 0x53, 0x68, 0x75, 0x74, 0x64,
|
||||||
0x61, 0x6c, 0x6c, 0x65, 0x74, 0x64, 0x2e, 0x4e, 0x65, 0x77, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73,
|
0x6f, 0x77, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x4e, 0x0a,
|
||||||
0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x4b, 0x0a, 0x08, 0x53,
|
0x09, 0x42, 0x72, 0x6f, 0x61, 0x64, 0x63, 0x61, 0x73, 0x74, 0x12, 0x1e, 0x2e, 0x6b, 0x61, 0x73,
|
||||||
0x68, 0x75, 0x74, 0x64, 0x6f, 0x77, 0x6e, 0x12, 0x1d, 0x2e, 0x6b, 0x61, 0x73, 0x70, 0x61, 0x77,
|
0x70, 0x61, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x64, 0x2e, 0x42, 0x72, 0x6f, 0x61, 0x64, 0x63,
|
||||||
0x61, 0x6c, 0x6c, 0x65, 0x74, 0x64, 0x2e, 0x53, 0x68, 0x75, 0x74, 0x64, 0x6f, 0x77, 0x6e, 0x52,
|
0x61, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x6b, 0x61, 0x73,
|
||||||
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x6b, 0x61, 0x73, 0x70, 0x61, 0x77, 0x61,
|
0x70, 0x61, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x64, 0x2e, 0x42, 0x72, 0x6f, 0x61, 0x64, 0x63,
|
||||||
0x6c, 0x6c, 0x65, 0x74, 0x64, 0x2e, 0x53, 0x68, 0x75, 0x74, 0x64, 0x6f, 0x77, 0x6e, 0x52, 0x65,
|
0x61, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x3f, 0x0a,
|
||||||
0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x4e, 0x0a, 0x09, 0x42, 0x72, 0x6f, 0x61,
|
0x04, 0x53, 0x65, 0x6e, 0x64, 0x12, 0x19, 0x2e, 0x6b, 0x61, 0x73, 0x70, 0x61, 0x77, 0x61, 0x6c,
|
||||||
0x64, 0x63, 0x61, 0x73, 0x74, 0x12, 0x1e, 0x2e, 0x6b, 0x61, 0x73, 0x70, 0x61, 0x77, 0x61, 0x6c,
|
0x6c, 0x65, 0x74, 0x64, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
|
||||||
0x6c, 0x65, 0x74, 0x64, 0x2e, 0x42, 0x72, 0x6f, 0x61, 0x64, 0x63, 0x61, 0x73, 0x74, 0x52, 0x65,
|
0x1a, 0x1a, 0x2e, 0x6b, 0x61, 0x73, 0x70, 0x61, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x64, 0x2e,
|
||||||
0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x6b, 0x61, 0x73, 0x70, 0x61, 0x77, 0x61, 0x6c,
|
0x53, 0x65, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x3f,
|
||||||
0x6c, 0x65, 0x74, 0x64, 0x2e, 0x42, 0x72, 0x6f, 0x61, 0x64, 0x63, 0x61, 0x73, 0x74, 0x52, 0x65,
|
0x0a, 0x04, 0x53, 0x69, 0x67, 0x6e, 0x12, 0x19, 0x2e, 0x6b, 0x61, 0x73, 0x70, 0x61, 0x77, 0x61,
|
||||||
0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x3f, 0x0a, 0x04, 0x53, 0x65, 0x6e, 0x64,
|
0x6c, 0x6c, 0x65, 0x74, 0x64, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
|
||||||
0x12, 0x19, 0x2e, 0x6b, 0x61, 0x73, 0x70, 0x61, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x64, 0x2e,
|
0x74, 0x1a, 0x1a, 0x2e, 0x6b, 0x61, 0x73, 0x70, 0x61, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x64,
|
||||||
0x53, 0x65, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x6b, 0x61,
|
0x2e, 0x53, 0x69, 0x67, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12,
|
||||||
0x73, 0x70, 0x61, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x64, 0x2e, 0x53, 0x65, 0x6e, 0x64, 0x52,
|
0x51, 0x0a, 0x0a, 0x47, 0x65, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1f, 0x2e,
|
||||||
0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x3f, 0x0a, 0x04, 0x53, 0x69, 0x67,
|
0x6b, 0x61, 0x73, 0x70, 0x61, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x64, 0x2e, 0x47, 0x65, 0x74,
|
||||||
0x6e, 0x12, 0x19, 0x2e, 0x6b, 0x61, 0x73, 0x70, 0x61, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x64,
|
0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20,
|
||||||
0x2e, 0x53, 0x69, 0x67, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x6b,
|
0x2e, 0x6b, 0x61, 0x73, 0x70, 0x61, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x64, 0x2e, 0x47, 0x65,
|
||||||
0x61, 0x73, 0x70, 0x61, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x64, 0x2e, 0x53, 0x69, 0x67, 0x6e,
|
0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
|
||||||
0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x36, 0x5a, 0x34, 0x67, 0x69,
|
0x22, 0x00, 0x42, 0x36, 0x5a, 0x34, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d,
|
||||||
0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6b, 0x61, 0x73, 0x70, 0x61, 0x6e, 0x65,
|
0x2f, 0x6b, 0x61, 0x73, 0x70, 0x61, 0x6e, 0x65, 0x74, 0x2f, 0x6b, 0x61, 0x73, 0x70, 0x61, 0x64,
|
||||||
0x74, 0x2f, 0x6b, 0x61, 0x73, 0x70, 0x61, 0x64, 0x2f, 0x63, 0x6d, 0x64, 0x2f, 0x6b, 0x61, 0x73,
|
0x2f, 0x63, 0x6d, 0x64, 0x2f, 0x6b, 0x61, 0x73, 0x70, 0x61, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74,
|
||||||
0x70, 0x61, 0x77, 0x61, 0x6c, 0x6c, 0x65, 0x74, 0x2f, 0x64, 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x2f,
|
0x2f, 0x64, 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x2f, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74,
|
||||||
0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
0x6f, 0x33,
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -1441,7 +1536,7 @@ func file_kaspawalletd_proto_rawDescGZIP() []byte {
|
|||||||
return file_kaspawalletd_proto_rawDescData
|
return file_kaspawalletd_proto_rawDescData
|
||||||
}
|
}
|
||||||
|
|
||||||
var file_kaspawalletd_proto_msgTypes = make([]protoimpl.MessageInfo, 23)
|
var file_kaspawalletd_proto_msgTypes = make([]protoimpl.MessageInfo, 25)
|
||||||
var file_kaspawalletd_proto_goTypes = []interface{}{
|
var file_kaspawalletd_proto_goTypes = []interface{}{
|
||||||
(*GetBalanceRequest)(nil), // 0: kaspawalletd.GetBalanceRequest
|
(*GetBalanceRequest)(nil), // 0: kaspawalletd.GetBalanceRequest
|
||||||
(*GetBalanceResponse)(nil), // 1: kaspawalletd.GetBalanceResponse
|
(*GetBalanceResponse)(nil), // 1: kaspawalletd.GetBalanceResponse
|
||||||
@ -1466,6 +1561,8 @@ var file_kaspawalletd_proto_goTypes = []interface{}{
|
|||||||
(*SendResponse)(nil), // 20: kaspawalletd.SendResponse
|
(*SendResponse)(nil), // 20: kaspawalletd.SendResponse
|
||||||
(*SignRequest)(nil), // 21: kaspawalletd.SignRequest
|
(*SignRequest)(nil), // 21: kaspawalletd.SignRequest
|
||||||
(*SignResponse)(nil), // 22: kaspawalletd.SignResponse
|
(*SignResponse)(nil), // 22: kaspawalletd.SignResponse
|
||||||
|
(*GetVersionRequest)(nil), // 23: kaspawalletd.GetVersionRequest
|
||||||
|
(*GetVersionResponse)(nil), // 24: kaspawalletd.GetVersionResponse
|
||||||
}
|
}
|
||||||
var file_kaspawalletd_proto_depIdxs = []int32{
|
var file_kaspawalletd_proto_depIdxs = []int32{
|
||||||
2, // 0: kaspawalletd.GetBalanceResponse.addressBalances:type_name -> kaspawalletd.AddressBalances
|
2, // 0: kaspawalletd.GetBalanceResponse.addressBalances:type_name -> kaspawalletd.AddressBalances
|
||||||
@ -1482,17 +1579,19 @@ var file_kaspawalletd_proto_depIdxs = []int32{
|
|||||||
9, // 11: kaspawalletd.kaspawalletd.Broadcast:input_type -> kaspawalletd.BroadcastRequest
|
9, // 11: kaspawalletd.kaspawalletd.Broadcast:input_type -> kaspawalletd.BroadcastRequest
|
||||||
19, // 12: kaspawalletd.kaspawalletd.Send:input_type -> kaspawalletd.SendRequest
|
19, // 12: kaspawalletd.kaspawalletd.Send:input_type -> kaspawalletd.SendRequest
|
||||||
21, // 13: kaspawalletd.kaspawalletd.Sign:input_type -> kaspawalletd.SignRequest
|
21, // 13: kaspawalletd.kaspawalletd.Sign:input_type -> kaspawalletd.SignRequest
|
||||||
1, // 14: kaspawalletd.kaspawalletd.GetBalance:output_type -> kaspawalletd.GetBalanceResponse
|
23, // 14: kaspawalletd.kaspawalletd.GetVersion:input_type -> kaspawalletd.GetVersionRequest
|
||||||
18, // 15: kaspawalletd.kaspawalletd.GetExternalSpendableUTXOs:output_type -> kaspawalletd.GetExternalSpendableUTXOsResponse
|
1, // 15: kaspawalletd.kaspawalletd.GetBalance:output_type -> kaspawalletd.GetBalanceResponse
|
||||||
4, // 16: kaspawalletd.kaspawalletd.CreateUnsignedTransactions:output_type -> kaspawalletd.CreateUnsignedTransactionsResponse
|
18, // 16: kaspawalletd.kaspawalletd.GetExternalSpendableUTXOs:output_type -> kaspawalletd.GetExternalSpendableUTXOsResponse
|
||||||
6, // 17: kaspawalletd.kaspawalletd.ShowAddresses:output_type -> kaspawalletd.ShowAddressesResponse
|
4, // 17: kaspawalletd.kaspawalletd.CreateUnsignedTransactions:output_type -> kaspawalletd.CreateUnsignedTransactionsResponse
|
||||||
8, // 18: kaspawalletd.kaspawalletd.NewAddress:output_type -> kaspawalletd.NewAddressResponse
|
6, // 18: kaspawalletd.kaspawalletd.ShowAddresses:output_type -> kaspawalletd.ShowAddressesResponse
|
||||||
12, // 19: kaspawalletd.kaspawalletd.Shutdown:output_type -> kaspawalletd.ShutdownResponse
|
8, // 19: kaspawalletd.kaspawalletd.NewAddress:output_type -> kaspawalletd.NewAddressResponse
|
||||||
10, // 20: kaspawalletd.kaspawalletd.Broadcast:output_type -> kaspawalletd.BroadcastResponse
|
12, // 20: kaspawalletd.kaspawalletd.Shutdown:output_type -> kaspawalletd.ShutdownResponse
|
||||||
20, // 21: kaspawalletd.kaspawalletd.Send:output_type -> kaspawalletd.SendResponse
|
10, // 21: kaspawalletd.kaspawalletd.Broadcast:output_type -> kaspawalletd.BroadcastResponse
|
||||||
22, // 22: kaspawalletd.kaspawalletd.Sign:output_type -> kaspawalletd.SignResponse
|
20, // 22: kaspawalletd.kaspawalletd.Send:output_type -> kaspawalletd.SendResponse
|
||||||
14, // [14:23] is the sub-list for method output_type
|
22, // 23: kaspawalletd.kaspawalletd.Sign:output_type -> kaspawalletd.SignResponse
|
||||||
5, // [5:14] is the sub-list for method input_type
|
24, // 24: kaspawalletd.kaspawalletd.GetVersion:output_type -> kaspawalletd.GetVersionResponse
|
||||||
|
15, // [15:25] is the sub-list for method output_type
|
||||||
|
5, // [5:15] is the sub-list for method input_type
|
||||||
5, // [5:5] is the sub-list for extension type_name
|
5, // [5:5] is the sub-list for extension type_name
|
||||||
5, // [5:5] is the sub-list for extension extendee
|
5, // [5:5] is the sub-list for extension extendee
|
||||||
0, // [0:5] is the sub-list for field type_name
|
0, // [0:5] is the sub-list for field type_name
|
||||||
@ -1780,6 +1879,30 @@ func file_kaspawalletd_proto_init() {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
file_kaspawalletd_proto_msgTypes[23].Exporter = func(v interface{}, i int) interface{} {
|
||||||
|
switch v := v.(*GetVersionRequest); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file_kaspawalletd_proto_msgTypes[24].Exporter = func(v interface{}, i int) interface{} {
|
||||||
|
switch v := v.(*GetVersionResponse); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
type x struct{}
|
type x struct{}
|
||||||
out := protoimpl.TypeBuilder{
|
out := protoimpl.TypeBuilder{
|
||||||
@ -1787,7 +1910,7 @@ func file_kaspawalletd_proto_init() {
|
|||||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||||
RawDescriptor: file_kaspawalletd_proto_rawDesc,
|
RawDescriptor: file_kaspawalletd_proto_rawDesc,
|
||||||
NumEnums: 0,
|
NumEnums: 0,
|
||||||
NumMessages: 23,
|
NumMessages: 25,
|
||||||
NumExtensions: 0,
|
NumExtensions: 0,
|
||||||
NumServices: 1,
|
NumServices: 1,
|
||||||
},
|
},
|
||||||
|
@ -15,6 +15,7 @@ service kaspawalletd {
|
|||||||
rpc Send(SendRequest) returns (SendResponse) {}
|
rpc Send(SendRequest) returns (SendResponse) {}
|
||||||
// Since SignRequest contains a password - this command should only be used on a trusted or secure connection
|
// Since SignRequest contains a password - this command should only be used on a trusted or secure connection
|
||||||
rpc Sign(SignRequest) returns (SignResponse) {}
|
rpc Sign(SignRequest) returns (SignResponse) {}
|
||||||
|
rpc GetVersion(GetVersionRequest) returns (GetVersionResponse) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
message GetBalanceRequest {
|
message GetBalanceRequest {
|
||||||
@ -127,3 +128,10 @@ message SignRequest{
|
|||||||
message SignResponse{
|
message SignResponse{
|
||||||
repeated bytes signedTransactions = 1;
|
repeated bytes signedTransactions = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
message GetVersionRequest{
|
||||||
|
}
|
||||||
|
|
||||||
|
message GetVersionResponse{
|
||||||
|
string version = 1;
|
||||||
|
}
|
@ -1,4 +1,8 @@
|
|||||||
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
|
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
|
||||||
|
// versions:
|
||||||
|
// - protoc-gen-go-grpc v1.2.0
|
||||||
|
// - protoc v3.12.3
|
||||||
|
// source: kaspawalletd.proto
|
||||||
|
|
||||||
package pb
|
package pb
|
||||||
|
|
||||||
@ -29,6 +33,7 @@ type KaspawalletdClient interface {
|
|||||||
Send(ctx context.Context, in *SendRequest, opts ...grpc.CallOption) (*SendResponse, error)
|
Send(ctx context.Context, in *SendRequest, opts ...grpc.CallOption) (*SendResponse, error)
|
||||||
// Since SignRequest contains a password - this command should only be used on a trusted or secure connection
|
// Since SignRequest contains a password - this command should only be used on a trusted or secure connection
|
||||||
Sign(ctx context.Context, in *SignRequest, opts ...grpc.CallOption) (*SignResponse, error)
|
Sign(ctx context.Context, in *SignRequest, opts ...grpc.CallOption) (*SignResponse, error)
|
||||||
|
GetVersion(ctx context.Context, in *GetVersionRequest, opts ...grpc.CallOption) (*GetVersionResponse, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type kaspawalletdClient struct {
|
type kaspawalletdClient struct {
|
||||||
@ -120,6 +125,15 @@ func (c *kaspawalletdClient) Sign(ctx context.Context, in *SignRequest, opts ...
|
|||||||
return out, nil
|
return out, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *kaspawalletdClient) GetVersion(ctx context.Context, in *GetVersionRequest, opts ...grpc.CallOption) (*GetVersionResponse, error) {
|
||||||
|
out := new(GetVersionResponse)
|
||||||
|
err := c.cc.Invoke(ctx, "/kaspawalletd.kaspawalletd/GetVersion", in, out, opts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
// KaspawalletdServer is the server API for Kaspawalletd service.
|
// KaspawalletdServer is the server API for Kaspawalletd service.
|
||||||
// All implementations must embed UnimplementedKaspawalletdServer
|
// All implementations must embed UnimplementedKaspawalletdServer
|
||||||
// for forward compatibility
|
// for forward compatibility
|
||||||
@ -135,6 +149,7 @@ type KaspawalletdServer interface {
|
|||||||
Send(context.Context, *SendRequest) (*SendResponse, error)
|
Send(context.Context, *SendRequest) (*SendResponse, error)
|
||||||
// Since SignRequest contains a password - this command should only be used on a trusted or secure connection
|
// Since SignRequest contains a password - this command should only be used on a trusted or secure connection
|
||||||
Sign(context.Context, *SignRequest) (*SignResponse, error)
|
Sign(context.Context, *SignRequest) (*SignResponse, error)
|
||||||
|
GetVersion(context.Context, *GetVersionRequest) (*GetVersionResponse, error)
|
||||||
mustEmbedUnimplementedKaspawalletdServer()
|
mustEmbedUnimplementedKaspawalletdServer()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -169,6 +184,9 @@ func (UnimplementedKaspawalletdServer) Send(context.Context, *SendRequest) (*Sen
|
|||||||
func (UnimplementedKaspawalletdServer) Sign(context.Context, *SignRequest) (*SignResponse, error) {
|
func (UnimplementedKaspawalletdServer) Sign(context.Context, *SignRequest) (*SignResponse, error) {
|
||||||
return nil, status.Errorf(codes.Unimplemented, "method Sign not implemented")
|
return nil, status.Errorf(codes.Unimplemented, "method Sign not implemented")
|
||||||
}
|
}
|
||||||
|
func (UnimplementedKaspawalletdServer) GetVersion(context.Context, *GetVersionRequest) (*GetVersionResponse, error) {
|
||||||
|
return nil, status.Errorf(codes.Unimplemented, "method GetVersion not implemented")
|
||||||
|
}
|
||||||
func (UnimplementedKaspawalletdServer) mustEmbedUnimplementedKaspawalletdServer() {}
|
func (UnimplementedKaspawalletdServer) mustEmbedUnimplementedKaspawalletdServer() {}
|
||||||
|
|
||||||
// UnsafeKaspawalletdServer may be embedded to opt out of forward compatibility for this service.
|
// UnsafeKaspawalletdServer may be embedded to opt out of forward compatibility for this service.
|
||||||
@ -344,6 +362,24 @@ func _Kaspawalletd_Sign_Handler(srv interface{}, ctx context.Context, dec func(i
|
|||||||
return interceptor(ctx, in, info, handler)
|
return interceptor(ctx, in, info, handler)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func _Kaspawalletd_GetVersion_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||||
|
in := new(GetVersionRequest)
|
||||||
|
if err := dec(in); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if interceptor == nil {
|
||||||
|
return srv.(KaspawalletdServer).GetVersion(ctx, in)
|
||||||
|
}
|
||||||
|
info := &grpc.UnaryServerInfo{
|
||||||
|
Server: srv,
|
||||||
|
FullMethod: "/kaspawalletd.kaspawalletd/GetVersion",
|
||||||
|
}
|
||||||
|
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||||
|
return srv.(KaspawalletdServer).GetVersion(ctx, req.(*GetVersionRequest))
|
||||||
|
}
|
||||||
|
return interceptor(ctx, in, info, handler)
|
||||||
|
}
|
||||||
|
|
||||||
// Kaspawalletd_ServiceDesc is the grpc.ServiceDesc for Kaspawalletd service.
|
// Kaspawalletd_ServiceDesc is the grpc.ServiceDesc for Kaspawalletd service.
|
||||||
// It's only intended for direct use with grpc.RegisterService,
|
// It's only intended for direct use with grpc.RegisterService,
|
||||||
// and not to be introspected or modified (even as a copy)
|
// and not to be introspected or modified (even as a copy)
|
||||||
@ -387,6 +423,10 @@ var Kaspawalletd_ServiceDesc = grpc.ServiceDesc{
|
|||||||
MethodName: "Sign",
|
MethodName: "Sign",
|
||||||
Handler: _Kaspawalletd_Sign_Handler,
|
Handler: _Kaspawalletd_Sign_Handler,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
MethodName: "GetVersion",
|
||||||
|
Handler: _Kaspawalletd_GetVersion_Handler,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
Streams: []grpc.StreamDesc{},
|
Streams: []grpc.StreamDesc{},
|
||||||
Metadata: "kaspawalletd.proto",
|
Metadata: "kaspawalletd.proto",
|
||||||
|
@ -2,6 +2,7 @@ package server
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
|
||||||
"github.com/kaspanet/kaspad/cmd/kaspawallet/daemon/pb"
|
"github.com/kaspanet/kaspad/cmd/kaspawallet/daemon/pb"
|
||||||
"github.com/kaspanet/kaspad/cmd/kaspawallet/libkaspawallet"
|
"github.com/kaspanet/kaspad/cmd/kaspawallet/libkaspawallet"
|
||||||
@ -14,13 +15,15 @@ func (s *server) GetBalance(_ context.Context, _ *pb.GetBalanceRequest) (*pb.Get
|
|||||||
s.lock.RLock()
|
s.lock.RLock()
|
||||||
defer s.lock.RUnlock()
|
defer s.lock.RUnlock()
|
||||||
|
|
||||||
|
if !s.isSynced() {
|
||||||
|
return nil, errors.Errorf("wallet daemon is not synced yet, %s", s.formatSyncStateReport())
|
||||||
|
}
|
||||||
|
|
||||||
dagInfo, err := s.rpcClient.GetBlockDAGInfo()
|
dagInfo, err := s.rpcClient.GetBlockDAGInfo()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
daaScore := dagInfo.VirtualDAAScore
|
daaScore := dagInfo.VirtualDAAScore
|
||||||
maturity := s.params.BlockCoinbaseMaturity
|
|
||||||
|
|
||||||
balancesMap := make(balancesMapType, 0)
|
balancesMap := make(balancesMapType, 0)
|
||||||
for _, entry := range s.utxosSortedByAmount {
|
for _, entry := range s.utxosSortedByAmount {
|
||||||
amount := entry.UTXOEntry.Amount()
|
amount := entry.UTXOEntry.Amount()
|
||||||
@ -30,7 +33,7 @@ func (s *server) GetBalance(_ context.Context, _ *pb.GetBalanceRequest) (*pb.Get
|
|||||||
balances = new(balancesType)
|
balances = new(balancesType)
|
||||||
balancesMap[address] = balances
|
balancesMap[address] = balances
|
||||||
}
|
}
|
||||||
if isUTXOSpendable(entry, daaScore, maturity) {
|
if s.isUTXOSpendable(entry, daaScore) {
|
||||||
balances.available += amount
|
balances.available += amount
|
||||||
} else {
|
} else {
|
||||||
balances.pending += amount
|
balances.pending += amount
|
||||||
@ -55,6 +58,8 @@ func (s *server) GetBalance(_ context.Context, _ *pb.GetBalanceRequest) (*pb.Get
|
|||||||
pending += balances.pending
|
pending += balances.pending
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log.Infof("GetBalance request scanned %d UTXOs overall over %d addresses", len(s.utxosSortedByAmount), len(balancesMap))
|
||||||
|
|
||||||
return &pb.GetBalanceResponse{
|
return &pb.GetBalanceResponse{
|
||||||
Available: available,
|
Available: available,
|
||||||
Pending: pending,
|
Pending: pending,
|
||||||
@ -62,9 +67,9 @@ func (s *server) GetBalance(_ context.Context, _ *pb.GetBalanceRequest) (*pb.Get
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func isUTXOSpendable(entry *walletUTXO, virtualDAAScore uint64, coinbaseMaturity uint64) bool {
|
func (s *server) isUTXOSpendable(entry *walletUTXO, virtualDAAScore uint64) bool {
|
||||||
if !entry.UTXOEntry.IsCoinbase() {
|
if !entry.UTXOEntry.IsCoinbase() {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return entry.UTXOEntry.BlockDAAScore()+coinbaseMaturity < virtualDAAScore
|
return entry.UTXOEntry.BlockDAAScore()+s.coinbaseMaturity < virtualDAAScore
|
||||||
}
|
}
|
||||||
|
@ -2,14 +2,16 @@ package server
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/kaspanet/kaspad/app/appmessage"
|
"github.com/kaspanet/kaspad/app/appmessage"
|
||||||
"github.com/kaspanet/kaspad/cmd/kaspawallet/daemon/pb"
|
"github.com/kaspanet/kaspad/cmd/kaspawallet/daemon/pb"
|
||||||
"github.com/kaspanet/kaspad/cmd/kaspawallet/libkaspawallet"
|
"github.com/kaspanet/kaspad/cmd/kaspawallet/libkaspawallet"
|
||||||
"github.com/kaspanet/kaspad/cmd/kaspawallet/libkaspawallet/serialization"
|
"github.com/kaspanet/kaspad/cmd/kaspawallet/libkaspawallet/serialization"
|
||||||
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||||
|
"github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing"
|
||||||
"github.com/kaspanet/kaspad/infrastructure/network/rpcclient"
|
"github.com/kaspanet/kaspad/infrastructure/network/rpcclient"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"time"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func (s *server) Broadcast(_ context.Context, request *pb.BroadcastRequest) (*pb.BroadcastResponse, error) {
|
func (s *server) Broadcast(_ context.Context, request *pb.BroadcastRequest) (*pb.BroadcastResponse, error) {
|
||||||
@ -54,16 +56,12 @@ func (s *server) broadcast(transactions [][]byte, isDomain bool) ([]string, erro
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
err = s.refreshUTXOs()
|
s.forceSync()
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return txIDs, nil
|
return txIDs, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func sendTransaction(client *rpcclient.RPCClient, tx *externalapi.DomainTransaction) (string, error) {
|
func sendTransaction(client *rpcclient.RPCClient, tx *externalapi.DomainTransaction) (string, error) {
|
||||||
submitTransactionResponse, err := client.SubmitTransaction(appmessage.DomainTransactionToRPCTransaction(tx), false)
|
submitTransactionResponse, err := client.SubmitTransaction(appmessage.DomainTransactionToRPCTransaction(tx), consensushashing.TransactionID(tx).String(), false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", errors.Wrapf(err, "error submitting transaction")
|
return "", errors.Wrapf(err, "error submitting transaction")
|
||||||
}
|
}
|
||||||
|
@ -3,19 +3,22 @@ package server
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/kaspanet/kaspad/cmd/kaspawallet/daemon/pb"
|
"github.com/kaspanet/kaspad/cmd/kaspawallet/daemon/pb"
|
||||||
"github.com/kaspanet/kaspad/cmd/kaspawallet/libkaspawallet"
|
"github.com/kaspanet/kaspad/cmd/kaspawallet/libkaspawallet"
|
||||||
"github.com/kaspanet/kaspad/domain/consensus/utils/constants"
|
"github.com/kaspanet/kaspad/domain/consensus/utils/constants"
|
||||||
"github.com/kaspanet/kaspad/util"
|
"github.com/kaspanet/kaspad/util"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"golang.org/x/exp/slices"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// TODO: Implement a better fee estimation mechanism
|
// TODO: Implement a better fee estimation mechanism
|
||||||
const feePerInput = 10000
|
const feePerInput = 10000
|
||||||
|
|
||||||
|
// The minimal change amount to target in order to avoid large storage mass (see KIP9 for more details).
|
||||||
|
// By having at least 0.2KAS in the change output we make sure that every transaction with send value >= 0.2KAS
|
||||||
|
// should succeed (at most 50K storage mass for each output, thus overall lower than standard mass upper bound which is 100K gram)
|
||||||
|
const minChangeTarget = constants.SompiPerKaspa / 5
|
||||||
|
|
||||||
func (s *server) CreateUnsignedTransactions(_ context.Context, request *pb.CreateUnsignedTransactionsRequest) (
|
func (s *server) CreateUnsignedTransactions(_ context.Context, request *pb.CreateUnsignedTransactionsRequest) (
|
||||||
*pb.CreateUnsignedTransactionsResponse, error,
|
*pb.CreateUnsignedTransactionsResponse, error,
|
||||||
) {
|
) {
|
||||||
@ -35,7 +38,6 @@ func (s *server) createUnsignedTransactions(address string, amount uint64, isSen
|
|||||||
if !s.isSynced() {
|
if !s.isSynced() {
|
||||||
return nil, errors.Errorf("wallet daemon is not synced yet, %s", s.formatSyncStateReport())
|
return nil, errors.Errorf("wallet daemon is not synced yet, %s", s.formatSyncStateReport())
|
||||||
}
|
}
|
||||||
|
|
||||||
// make sure address string is correct before proceeding to a
|
// make sure address string is correct before proceeding to a
|
||||||
// potentially long UTXO refreshment operation
|
// potentially long UTXO refreshment operation
|
||||||
toAddress, err := util.DecodeAddress(address, s.params.Prefix)
|
toAddress, err := util.DecodeAddress(address, s.params.Prefix)
|
||||||
@ -43,16 +45,11 @@ func (s *server) createUnsignedTransactions(address string, amount uint64, isSen
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = s.refreshUTXOs()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
var fromAddresses []*walletAddress
|
var fromAddresses []*walletAddress
|
||||||
for _, from := range fromAddressesString {
|
for _, from := range fromAddressesString {
|
||||||
fromAddress, exists := s.addressSet[from]
|
fromAddress, exists := s.addressSet[from]
|
||||||
if !exists {
|
if !exists {
|
||||||
return nil, fmt.Errorf("Specified from address %s does not exists", from)
|
return nil, fmt.Errorf("specified from address %s does not exists", from)
|
||||||
}
|
}
|
||||||
fromAddresses = append(fromAddresses, fromAddress)
|
fromAddresses = append(fromAddresses, fromAddress)
|
||||||
}
|
}
|
||||||
@ -106,19 +103,14 @@ func (s *server) selectUTXOs(spendAmount uint64, isSendAll bool, feePerInput uin
|
|||||||
return nil, 0, 0, err
|
return nil, 0, 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
coinbaseMaturity := s.params.BlockCoinbaseMaturity
|
|
||||||
if dagInfo.NetworkName == "kaspa-testnet-11" {
|
|
||||||
coinbaseMaturity = 1000
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, utxo := range s.utxosSortedByAmount {
|
for _, utxo := range s.utxosSortedByAmount {
|
||||||
if (fromAddresses != nil && !slices.Contains(fromAddresses, utxo.address)) ||
|
if (fromAddresses != nil && !walletAddressesContain(fromAddresses, utxo.address)) ||
|
||||||
!isUTXOSpendable(utxo, dagInfo.VirtualDAAScore, coinbaseMaturity) {
|
!s.isUTXOSpendable(utxo, dagInfo.VirtualDAAScore) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if broadcastTime, ok := s.usedOutpoints[*utxo.Outpoint]; ok {
|
if broadcastTime, ok := s.usedOutpoints[*utxo.Outpoint]; ok {
|
||||||
if time.Since(broadcastTime) > time.Minute {
|
if s.usedOutpointHasExpired(broadcastTime) {
|
||||||
delete(s.usedOutpoints, *utxo.Outpoint)
|
delete(s.usedOutpoints, *utxo.Outpoint)
|
||||||
} else {
|
} else {
|
||||||
continue
|
continue
|
||||||
@ -135,7 +127,12 @@ func (s *server) selectUTXOs(spendAmount uint64, isSendAll bool, feePerInput uin
|
|||||||
|
|
||||||
fee := feePerInput * uint64(len(selectedUTXOs))
|
fee := feePerInput * uint64(len(selectedUTXOs))
|
||||||
totalSpend := spendAmount + fee
|
totalSpend := spendAmount + fee
|
||||||
if !isSendAll && totalValue >= totalSpend {
|
// Two break cases (if not send all):
|
||||||
|
// 1. totalValue == totalSpend, so there's no change needed -> number of outputs = 1, so a single input is sufficient
|
||||||
|
// 2. totalValue > totalSpend, so there will be change and 2 outputs, therefor in order to not struggle with --
|
||||||
|
// 2.1 go-nodes dust patch we try and find at least 2 inputs (even though the next one is not necessary in terms of spend value)
|
||||||
|
// 2.2 KIP9 we try and make sure that the change amount is not too small
|
||||||
|
if !isSendAll && (totalValue == totalSpend || (totalValue >= totalSpend+minChangeTarget && len(selectedUTXOs) > 1)) {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -156,3 +153,13 @@ func (s *server) selectUTXOs(spendAmount uint64, isSendAll bool, feePerInput uin
|
|||||||
|
|
||||||
return selectedUTXOs, totalReceived, totalValue - totalSpend, nil
|
return selectedUTXOs, totalReceived, totalValue - totalSpend, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func walletAddressesContain(addresses []*walletAddress, contain *walletAddress) bool {
|
||||||
|
for _, address := range addresses {
|
||||||
|
if *address == *contain {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
@ -5,8 +5,11 @@ import (
|
|||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
"sync"
|
"sync"
|
||||||
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/kaspanet/kaspad/version"
|
||||||
|
|
||||||
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||||
|
|
||||||
"github.com/kaspanet/kaspad/util/txmass"
|
"github.com/kaspanet/kaspad/util/txmass"
|
||||||
@ -27,17 +30,22 @@ import (
|
|||||||
type server struct {
|
type server struct {
|
||||||
pb.UnimplementedKaspawalletdServer
|
pb.UnimplementedKaspawalletdServer
|
||||||
|
|
||||||
rpcClient *rpcclient.RPCClient
|
rpcClient *rpcclient.RPCClient // RPC client for ongoing user requests
|
||||||
params *dagconfig.Params
|
backgroundRPCClient *rpcclient.RPCClient // RPC client dedicated for address and UTXO background fetching
|
||||||
|
params *dagconfig.Params
|
||||||
|
coinbaseMaturity uint64 // Is different from default if we use testnet-11
|
||||||
|
|
||||||
lock sync.RWMutex
|
lock sync.RWMutex
|
||||||
utxosSortedByAmount []*walletUTXO
|
utxosSortedByAmount []*walletUTXO
|
||||||
nextSyncStartIndex uint32
|
nextSyncStartIndex uint32
|
||||||
keysFile *keys.File
|
keysFile *keys.File
|
||||||
shutdown chan struct{}
|
shutdown chan struct{}
|
||||||
addressSet walletAddressSet
|
forceSyncChan chan struct{}
|
||||||
txMassCalculator *txmass.Calculator
|
startTimeOfLastCompletedRefresh time.Time
|
||||||
usedOutpoints map[externalapi.DomainOutpoint]time.Time
|
addressSet walletAddressSet
|
||||||
|
txMassCalculator *txmass.Calculator
|
||||||
|
usedOutpoints map[externalapi.DomainOutpoint]time.Time
|
||||||
|
firstSyncDone atomic.Bool
|
||||||
|
|
||||||
isLogFinalProgressLineShown bool
|
isLogFinalProgressLineShown bool
|
||||||
maxUsedAddressesForLog uint32
|
maxUsedAddressesForLog uint32
|
||||||
@ -59,6 +67,7 @@ func Start(params *dagconfig.Params, listen, rpcServer string, keysFilePath stri
|
|||||||
profiling.Start(profile, log)
|
profiling.Start(profile, log)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log.Infof("Version %s", version.Version())
|
||||||
listener, err := net.Listen("tcp", listen)
|
listener, err := net.Listen("tcp", listen)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return (errors.Wrapf(err, "Error listening to TCP on %s", listen))
|
return (errors.Wrapf(err, "Error listening to TCP on %s", listen))
|
||||||
@ -70,6 +79,10 @@ func Start(params *dagconfig.Params, listen, rpcServer string, keysFilePath stri
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return (errors.Wrapf(err, "Error connecting to RPC server %s", rpcServer))
|
return (errors.Wrapf(err, "Error connecting to RPC server %s", rpcServer))
|
||||||
}
|
}
|
||||||
|
backgroundRPCClient, err := connectToRPC(params, rpcServer, timeout)
|
||||||
|
if err != nil {
|
||||||
|
return (errors.Wrapf(err, "Error making a second connection to RPC server %s", rpcServer))
|
||||||
|
}
|
||||||
|
|
||||||
log.Infof("Connected, reading keys file %s...", keysFilePath)
|
log.Infof("Connected, reading keys file %s...", keysFilePath)
|
||||||
keysFile, err := keys.ReadKeysFile(params, keysFilePath)
|
keysFile, err := keys.ReadKeysFile(params, keysFilePath)
|
||||||
@ -82,13 +95,26 @@ func Start(params *dagconfig.Params, listen, rpcServer string, keysFilePath stri
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dagInfo, err := rpcClient.GetBlockDAGInfo()
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
coinbaseMaturity := params.BlockCoinbaseMaturity
|
||||||
|
if dagInfo.NetworkName == "kaspa-testnet-11" {
|
||||||
|
coinbaseMaturity = 1000
|
||||||
|
}
|
||||||
|
|
||||||
serverInstance := &server{
|
serverInstance := &server{
|
||||||
rpcClient: rpcClient,
|
rpcClient: rpcClient,
|
||||||
|
backgroundRPCClient: backgroundRPCClient,
|
||||||
params: params,
|
params: params,
|
||||||
|
coinbaseMaturity: coinbaseMaturity,
|
||||||
utxosSortedByAmount: []*walletUTXO{},
|
utxosSortedByAmount: []*walletUTXO{},
|
||||||
nextSyncStartIndex: 0,
|
nextSyncStartIndex: 0,
|
||||||
keysFile: keysFile,
|
keysFile: keysFile,
|
||||||
shutdown: make(chan struct{}),
|
shutdown: make(chan struct{}),
|
||||||
|
forceSyncChan: make(chan struct{}),
|
||||||
addressSet: make(walletAddressSet),
|
addressSet: make(walletAddressSet),
|
||||||
txMassCalculator: txmass.NewCalculator(params.MassPerTxByte, params.MassPerScriptPubKeyByte, params.MassPerSigOp),
|
txMassCalculator: txmass.NewCalculator(params.MassPerTxByte, params.MassPerScriptPubKeyByte, params.MassPerSigOp),
|
||||||
usedOutpoints: map[externalapi.DomainOutpoint]time.Time{},
|
usedOutpoints: map[externalapi.DomainOutpoint]time.Time{},
|
||||||
@ -98,8 +124,8 @@ func Start(params *dagconfig.Params, listen, rpcServer string, keysFilePath stri
|
|||||||
}
|
}
|
||||||
|
|
||||||
log.Infof("Read, syncing the wallet...")
|
log.Infof("Read, syncing the wallet...")
|
||||||
spawn("serverInstance.sync", func() {
|
spawn("serverInstance.syncLoop", func() {
|
||||||
err := serverInstance.sync()
|
err := serverInstance.syncLoop()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
printErrorAndExit(errors.Wrap(err, "error syncing the wallet"))
|
printErrorAndExit(errors.Wrap(err, "error syncing the wallet"))
|
||||||
}
|
}
|
||||||
|
@ -264,7 +264,7 @@ func (s *server) moreUTXOsForMergeTransaction(alreadySelectedUTXOs []*libkaspawa
|
|||||||
if _, ok := alreadySelectedUTXOsMap[*utxo.Outpoint]; ok {
|
if _, ok := alreadySelectedUTXOsMap[*utxo.Outpoint]; ok {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if !isUTXOSpendable(utxo, dagInfo.VirtualDAAScore, s.params.BlockCoinbaseMaturity) {
|
if !s.isUTXOSpendable(utxo, dagInfo.VirtualDAAScore) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
additionalUTXOs = append(additionalUTXOs, &libkaspawallet.UTXO{
|
additionalUTXOs = append(additionalUTXOs, &libkaspawallet.UTXO{
|
||||||
|
@ -23,7 +23,7 @@ func (was walletAddressSet) strings() []string {
|
|||||||
return addresses
|
return addresses
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *server) sync() error {
|
func (s *server) syncLoop() error {
|
||||||
ticker := time.NewTicker(time.Second)
|
ticker := time.NewTicker(time.Second)
|
||||||
defer ticker.Stop()
|
defer ticker.Stop()
|
||||||
|
|
||||||
@ -32,29 +32,39 @@ func (s *server) sync() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = s.refreshExistingUTXOsWithLock()
|
err = s.refreshUTXOs()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
for range ticker.C {
|
s.firstSyncDone.Store(true)
|
||||||
err = s.collectFarAddresses()
|
log.Infof("Wallet is synced and ready for operation")
|
||||||
if err != nil {
|
|
||||||
return err
|
for {
|
||||||
|
select {
|
||||||
|
case <-ticker.C:
|
||||||
|
case <-s.forceSyncChan:
|
||||||
}
|
}
|
||||||
|
|
||||||
err = s.collectRecentAddresses()
|
err := s.sync()
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = s.refreshExistingUTXOsWithLock()
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
func (s *server) sync() error {
|
||||||
|
err := s.collectFarAddresses()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = s.collectRecentAddresses()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return s.refreshUTXOs()
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -158,7 +168,7 @@ func (s *server) collectAddresses(start, end uint32) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
getBalancesByAddressesResponse, err := s.rpcClient.GetBalancesByAddresses(addressSet.strings())
|
getBalancesByAddressesResponse, err := s.backgroundRPCClient.GetBalancesByAddresses(addressSet.strings())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -208,15 +218,17 @@ func (s *server) updateAddressesAndLastUsedIndexes(requestedAddressSet walletAdd
|
|||||||
return s.keysFile.SetLastUsedInternalIndex(lastUsedInternalIndex)
|
return s.keysFile.SetLastUsedInternalIndex(lastUsedInternalIndex)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *server) refreshExistingUTXOsWithLock() error {
|
func (s *server) usedOutpointHasExpired(outpointBroadcastTime time.Time) bool {
|
||||||
s.lock.Lock()
|
// If the node returns a UTXO we previously attempted to spend and enough time has passed, we assume
|
||||||
defer s.lock.Unlock()
|
// that the network rejected or lost the previous transaction and allow a reuse. We set this time
|
||||||
|
// interval to a minute.
|
||||||
return s.refreshUTXOs()
|
// We also verify that a full refresh UTXO operation started after this time point and has already
|
||||||
|
// completed, in order to make sure that indeed this state reflects a state obtained following the required wait time.
|
||||||
|
return s.startTimeOfLastCompletedRefresh.After(outpointBroadcastTime.Add(time.Minute))
|
||||||
}
|
}
|
||||||
|
|
||||||
// updateUTXOSet clears the current UTXO set, and re-fills it with the given entries
|
// updateUTXOSet clears the current UTXO set, and re-fills it with the given entries
|
||||||
func (s *server) updateUTXOSet(entries []*appmessage.UTXOsByAddressesEntry, mempoolEntries []*appmessage.MempoolEntryByAddress) error {
|
func (s *server) updateUTXOSet(entries []*appmessage.UTXOsByAddressesEntry, mempoolEntries []*appmessage.MempoolEntryByAddress, refreshStart time.Time) error {
|
||||||
utxos := make([]*walletUTXO, 0, len(entries))
|
utxos := make([]*walletUTXO, 0, len(entries))
|
||||||
|
|
||||||
exclude := make(map[appmessage.RPCOutpoint]struct{})
|
exclude := make(map[appmessage.RPCOutpoint]struct{})
|
||||||
@ -243,6 +255,7 @@ func (s *server) updateUTXOSet(entries []*appmessage.UTXOsByAddressesEntry, memp
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// No need to lock for reading since the only writer of this set is on `syncLoop` on the same goroutine.
|
||||||
address, ok := s.addressSet[entry.Address]
|
address, ok := s.addressSet[entry.Address]
|
||||||
if !ok {
|
if !ok {
|
||||||
return errors.Errorf("Got result from address %s even though it wasn't requested", entry.Address)
|
return errors.Errorf("Got result from address %s even though it wasn't requested", entry.Address)
|
||||||
@ -256,32 +269,56 @@ func (s *server) updateUTXOSet(entries []*appmessage.UTXOsByAddressesEntry, memp
|
|||||||
|
|
||||||
sort.Slice(utxos, func(i, j int) bool { return utxos[i].UTXOEntry.Amount() > utxos[j].UTXOEntry.Amount() })
|
sort.Slice(utxos, func(i, j int) bool { return utxos[i].UTXOEntry.Amount() > utxos[j].UTXOEntry.Amount() })
|
||||||
|
|
||||||
|
s.lock.Lock()
|
||||||
|
s.startTimeOfLastCompletedRefresh = refreshStart
|
||||||
s.utxosSortedByAmount = utxos
|
s.utxosSortedByAmount = utxos
|
||||||
|
|
||||||
|
// Cleanup expired used outpoints to avoid a memory leak
|
||||||
|
for outpoint, broadcastTime := range s.usedOutpoints {
|
||||||
|
if s.usedOutpointHasExpired(broadcastTime) {
|
||||||
|
delete(s.usedOutpoints, outpoint)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
s.lock.Unlock()
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *server) refreshUTXOs() error {
|
func (s *server) refreshUTXOs() error {
|
||||||
|
refreshStart := time.Now()
|
||||||
|
|
||||||
|
// No need to lock for reading since the only writer of this set is on `syncLoop` on the same goroutine.
|
||||||
|
addresses := s.addressSet.strings()
|
||||||
// It's important to check the mempool before calling `GetUTXOsByAddresses`:
|
// It's important to check the mempool before calling `GetUTXOsByAddresses`:
|
||||||
// If we would do it the other way around an output can be spent in the mempool
|
// If we would do it the other way around an output can be spent in the mempool
|
||||||
// and not in consensus, and between the calls its spending transaction will be
|
// and not in consensus, and between the calls its spending transaction will be
|
||||||
// added to consensus and removed from the mempool, so `getUTXOsByAddressesResponse`
|
// added to consensus and removed from the mempool, so `getUTXOsByAddressesResponse`
|
||||||
// will include an obsolete output.
|
// will include an obsolete output.
|
||||||
mempoolEntriesByAddresses, err := s.rpcClient.GetMempoolEntriesByAddresses(s.addressSet.strings(), true, true)
|
mempoolEntriesByAddresses, err := s.backgroundRPCClient.GetMempoolEntriesByAddresses(addresses, true, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
getUTXOsByAddressesResponse, err := s.rpcClient.GetUTXOsByAddresses(s.addressSet.strings())
|
getUTXOsByAddressesResponse, err := s.backgroundRPCClient.GetUTXOsByAddresses(addresses)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return s.updateUTXOSet(getUTXOsByAddressesResponse.Entries, mempoolEntriesByAddresses.Entries)
|
return s.updateUTXOSet(getUTXOsByAddressesResponse.Entries, mempoolEntriesByAddresses.Entries, refreshStart)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *server) forceSync() {
|
||||||
|
// Technically if two callers check the `if` simultaneously they will both spawn a
|
||||||
|
// goroutine, but we don't care about the small redundancy in such a rare case.
|
||||||
|
if len(s.forceSyncChan) == 0 {
|
||||||
|
go func() {
|
||||||
|
s.forceSyncChan <- struct{}{}
|
||||||
|
}()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *server) isSynced() bool {
|
func (s *server) isSynced() bool {
|
||||||
return s.nextSyncStartIndex > s.maxUsedIndex()
|
return s.nextSyncStartIndex > s.maxUsedIndex() && s.firstSyncDone.Load()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *server) formatSyncStateReport() string {
|
func (s *server) formatSyncStateReport() string {
|
||||||
@ -291,8 +328,11 @@ func (s *server) formatSyncStateReport() string {
|
|||||||
maxUsedIndex = s.nextSyncStartIndex
|
maxUsedIndex = s.nextSyncStartIndex
|
||||||
}
|
}
|
||||||
|
|
||||||
return fmt.Sprintf("scanned %d out of %d addresses (%.2f%%)",
|
if s.nextSyncStartIndex < s.maxUsedIndex() {
|
||||||
s.nextSyncStartIndex, maxUsedIndex, float64(s.nextSyncStartIndex)*100.0/float64(maxUsedIndex))
|
return fmt.Sprintf("scanned %d out of %d addresses (%.2f%%)",
|
||||||
|
s.nextSyncStartIndex, maxUsedIndex, float64(s.nextSyncStartIndex)*100.0/float64(maxUsedIndex))
|
||||||
|
}
|
||||||
|
return "loading the wallet UTXO set"
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *server) updateSyncingProgressLog(currProcessedAddresses, currMaxUsedAddresses uint32) {
|
func (s *server) updateSyncingProgressLog(currProcessedAddresses, currMaxUsedAddresses uint32) {
|
||||||
@ -311,7 +351,7 @@ func (s *server) updateSyncingProgressLog(currProcessedAddresses, currMaxUsedAdd
|
|||||||
|
|
||||||
if s.maxProcessedAddressesForLog >= s.maxUsedAddressesForLog {
|
if s.maxProcessedAddressesForLog >= s.maxUsedAddressesForLog {
|
||||||
if !s.isLogFinalProgressLineShown {
|
if !s.isLogFinalProgressLineShown {
|
||||||
log.Infof("Wallet is synced, ready for queries")
|
log.Infof("Finished scanning recent addresses")
|
||||||
s.isLogFinalProgressLineShown = true
|
s.isLogFinalProgressLineShown = true
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
16
cmd/kaspawallet/daemon/server/version.go
Normal file
16
cmd/kaspawallet/daemon/server/version.go
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
package server
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"github.com/kaspanet/kaspad/cmd/kaspawallet/daemon/pb"
|
||||||
|
"github.com/kaspanet/kaspad/version"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (s *server) GetVersion(_ context.Context, _ *pb.GetVersionRequest) (*pb.GetVersionResponse, error) {
|
||||||
|
s.lock.RLock()
|
||||||
|
defer s.lock.RUnlock()
|
||||||
|
|
||||||
|
return &pb.GetVersionResponse{
|
||||||
|
Version: version.Version(),
|
||||||
|
}, nil
|
||||||
|
}
|
26
cmd/kaspawallet/get_daemon_version.go
Normal file
26
cmd/kaspawallet/get_daemon_version.go
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"github.com/kaspanet/kaspad/cmd/kaspawallet/daemon/client"
|
||||||
|
"github.com/kaspanet/kaspad/cmd/kaspawallet/daemon/pb"
|
||||||
|
)
|
||||||
|
|
||||||
|
func getDaemonVersion(conf *getDaemonVersionConfig) error {
|
||||||
|
daemonClient, tearDown, err := client.Connect(conf.DaemonAddress)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer tearDown()
|
||||||
|
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), daemonTimeout)
|
||||||
|
defer cancel()
|
||||||
|
response, err := daemonClient.GetVersion(ctx, &pb.GetVersionRequest{})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
fmt.Println(response.Version)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
@ -1,10 +1,11 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import "github.com/pkg/errors"
|
import (
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
subCmd, config := parseCommandLine()
|
subCmd, config := parseCommandLine()
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
switch subCmd {
|
switch subCmd {
|
||||||
case createSubCmd:
|
case createSubCmd:
|
||||||
@ -31,6 +32,10 @@ func main() {
|
|||||||
err = startDaemon(config.(*startDaemonConfig))
|
err = startDaemon(config.(*startDaemonConfig))
|
||||||
case sweepSubCmd:
|
case sweepSubCmd:
|
||||||
err = sweep(config.(*sweepConfig))
|
err = sweep(config.(*sweepConfig))
|
||||||
|
case versionSubCmd:
|
||||||
|
showVersion()
|
||||||
|
case getDaemonVersionSubCmd:
|
||||||
|
err = getDaemonVersion(config.(*getDaemonVersionConfig))
|
||||||
default:
|
default:
|
||||||
err = errors.Errorf("Unknown sub-command '%s'\n", subCmd)
|
err = errors.Errorf("Unknown sub-command '%s'\n", subCmd)
|
||||||
}
|
}
|
||||||
|
@ -75,23 +75,29 @@ func send(conf *sendConfig) error {
|
|||||||
signedTransactions[i] = signedTransaction
|
signedTransactions[i] = signedTransaction
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(signedTransactions) > 1 {
|
fmt.Printf("Broadcasting %d transaction(s)\n", len(signedTransactions))
|
||||||
fmt.Printf("Broadcasting %d transactions\n", len(signedTransactions))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Since we waited for user input when getting the password, which could take unbound amount of time -
|
// Since we waited for user input when getting the password, which could take unbound amount of time -
|
||||||
// create a new context for broadcast, to reset the timeout.
|
// create a new context for broadcast, to reset the timeout.
|
||||||
broadcastCtx, broadcastCancel := context.WithTimeout(context.Background(), daemonTimeout)
|
broadcastCtx, broadcastCancel := context.WithTimeout(context.Background(), daemonTimeout)
|
||||||
defer broadcastCancel()
|
defer broadcastCancel()
|
||||||
|
|
||||||
response, err := daemonClient.Broadcast(broadcastCtx, &pb.BroadcastRequest{Transactions: signedTransactions})
|
const chunkSize = 100 // To avoid sending a message bigger than the gRPC max message size, we split it to chunks
|
||||||
if err != nil {
|
for offset := 0; offset < len(signedTransactions); offset += chunkSize {
|
||||||
return err
|
end := len(signedTransactions)
|
||||||
}
|
if offset+chunkSize <= len(signedTransactions) {
|
||||||
fmt.Println("Transactions were sent successfully")
|
end = offset + chunkSize
|
||||||
fmt.Println("Transaction ID(s): ")
|
}
|
||||||
for _, txID := range response.TxIDs {
|
|
||||||
fmt.Printf("\t%s\n", txID)
|
chunk := signedTransactions[offset:end]
|
||||||
|
response, err := daemonClient.Broadcast(broadcastCtx, &pb.BroadcastRequest{Transactions: chunk})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
fmt.Printf("Broadcasted %d transaction(s) (broadcasted %.2f%% of the transactions so far)\n", len(chunk), 100*float64(end)/float64(len(signedTransactions)))
|
||||||
|
fmt.Println("Broadcasted Transaction ID(s): ")
|
||||||
|
for _, txID := range response.TxIDs {
|
||||||
|
fmt.Printf("\t%s\n", txID)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if conf.Verbose {
|
if conf.Verbose {
|
||||||
|
15
cmd/kaspawallet/version.go
Normal file
15
cmd/kaspawallet/version.go
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/kaspanet/kaspad/version"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
func showVersion() {
|
||||||
|
appName := filepath.Base(os.Args[0])
|
||||||
|
appName = strings.TrimSuffix(appName, filepath.Ext(appName))
|
||||||
|
fmt.Println(appName, "version", version.Version())
|
||||||
|
}
|
@ -1,23 +1,44 @@
|
|||||||
package rpcclient
|
package rpcclient
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/kaspanet/kaspad/app/appmessage"
|
"github.com/kaspanet/kaspad/app/appmessage"
|
||||||
)
|
)
|
||||||
|
|
||||||
// SubmitTransaction sends an RPC request respective to the function's name and returns the RPC server's response
|
// SubmitTransaction sends an RPC request respective to the function's name and returns the RPC server's response
|
||||||
func (c *RPCClient) SubmitTransaction(transaction *appmessage.RPCTransaction, allowOrphan bool) (*appmessage.SubmitTransactionResponseMessage, error) {
|
func (c *RPCClient) SubmitTransaction(transaction *appmessage.RPCTransaction, transactionID string, allowOrphan bool) (*appmessage.SubmitTransactionResponseMessage, error) {
|
||||||
err := c.rpcRouter.outgoingRoute().Enqueue(appmessage.NewSubmitTransactionRequestMessage(transaction, allowOrphan))
|
err := c.rpcRouter.outgoingRoute().Enqueue(appmessage.NewSubmitTransactionRequestMessage(transaction, allowOrphan))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
response, err := c.route(appmessage.CmdSubmitTransactionResponseMessage).DequeueWithTimeout(c.timeout)
|
for {
|
||||||
if err != nil {
|
response, err := c.route(appmessage.CmdSubmitTransactionResponseMessage).DequeueWithTimeout(c.timeout)
|
||||||
return nil, err
|
if err != nil {
|
||||||
}
|
return nil, err
|
||||||
submitTransactionResponse := response.(*appmessage.SubmitTransactionResponseMessage)
|
}
|
||||||
if submitTransactionResponse.Error != nil {
|
submitTransactionResponse := response.(*appmessage.SubmitTransactionResponseMessage)
|
||||||
return nil, c.convertRPCError(submitTransactionResponse.Error)
|
// Match the response to the expected ID. If they are different it means we got an old response which we
|
||||||
}
|
// previously timed-out on, so we log and continue waiting for the correct current response.
|
||||||
|
if submitTransactionResponse.TransactionID != transactionID {
|
||||||
|
if submitTransactionResponse.Error != nil {
|
||||||
|
// A non-updated Kaspad might return an empty ID in the case of error, so in
|
||||||
|
// such a case we fallback to checking if the error contains the expected ID
|
||||||
|
if submitTransactionResponse.TransactionID != "" || !strings.Contains(submitTransactionResponse.Error.Message, transactionID) {
|
||||||
|
log.Warnf("SubmitTransaction: received an error response for previous request: %s", submitTransactionResponse.Error)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
return submitTransactionResponse, nil
|
} else {
|
||||||
|
log.Warnf("SubmitTransaction: received a successful response for previous request with ID %s",
|
||||||
|
submitTransactionResponse.TransactionID)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if submitTransactionResponse.Error != nil {
|
||||||
|
return nil, c.convertRPCError(submitTransactionResponse.Error)
|
||||||
|
}
|
||||||
|
|
||||||
|
return submitTransactionResponse, nil
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -86,7 +86,7 @@ func submitAnAmountOfTransactionsToTheMempool(t *testing.T, rpcClient *rpcclient
|
|||||||
|
|
||||||
for i, transaction := range transactions {
|
for i, transaction := range transactions {
|
||||||
rpcTransaction := appmessage.DomainTransactionToRPCTransaction(transaction)
|
rpcTransaction := appmessage.DomainTransactionToRPCTransaction(transaction)
|
||||||
_, err := rpcClient.SubmitTransaction(rpcTransaction, false)
|
_, err := rpcClient.SubmitTransaction(rpcTransaction, consensushashing.TransactionID(transaction).String(), false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if ignoreOrphanRejects && strings.Contains(err.Error(), "orphan") {
|
if ignoreOrphanRejects && strings.Contains(err.Error(), "orphan") {
|
||||||
continue
|
continue
|
||||||
|
@ -53,7 +53,7 @@ func TestTxRelay(t *testing.T) {
|
|||||||
msgTx := generateTx(t, secondBlock.Transactions[transactionhelper.CoinbaseTransactionIndex], payer, payee)
|
msgTx := generateTx(t, secondBlock.Transactions[transactionhelper.CoinbaseTransactionIndex], payer, payee)
|
||||||
domainTransaction := appmessage.MsgTxToDomainTransaction(msgTx)
|
domainTransaction := appmessage.MsgTxToDomainTransaction(msgTx)
|
||||||
rpcTransaction := appmessage.DomainTransactionToRPCTransaction(domainTransaction)
|
rpcTransaction := appmessage.DomainTransactionToRPCTransaction(domainTransaction)
|
||||||
response, err := payer.rpcClient.SubmitTransaction(rpcTransaction, false)
|
response, err := payer.rpcClient.SubmitTransaction(rpcTransaction, consensushashing.TransactionID(domainTransaction).String(), false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Error submitting transaction: %+v", err)
|
t.Fatalf("Error submitting transaction: %+v", err)
|
||||||
}
|
}
|
||||||
|
@ -88,8 +88,8 @@ func TestUTXOIndex(t *testing.T) {
|
|||||||
// Submit a few transactions that spends some UTXOs
|
// Submit a few transactions that spends some UTXOs
|
||||||
const transactionAmountToSpend = 5
|
const transactionAmountToSpend = 5
|
||||||
for i := 0; i < transactionAmountToSpend; i++ {
|
for i := 0; i < transactionAmountToSpend; i++ {
|
||||||
rpcTransaction := buildTransactionForUTXOIndexTest(t, notificationEntries[i])
|
rpcTransaction, transactionID := buildTransactionForUTXOIndexTest(t, notificationEntries[i])
|
||||||
_, err = kaspad.rpcClient.SubmitTransaction(rpcTransaction, false)
|
_, err = kaspad.rpcClient.SubmitTransaction(rpcTransaction, transactionID, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Error submitting transaction: %s", err)
|
t.Fatalf("Error submitting transaction: %s", err)
|
||||||
}
|
}
|
||||||
@ -171,7 +171,7 @@ func TestUTXOIndex(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildTransactionForUTXOIndexTest(t *testing.T, entry *appmessage.UTXOsByAddressesEntry) *appmessage.RPCTransaction {
|
func buildTransactionForUTXOIndexTest(t *testing.T, entry *appmessage.UTXOsByAddressesEntry) (*appmessage.RPCTransaction, string) {
|
||||||
transactionIDBytes, err := hex.DecodeString(entry.Outpoint.TransactionID)
|
transactionIDBytes, err := hex.DecodeString(entry.Outpoint.TransactionID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Error decoding transaction ID: %s", err)
|
t.Fatalf("Error decoding transaction ID: %s", err)
|
||||||
@ -224,5 +224,5 @@ func buildTransactionForUTXOIndexTest(t *testing.T, entry *appmessage.UTXOsByAdd
|
|||||||
msgTx.TxIn[0].SignatureScript = signatureScript
|
msgTx.TxIn[0].SignatureScript = signatureScript
|
||||||
|
|
||||||
domainTransaction := appmessage.MsgTxToDomainTransaction(msgTx)
|
domainTransaction := appmessage.MsgTxToDomainTransaction(msgTx)
|
||||||
return appmessage.DomainTransactionToRPCTransaction(domainTransaction)
|
return appmessage.DomainTransactionToRPCTransaction(domainTransaction), consensushashing.TransactionID(domainTransaction).String()
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,7 @@ const validCharacters = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrs
|
|||||||
const (
|
const (
|
||||||
appMajor uint = 0
|
appMajor uint = 0
|
||||||
appMinor uint = 12
|
appMinor uint = 12
|
||||||
appPatch uint = 15
|
appPatch uint = 17
|
||||||
)
|
)
|
||||||
|
|
||||||
// appBuild is defined as a variable so it can be overridden during the build
|
// appBuild is defined as a variable so it can be overridden during the build
|
||||||
|
Loading…
x
Reference in New Issue
Block a user