Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Lease chain fee estimation calculation includes account version #434

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions clientdb/batch.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,8 @@ func (db *DB) StorePendingBatch(batch *order.Batch, orders []order.Nonce,
return err
}

spendingAccountsSnapshot := accounts

var updatedAccounts []*account.Account
for idx, acct := range accounts {
accountKey := getAccountKey(acct)
Expand All @@ -125,10 +127,11 @@ func (db *DB) StorePendingBatch(batch *order.Batch, orders []order.Nonce,
return err
}

// Before we are done, we store a snapshot of the this batch,
// Before we are done, we store a snapshot of the batch,
// so we retain this history for later.
snapshot, err := NewSnapshot(
batch, updatedOrders, updatedAccounts,
batch, updatedOrders, spendingAccountsSnapshot,
updatedAccounts,
)
if err != nil {
return err
Expand Down
36 changes: 27 additions & 9 deletions clientdb/batch_snapshot.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,14 @@ type LocalBatchSnapshot struct {
// the batch transaction.
BatchTxFeeRate chainfee.SatPerKWeight

// spendingAccountsSnapshot is a snapshot of the local accounts that
// participated in this batch before any potential account updates were
// applied.
//
// NOTE: this field is used for estimating on-chains fee using the
// account version.
SpendingAccountsSnapshot map[[33]byte]*account.Account

// Account holds snapshots of the ending state of the local accounts
// that participated in this batch.
Accounts map[[33]byte]*account.Account
Expand All @@ -97,6 +105,7 @@ type LocalBatchSnapshot struct {

// NewSnapshot creates a new LocalBatchSnapshot from the passed order batched.
func NewSnapshot(batch *order.Batch, ourOrders []order.Order,
spendingAccountsSnapshot []*account.Account,
accounts []*account.Account) (*LocalBatchSnapshot, error) {

// We only support LinearFeeSchedule at this point (because of
Expand All @@ -107,6 +116,14 @@ func NewSnapshot(batch *order.Batch, ourOrders []order.Order,
batch.ExecutionFee)
}

// Reformulate account data structure into a map keyed on trader key.
spendingAccsSnapshot := make(map[[33]byte]*account.Account)
for _, a := range accounts {
var key [33]byte
copy(key[:], a.TraderKey.PubKey.SerializeCompressed())
spendingAccsSnapshot[key] = a
}

as := make(map[[33]byte]*account.Account)
for _, a := range accounts {
var key [33]byte
Expand All @@ -120,15 +137,16 @@ func NewSnapshot(batch *order.Batch, ourOrders []order.Order,
}

snapshot := &LocalBatchSnapshot{
Version: batch.Version,
BatchID: batch.ID,
ClearingPrices: batch.ClearingPrices,
ExecutionFee: *feeSched,
BatchTX: batch.BatchTX,
BatchTxFeeRate: batch.BatchTxFeeRate,
Accounts: as,
Orders: os,
MatchedOrders: batch.MatchedOrders,
Version: batch.Version,
BatchID: batch.ID,
ClearingPrices: batch.ClearingPrices,
ExecutionFee: *feeSched,
BatchTX: batch.BatchTX,
BatchTxFeeRate: batch.BatchTxFeeRate,
SpendingAccountsSnapshot: spendingAccsSnapshot,
Accounts: as,
Orders: os,
MatchedOrders: batch.MatchedOrders,
}

return snapshot, nil
Expand Down
55 changes: 38 additions & 17 deletions rpcserver.go
Original file line number Diff line number Diff line change
Expand Up @@ -2261,9 +2261,13 @@ func (s *rpcServer) prepareLeasesResponse(ctx context.Context,
totalAmtPaid btcutil.Amount
)
for _, batch := range batches {
// Keep a tally of how many channels were created within each
// batch in order to estimate the chain fees paid.
numChans := 0
// Keep a tally of the total number of channels which were
// created within each batch in order to estimate the chain fees
// paid.
totalNumChannels := 0

// Keep a tally of the total number of channels per account key.
accountChannelsCount := make(map[[33]byte]uint32)

// Keep track of the index for the first lease found for this
// batch. We'll use this to know where to start from when
Expand All @@ -2281,7 +2285,8 @@ func (s *rpcServer) prepareLeasesResponse(ctx context.Context,
}

// Filter out the account if required.
_, ok = accounts[ourOrder.Details().AcctKey]
accountKey := ourOrder.Details().AcctKey
_, ok = accounts[accountKey]
if len(accounts) != 0 && !ok {
continue
}
Expand Down Expand Up @@ -2415,28 +2420,44 @@ func (s *rpcServer) prepareLeasesResponse(ctx context.Context,
SidecarChannel: isSidecarChannel,
})

numChans++
// Count the total number of channels.
totalNumChannels++

// Count the total number of channels per
// account.
accountChannelsCount[accountKey]++
}

// Estimate the chain fees paid for the number of
// channels created in this batch and tally them.
//
// TODO(guggero): This is just an approximation! We
// should properly calculate the fees _per account_ as
// that's what we do on the server side. Then we can
// also take a look at the actual account version at the
// time of the batch.
chainFee := order.EstimateTraderFee(
uint32(numChans), batch.BatchTxFeeRate,
account.VersionInitialNoVersion,
)
chainFee := btcutil.Amount(0)
for accountKey, numChannels := range accountChannelsCount {
// Calculate and sum the account specific chain
// fee estimate.
//
// The account version influences the chain fee.
// It is important to use the account version
// that was used when the batch was created.
// Accounts might be updated within the batch.
// Therefore, we query the account version from
// an account spending snapshot.
spendingAcctSnapshot :=
batch.SpendingAccountsSnapshot[accountKey]

chainFee += order.EstimateTraderFee(
numChannels, batch.BatchTxFeeRate,
spendingAcctSnapshot.Version,
)
}

// We'll need to compute the chain fee paid for each
// lease. Since multiple leases can be created within a
// batch, we'll need to evenly distribute. We'll always
// apply the remainder to the first lease in the batch.
chainFeePerChan := chainFee / btcutil.Amount(numChans)
chainFeePerChanRem := chainFee % btcutil.Amount(numChans)
chainFeePerChan :=
chainFee / btcutil.Amount(totalNumChannels)
chainFeePerChanRem :=
chainFee % btcutil.Amount(totalNumChannels)
for i := firstIdxForBatch; i < len(rpcLeases); i++ {
chainFee := chainFeePerChan
if i == firstIdxForBatch {
Expand Down