mirror of
https://github.com/kaspanet/kaspad.git
synced 2025-03-30 15:08:33 +00:00
Some fixes
This commit is contained in:
parent
30fcd217ed
commit
fedbb3bd0f
1
.gitignore
vendored
1
.gitignore
vendored
@ -53,6 +53,7 @@ _testmain.go
|
||||
debug
|
||||
debug.test
|
||||
__debug_bin
|
||||
*__debug_*
|
||||
|
||||
# CI
|
||||
version.txt
|
||||
|
@ -21,10 +21,13 @@ func createUnsignedTransaction(conf *createUnsignedTransactionConfig) error {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), daemonTimeout)
|
||||
defer cancel()
|
||||
|
||||
sendAmountSompi, err := utils.KasToSompi(conf.SendAmount)
|
||||
var sendAmountSompi uint64
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
if !conf.IsSendAll {
|
||||
sendAmountSompi, err = utils.KasToSompi(conf.SendAmount)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
feeRate := &pb.FeeRate{
|
||||
|
@ -2,9 +2,10 @@ package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/kaspanet/kaspad/cmd/kaspawallet/daemon/server"
|
||||
"time"
|
||||
|
||||
"github.com/kaspanet/kaspad/cmd/kaspawallet/daemon/server"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/kaspanet/kaspad/cmd/kaspawallet/daemon/pb"
|
||||
|
@ -13,6 +13,7 @@ service kaspawalletd {
|
||||
rpc NewAddress(NewAddressRequest) returns (NewAddressResponse) {}
|
||||
rpc Shutdown(ShutdownRequest) returns (ShutdownResponse) {}
|
||||
rpc Broadcast(BroadcastRequest) returns (BroadcastResponse) {}
|
||||
// BroadcastRBF assumes that all transactions depends on the first one
|
||||
rpc BroadcastRBF(BroadcastRequest) returns (BroadcastResponse) {}
|
||||
// Since SendRequest contains a password - this command should only be used on
|
||||
// a trusted or secure connection
|
||||
|
@ -26,6 +26,7 @@ func (s *server) BroadcastRBF(_ context.Context, request *pb.BroadcastRequest) (
|
||||
return &pb.BroadcastResponse{TxIDs: txIDs}, nil
|
||||
}
|
||||
|
||||
// broadcastRBF assumes that all transactions depends on the first one
|
||||
func (s *server) broadcastRBF(transactions [][]byte, isDomain bool) ([]string, error) {
|
||||
|
||||
txIDs := make([]string, len(transactions))
|
||||
@ -46,9 +47,20 @@ func (s *server) broadcastRBF(transactions [][]byte, isDomain bool) ([]string, e
|
||||
}
|
||||
}
|
||||
|
||||
txIDs[i], err = sendTransactionRBF(s.rpcClient, tx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
// Once the first transaction is added to the mempool, the transactions that depend
|
||||
// on the replaced transaction will be removed, so there's no need to submit them
|
||||
// as RBF transactions.
|
||||
if i == 0 {
|
||||
txIDs[i], err = sendTransactionRBF(s.rpcClient, tx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
txIDs[i], err = sendTransaction(s.rpcClient, tx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
for _, input := range tx.Inputs {
|
||||
|
@ -25,6 +25,40 @@ func (s *server) BumpFee(_ context.Context, request *pb.BumpFeeRequest) (*pb.Bum
|
||||
return nil, err
|
||||
}
|
||||
|
||||
outpointsToInputs := make(map[externalapi.DomainOutpoint]*externalapi.DomainTransactionInput)
|
||||
var maxUTXO *walletUTXO
|
||||
for _, input := range domainTx.Inputs {
|
||||
outpointsToInputs[input.PreviousOutpoint] = input
|
||||
utxo, ok := s.mempoolExcludedUTXOs[input.PreviousOutpoint]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
input.UTXOEntry = utxo.UTXOEntry
|
||||
if maxUTXO == nil || utxo.UTXOEntry.Amount() > maxUTXO.UTXOEntry.Amount() {
|
||||
maxUTXO = utxo
|
||||
}
|
||||
}
|
||||
|
||||
if maxUTXO == nil {
|
||||
// If we got here it means for some reason s.mempoolExcludedUTXOs is not up to date and we need to search for the UTXOs in s.utxosSortedByAmount
|
||||
for _, utxo := range s.utxosSortedByAmount {
|
||||
input, ok := outpointsToInputs[*utxo.Outpoint]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
input.UTXOEntry = utxo.UTXOEntry
|
||||
if maxUTXO == nil || utxo.UTXOEntry.Amount() > maxUTXO.UTXOEntry.Amount() {
|
||||
maxUTXO = utxo
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if maxUTXO == nil {
|
||||
return nil, errors.Errorf("no UTXOs were found for transaction %s. This probably means the transaction is already accepted", request.TxID)
|
||||
}
|
||||
|
||||
mass := s.txMassCalculator.CalculateTransactionOverallMass(domainTx)
|
||||
feeRate := float64(entry.Entry.Fee) / float64(mass)
|
||||
newFeeRate, err := s.calculateFeeRate(request.FeeRate)
|
||||
@ -36,37 +70,6 @@ func (s *server) BumpFee(_ context.Context, request *pb.BumpFeeRequest) (*pb.Bum
|
||||
return nil, errors.Errorf("new fee rate (%f) is not higher than the current fee rate (%f)", newFeeRate, feeRate)
|
||||
}
|
||||
|
||||
outpointsSet := make(map[externalapi.DomainOutpoint]struct{})
|
||||
var maxUTXO *walletUTXO
|
||||
for _, input := range domainTx.Inputs {
|
||||
outpointsSet[input.PreviousOutpoint] = struct{}{}
|
||||
utxo, ok := s.mempoolExcludedUTXOs[input.PreviousOutpoint]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
if maxUTXO == nil || utxo.UTXOEntry.Amount() > maxUTXO.UTXOEntry.Amount() {
|
||||
maxUTXO = utxo
|
||||
}
|
||||
}
|
||||
|
||||
if maxUTXO == nil {
|
||||
// If we got here it means for some reason s.mempoolExcludedUTXOs is not up to date and we need to search for the UTXOs in s.utxosSortedByAmount
|
||||
for _, utxo := range s.utxosSortedByAmount {
|
||||
if _, ok := outpointsSet[*utxo.Outpoint]; !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
if maxUTXO == nil || utxo.UTXOEntry.Amount() > maxUTXO.UTXOEntry.Amount() {
|
||||
maxUTXO = utxo
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if maxUTXO == nil {
|
||||
return nil, errors.Errorf("no UTXOs were found for transaction %s. This probably means the transaction is already accepted", request.TxID)
|
||||
}
|
||||
|
||||
if len(domainTx.Outputs) == 0 || len(domainTx.Outputs) > 2 {
|
||||
return nil, errors.Errorf("kaspawallet supports only transactions with 1 or 2 outputs in transaction %s, but this transaction got %d", request.TxID, len(domainTx.Outputs))
|
||||
}
|
||||
@ -80,7 +83,11 @@ func (s *server) BumpFee(_ context.Context, request *pb.BumpFeeRequest) (*pb.Bum
|
||||
fromAddresses = append(fromAddresses, fromAddress)
|
||||
}
|
||||
|
||||
selectedUTXOs, spendValue, changeSompi, err := s.selectUTXOsWithPreselected([]*walletUTXO{maxUTXO}, outpointsSet, domainTx.Outputs[0].Value, false, newFeeRate, fromAddresses)
|
||||
allowUsed := make(map[externalapi.DomainOutpoint]struct{})
|
||||
for outpoint := range outpointsToInputs {
|
||||
allowUsed[outpoint] = struct{}{}
|
||||
}
|
||||
selectedUTXOs, spendValue, changeSompi, err := s.selectUTXOsWithPreselected([]*walletUTXO{maxUTXO}, allowUsed, domainTx.Outputs[0].Value, false, newFeeRate, fromAddresses)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -121,7 +128,7 @@ func (s *server) BumpFee(_ context.Context, request *pb.BumpFeeRequest) (*pb.Bum
|
||||
return nil, err
|
||||
}
|
||||
|
||||
unsignedTransactions, err := s.maybeAutoCompoundTransaction(unsignedTransaction, toAddress, changeAddress, changeWalletAddress, feeRate)
|
||||
unsignedTransactions, err := s.maybeAutoCompoundTransaction(unsignedTransaction, toAddress, changeAddress, changeWalletAddress, newFeeRate)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -164,7 +164,8 @@ func (s *server) selectUTXOsWithPreselected(preSelectedUTXOs []*walletUTXO, allo
|
||||
|
||||
totalValue += utxo.UTXOEntry.Amount()
|
||||
|
||||
fee, err = s.estimateFee(selectedUTXOs, feeRate)
|
||||
// We're overestimating a bit by assuming that any transaction will have a change output
|
||||
fee, err = s.estimateFee(selectedUTXOs, feeRate, true)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
@ -223,23 +224,40 @@ func (s *server) selectUTXOsWithPreselected(preSelectedUTXOs []*walletUTXO, allo
|
||||
return selectedUTXOs, totalReceived, totalValue - totalSpend, nil
|
||||
}
|
||||
|
||||
func (s *server) estimateFee(selectedUTXOs []*libkaspawallet.UTXO, feeRate float64) (uint64, error) {
|
||||
func (s *server) estimateFee(selectedUTXOs []*libkaspawallet.UTXO, feeRate float64, assumeChange bool) (uint64, error) {
|
||||
fakePubKey := [util.PublicKeySize]byte{}
|
||||
fakeAddr, err := util.NewAddressPublicKey(fakePubKey[:], s.params.Prefix)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
mockPayments := []*libkaspawallet.Payment{
|
||||
{
|
||||
Address: fakeAddr,
|
||||
Amount: 1,
|
||||
},
|
||||
{ // We're overestimating a bit by assuming that any transaction will have a change output
|
||||
Address: fakeAddr,
|
||||
Amount: 1,
|
||||
},
|
||||
totalValue := uint64(0)
|
||||
for _, utxo := range selectedUTXOs {
|
||||
totalValue += utxo.UTXOEntry.Amount()
|
||||
}
|
||||
|
||||
// This is an approximation for the distribution of value between the recipient output and the change output.
|
||||
var mockPayments []*libkaspawallet.Payment
|
||||
if assumeChange {
|
||||
mockPayments = []*libkaspawallet.Payment{
|
||||
{
|
||||
Address: fakeAddr,
|
||||
Amount: totalValue * 99 / 100,
|
||||
},
|
||||
{
|
||||
Address: fakeAddr,
|
||||
Amount: totalValue / 100,
|
||||
},
|
||||
}
|
||||
} else {
|
||||
mockPayments = []*libkaspawallet.Payment{
|
||||
{
|
||||
Address: fakeAddr,
|
||||
Amount: totalValue,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
mockTx, err := libkaspawallet.CreateUnsignedTransaction(s.keysFile.ExtendedPublicKeys,
|
||||
s.keysFile.MinimumSignatures,
|
||||
mockPayments, selectedUTXOs)
|
||||
|
@ -69,7 +69,8 @@ func (s *server) mergeTransaction(
|
||||
}
|
||||
totalValue += output.Value
|
||||
}
|
||||
fee, err := s.estimateFee(utxos, feeRate)
|
||||
// We're overestimating a bit by assuming that any transaction will have a change output
|
||||
fee, err := s.estimateFee(utxos, feeRate, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -204,12 +205,15 @@ func (s *server) createSplitTransaction(transaction *serialization.PartiallySign
|
||||
|
||||
totalSompi += selectedUTXOs[i-startIndex].UTXOEntry.Amount()
|
||||
}
|
||||
fee, err := s.estimateFee(selectedUTXOs, feeRate)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
if len(selectedUTXOs) != 0 {
|
||||
fee, err := s.estimateFee(selectedUTXOs, feeRate, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
totalSompi -= fee
|
||||
}
|
||||
|
||||
totalSompi -= fee
|
||||
return libkaspawallet.CreateUnsignedTransaction(s.keysFile.ExtendedPublicKeys,
|
||||
s.keysFile.MinimumSignatures,
|
||||
[]*libkaspawallet.Payment{{
|
||||
|
@ -7,6 +7,7 @@ import (
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/constants"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/subnetworks"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/txscript"
|
||||
"github.com/kaspanet/kaspad/domain/consensus/utils/utxo"
|
||||
"github.com/kaspanet/kaspad/util"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
@ -242,6 +243,12 @@ func ExtractTransactionDeserialized(partiallySignedTransaction *serialization.Pa
|
||||
}
|
||||
partiallySignedTransaction.Tx.Inputs[i].SignatureScript = sigScript
|
||||
}
|
||||
partiallySignedTransaction.Tx.Inputs[i].UTXOEntry = utxo.NewUTXOEntry(
|
||||
input.PrevOutput.Value,
|
||||
input.PrevOutput.ScriptPublicKey,
|
||||
false, // This is a fake value
|
||||
0, // This is a fake value
|
||||
)
|
||||
}
|
||||
return partiallySignedTransaction.Tx, nil
|
||||
}
|
||||
|
@ -60,11 +60,20 @@ func (x *SubmitTransactionReplacementResponseMessage) toAppMessage() (appmessage
|
||||
if x == nil {
|
||||
return nil, errors.Wrapf(errorNil, "SubmitTransactionReplacementResponseMessage is nil")
|
||||
}
|
||||
rpcErr, err := x.Error.toAppMessage()
|
||||
// Error is an optional field
|
||||
if err != nil && !errors.Is(err, errorNil) {
|
||||
return nil, err
|
||||
|
||||
if x.Error != nil {
|
||||
rpcErr, err := x.Error.toAppMessage()
|
||||
// Error is an optional field
|
||||
if err != nil && !errors.Is(err, errorNil) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &appmessage.SubmitTransactionReplacementResponseMessage{
|
||||
TransactionID: x.TransactionId,
|
||||
Error: rpcErr,
|
||||
}, nil
|
||||
}
|
||||
|
||||
replacedTx, err := x.ReplacedTransaction.toAppMessage()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -72,6 +81,5 @@ func (x *SubmitTransactionReplacementResponseMessage) toAppMessage() (appmessage
|
||||
return &appmessage.SubmitTransactionReplacementResponseMessage{
|
||||
TransactionID: x.TransactionId,
|
||||
ReplacedTransaction: replacedTx,
|
||||
Error: rpcErr,
|
||||
}, nil
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user