Merge pull request #943 from Roasbeef/btc-rounding-fix
lnwallet: use btcutil.NewAmount for BTC -> SAT conversions
This commit is contained in:
commit
b49d29c2b0
@ -1255,7 +1255,11 @@ func createInitChannels(revocationWindow int) (*lnwallet.LightningChannel, *lnwa
|
|||||||
bobKeyPriv, bobKeyPub := btcec.PrivKeyFromBytes(btcec.S256(),
|
bobKeyPriv, bobKeyPub := btcec.PrivKeyFromBytes(btcec.S256(),
|
||||||
bobsPrivKey)
|
bobsPrivKey)
|
||||||
|
|
||||||
channelCapacity := btcutil.Amount(10 * 1e8)
|
channelCapacity, err := btcutil.NewAmount(10)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
channelBal := channelCapacity / 2
|
channelBal := channelCapacity / 2
|
||||||
aliceDustLimit := btcutil.Amount(200)
|
aliceDustLimit := btcutil.Amount(200)
|
||||||
bobDustLimit := btcutil.Amount(1300)
|
bobDustLimit := btcutil.Amount(1300)
|
||||||
|
@ -1418,7 +1418,7 @@ func testChannelForceClosure(net *lntest.NetworkHarness, t *harnessTest) {
|
|||||||
t.Fatalf("unable to get carol's balance: %v", err)
|
t.Fatalf("unable to get carol's balance: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
carolStartingBalance := btcutil.Amount(carolBalResp.ConfirmedBalance * 1e8)
|
carolStartingBalance := carolBalResp.ConfirmedBalance
|
||||||
|
|
||||||
ctxt, _ := context.WithTimeout(ctxb, timeout)
|
ctxt, _ := context.WithTimeout(ctxb, timeout)
|
||||||
chanPoint := openChannelAndAssert(ctxt, t, net, net.Alice, carol,
|
chanPoint := openChannelAndAssert(ctxt, t, net, net.Alice, carol,
|
||||||
@ -1965,11 +1965,11 @@ func testChannelForceClosure(net *lntest.NetworkHarness, t *harnessTest) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unable to get carol's balance: %v", err)
|
t.Fatalf("unable to get carol's balance: %v", err)
|
||||||
}
|
}
|
||||||
carolExpectedBalance := carolStartingBalance + pushAmt
|
carolExpectedBalance := btcutil.Amount(carolStartingBalance) + pushAmt
|
||||||
if btcutil.Amount(carolBalResp.ConfirmedBalance*1e8) < carolExpectedBalance {
|
if btcutil.Amount(carolBalResp.ConfirmedBalance) < carolExpectedBalance {
|
||||||
t.Fatalf("carol's balance is incorrect: expected %v got %v",
|
t.Fatalf("carol's balance is incorrect: expected %v got %v",
|
||||||
carolExpectedBalance,
|
carolExpectedBalance,
|
||||||
btcutil.Amount(carolBalResp.ConfirmedBalance*1e8))
|
carolBalResp.ConfirmedBalance)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,6 +7,7 @@ import (
|
|||||||
|
|
||||||
"github.com/roasbeef/btcd/chaincfg/chainhash"
|
"github.com/roasbeef/btcd/chaincfg/chainhash"
|
||||||
"github.com/roasbeef/btcd/wire"
|
"github.com/roasbeef/btcd/wire"
|
||||||
|
"github.com/roasbeef/btcutil"
|
||||||
|
|
||||||
"github.com/lightninglabs/neutrino"
|
"github.com/lightninglabs/neutrino"
|
||||||
"github.com/lightningnetwork/lnd/lnwallet"
|
"github.com/lightningnetwork/lnd/lnwallet"
|
||||||
@ -77,10 +78,15 @@ func (b *BtcWallet) GetUtxo(op *wire.OutPoint, heightHint uint32) (*wire.TxOut,
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We'll ensure we properly convert the amount given in BTC to
|
||||||
|
// satoshis.
|
||||||
|
amt, err := btcutil.NewAmount(txout.Value)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
return &wire.TxOut{
|
return &wire.TxOut{
|
||||||
// Sadly, gettxout returns the output value in BTC
|
Value: int64(amt),
|
||||||
// instead of satoshis.
|
|
||||||
Value: int64(txout.Value * 1e8),
|
|
||||||
PkScript: pkScript,
|
PkScript: pkScript,
|
||||||
}, nil
|
}, nil
|
||||||
|
|
||||||
@ -97,10 +103,15 @@ func (b *BtcWallet) GetUtxo(op *wire.OutPoint, heightHint uint32) (*wire.TxOut,
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Sadly, gettxout returns the output value in BTC instead of
|
||||||
|
// satoshis.
|
||||||
|
amt, err := btcutil.NewAmount(txout.Value)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
return &wire.TxOut{
|
return &wire.TxOut{
|
||||||
// Sadly, gettxout returns the output value in BTC
|
Value: int64(amt),
|
||||||
// instead of satoshis.
|
|
||||||
Value: int64(txout.Value * 1e8),
|
|
||||||
PkScript: pkScript,
|
PkScript: pkScript,
|
||||||
}, nil
|
}, nil
|
||||||
|
|
||||||
|
@ -330,9 +330,16 @@ func (b *BtcWallet) ListUnspentWitness(minConfs int32) ([]*lnwallet.Utxo, error)
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We'll ensure we properly convert the amount given in
|
||||||
|
// BTC to satoshis.
|
||||||
|
amt, err := btcutil.NewAmount(output.Amount)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
utxo := &lnwallet.Utxo{
|
utxo := &lnwallet.Utxo{
|
||||||
AddressType: addressType,
|
AddressType: addressType,
|
||||||
Value: btcutil.Amount(output.Amount * 1e8),
|
Value: amt,
|
||||||
PkScript: pkScript,
|
PkScript: pkScript,
|
||||||
OutPoint: wire.OutPoint{
|
OutPoint: wire.OutPoint{
|
||||||
Hash: *txid,
|
Hash: *txid,
|
||||||
|
@ -163,7 +163,11 @@ func forceStateTransition(chanA, chanB *LightningChannel) error {
|
|||||||
func createTestChannels(revocationWindow int) (*LightningChannel,
|
func createTestChannels(revocationWindow int) (*LightningChannel,
|
||||||
*LightningChannel, func(), error) {
|
*LightningChannel, func(), error) {
|
||||||
|
|
||||||
channelCapacity := btcutil.Amount(10 * 1e8)
|
channelCapacity, err := btcutil.NewAmount(10)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
channelBal := channelCapacity / 2
|
channelBal := channelCapacity / 2
|
||||||
aliceDustLimit := btcutil.Amount(200)
|
aliceDustLimit := btcutil.Amount(200)
|
||||||
bobDustLimit := btcutil.Amount(1300)
|
bobDustLimit := btcutil.Amount(1300)
|
||||||
|
@ -101,12 +101,14 @@ var (
|
|||||||
// assertProperBalance asserts than the total value of the unspent outputs
|
// assertProperBalance asserts than the total value of the unspent outputs
|
||||||
// within the wallet are *exactly* amount. If unable to retrieve the current
|
// within the wallet are *exactly* amount. If unable to retrieve the current
|
||||||
// balance, or the assertion fails, the test will halt with a fatal error.
|
// balance, or the assertion fails, the test will halt with a fatal error.
|
||||||
func assertProperBalance(t *testing.T, lw *lnwallet.LightningWallet, numConfirms int32, amount int64) {
|
func assertProperBalance(t *testing.T, lw *lnwallet.LightningWallet,
|
||||||
|
numConfirms int32, amount float64) {
|
||||||
|
|
||||||
balance, err := lw.ConfirmedBalance(numConfirms)
|
balance, err := lw.ConfirmedBalance(numConfirms)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unable to query for balance: %v", err)
|
t.Fatalf("unable to query for balance: %v", err)
|
||||||
}
|
}
|
||||||
if balance != btcutil.Amount(amount*1e8) {
|
if balance.ToBTC() != amount {
|
||||||
t.Fatalf("wallet credits not properly loaded, should have 40BTC, "+
|
t.Fatalf("wallet credits not properly loaded, should have 40BTC, "+
|
||||||
"instead have %v", balance)
|
"instead have %v", balance)
|
||||||
}
|
}
|
||||||
@ -149,7 +151,7 @@ func calcStaticFee(numHTLCs int) btcutil.Amount {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func loadTestCredits(miner *rpctest.Harness, w *lnwallet.LightningWallet,
|
func loadTestCredits(miner *rpctest.Harness, w *lnwallet.LightningWallet,
|
||||||
numOutputs, btcPerOutput int) error {
|
numOutputs int, btcPerOutput float64) error {
|
||||||
|
|
||||||
// For initial neutrino connection, wait a second.
|
// For initial neutrino connection, wait a second.
|
||||||
// TODO(aakselrod): Eliminate the need for this.
|
// TODO(aakselrod): Eliminate the need for this.
|
||||||
@ -159,12 +161,15 @@ func loadTestCredits(miner *rpctest.Harness, w *lnwallet.LightningWallet,
|
|||||||
}
|
}
|
||||||
// Using the mining node, spend from a coinbase output numOutputs to
|
// Using the mining node, spend from a coinbase output numOutputs to
|
||||||
// give us btcPerOutput with each output.
|
// give us btcPerOutput with each output.
|
||||||
satoshiPerOutput := int64(btcPerOutput * 1e8)
|
satoshiPerOutput, err := btcutil.NewAmount(btcPerOutput)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("unable to create amt: %v", err)
|
||||||
|
}
|
||||||
expectedBalance, err := w.ConfirmedBalance(1)
|
expectedBalance, err := w.ConfirmedBalance(1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
expectedBalance += btcutil.Amount(satoshiPerOutput * int64(numOutputs))
|
expectedBalance += btcutil.Amount(int64(satoshiPerOutput) * int64(numOutputs))
|
||||||
addrs := make([]btcutil.Address, 0, numOutputs)
|
addrs := make([]btcutil.Address, 0, numOutputs)
|
||||||
for i := 0; i < numOutputs; i++ {
|
for i := 0; i < numOutputs; i++ {
|
||||||
// Grab a fresh address from the wallet to house this output.
|
// Grab a fresh address from the wallet to house this output.
|
||||||
@ -181,7 +186,7 @@ func loadTestCredits(miner *rpctest.Harness, w *lnwallet.LightningWallet,
|
|||||||
addrs = append(addrs, walletAddr)
|
addrs = append(addrs, walletAddr)
|
||||||
|
|
||||||
output := &wire.TxOut{
|
output := &wire.TxOut{
|
||||||
Value: satoshiPerOutput,
|
Value: int64(satoshiPerOutput),
|
||||||
PkScript: script,
|
PkScript: script,
|
||||||
}
|
}
|
||||||
if _, err := miner.SendOutputs([]*wire.TxOut{output}, 10); err != nil {
|
if _, err := miner.SendOutputs([]*wire.TxOut{output}, 10); err != nil {
|
||||||
@ -278,7 +283,10 @@ func createTestWallet(tempTestDir string, miningNode *rpctest.Harness,
|
|||||||
func testDualFundingReservationWorkflow(miner *rpctest.Harness,
|
func testDualFundingReservationWorkflow(miner *rpctest.Harness,
|
||||||
alice, bob *lnwallet.LightningWallet, t *testing.T) {
|
alice, bob *lnwallet.LightningWallet, t *testing.T) {
|
||||||
|
|
||||||
const fundingAmount = btcutil.Amount(5 * 1e8)
|
fundingAmount, err := btcutil.NewAmount(5)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unable to create amt: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
// In this scenario, we'll test a dual funder reservation, with each
|
// In this scenario, we'll test a dual funder reservation, with each
|
||||||
// side putting in 10 BTC.
|
// side putting in 10 BTC.
|
||||||
@ -450,7 +458,10 @@ func testFundingTransactionLockedOutputs(miner *rpctest.Harness,
|
|||||||
alice, _ *lnwallet.LightningWallet, t *testing.T) {
|
alice, _ *lnwallet.LightningWallet, t *testing.T) {
|
||||||
|
|
||||||
// Create a single channel asking for 16 BTC total.
|
// Create a single channel asking for 16 BTC total.
|
||||||
fundingAmount := btcutil.Amount(8 * 1e8)
|
fundingAmount, err := btcutil.NewAmount(8)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unable to create amt: %v", err)
|
||||||
|
}
|
||||||
feeRate, err := alice.Cfg.FeeEstimator.EstimateFeePerVSize(1)
|
feeRate, err := alice.Cfg.FeeEstimator.EstimateFeePerVSize(1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unable to query fee estimator: %v", err)
|
t.Fatalf("unable to query fee estimator: %v", err)
|
||||||
@ -467,7 +478,10 @@ func testFundingTransactionLockedOutputs(miner *rpctest.Harness,
|
|||||||
// Now attempt to reserve funds for another channel, this time
|
// Now attempt to reserve funds for another channel, this time
|
||||||
// requesting 900 BTC. We only have around 64BTC worth of outpoints
|
// requesting 900 BTC. We only have around 64BTC worth of outpoints
|
||||||
// that aren't locked, so this should fail.
|
// that aren't locked, so this should fail.
|
||||||
amt := btcutil.Amount(900 * 1e8)
|
amt, err := btcutil.NewAmount(900)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unable to create amt: %v", err)
|
||||||
|
}
|
||||||
failedReservation, err := alice.InitChannelReservation(amt, amt, 0,
|
failedReservation, err := alice.InitChannelReservation(amt, amt, 0,
|
||||||
feePerKw, feeRate, bobPub, bobAddr, chainHash,
|
feePerKw, feeRate, bobPub, bobAddr, chainHash,
|
||||||
lnwire.FFAnnounceChannel)
|
lnwire.FFAnnounceChannel)
|
||||||
@ -492,7 +506,10 @@ func testFundingCancellationNotEnoughFunds(miner *rpctest.Harness,
|
|||||||
feePerKw := feeRate.FeePerKWeight()
|
feePerKw := feeRate.FeePerKWeight()
|
||||||
|
|
||||||
// Create a reservation for 44 BTC.
|
// Create a reservation for 44 BTC.
|
||||||
fundingAmount := btcutil.Amount(44 * 1e8)
|
fundingAmount, err := btcutil.NewAmount(44)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unable to create amt: %v", err)
|
||||||
|
}
|
||||||
chanReservation, err := alice.InitChannelReservation(fundingAmount,
|
chanReservation, err := alice.InitChannelReservation(fundingAmount,
|
||||||
fundingAmount, 0, feePerKw, feeRate, bobPub, bobAddr, chainHash,
|
fundingAmount, 0, feePerKw, feeRate, bobPub, bobAddr, chainHash,
|
||||||
lnwire.FFAnnounceChannel)
|
lnwire.FFAnnounceChannel)
|
||||||
@ -571,10 +588,13 @@ func testReservationInitiatorBalanceBelowDustCancel(miner *rpctest.Harness,
|
|||||||
// We'll attempt to create a new reservation with an extremely high fee
|
// We'll attempt to create a new reservation with an extremely high fee
|
||||||
// rate. This should push our balance into the negative and result in a
|
// rate. This should push our balance into the negative and result in a
|
||||||
// failure to create the reservation.
|
// failure to create the reservation.
|
||||||
fundingAmount := btcutil.Amount(4 * 1e8)
|
fundingAmount, err := btcutil.NewAmount(4)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unable to create amt: %v", err)
|
||||||
|
}
|
||||||
feePerVSize := lnwallet.SatPerVByte(btcutil.SatoshiPerBitcoin * 4 / 100)
|
feePerVSize := lnwallet.SatPerVByte(btcutil.SatoshiPerBitcoin * 4 / 100)
|
||||||
feePerKw := feePerVSize.FeePerKWeight()
|
feePerKw := feePerVSize.FeePerKWeight()
|
||||||
_, err := alice.InitChannelReservation(
|
_, err = alice.InitChannelReservation(
|
||||||
fundingAmount, fundingAmount, 0, feePerKw, feePerVSize, bobPub,
|
fundingAmount, fundingAmount, 0, feePerKw, feePerVSize, bobPub,
|
||||||
bobAddr, chainHash, lnwire.FFAnnounceChannel,
|
bobAddr, chainHash, lnwire.FFAnnounceChannel,
|
||||||
)
|
)
|
||||||
@ -638,7 +658,10 @@ func testSingleFunderReservationWorkflow(miner *rpctest.Harness,
|
|||||||
// First, Alice will Initialize a reservation for a channel with 4 BTC
|
// First, Alice will Initialize a reservation for a channel with 4 BTC
|
||||||
// funded solely by us. We'll also initially push 1 BTC of the channel
|
// funded solely by us. We'll also initially push 1 BTC of the channel
|
||||||
// towards Bob's side.
|
// towards Bob's side.
|
||||||
fundingAmt := btcutil.Amount(4 * 1e8)
|
fundingAmt, err := btcutil.NewAmount(4)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unable to create amt: %v", err)
|
||||||
|
}
|
||||||
pushAmt := lnwire.NewMSatFromSatoshis(btcutil.SatoshiPerBitcoin)
|
pushAmt := lnwire.NewMSatFromSatoshis(btcutil.SatoshiPerBitcoin)
|
||||||
feeRate, err := alice.Cfg.FeeEstimator.EstimateFeePerVSize(1)
|
feeRate, err := alice.Cfg.FeeEstimator.EstimateFeePerVSize(1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
Loading…
Reference in New Issue
Block a user