Skip to content

Commit

Permalink
feat(SPV-1398): rename UserUTXO struct. Remove unneeded code.
Browse files Browse the repository at this point in the history
  • Loading branch information
dorzepowski committed Jan 20, 2025
1 parent e9b1903 commit 6cd966e
Show file tree
Hide file tree
Showing 12 changed files with 35 additions and 95 deletions.
2 changes: 1 addition & 1 deletion engine/database/models.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ func Models() []any {
User{},
Paymail{},
Address{},
UsersUTXO{},
UserUTXO{},
Operation{},
}
}
2 changes: 1 addition & 1 deletion engine/database/repository/users.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ func (u *Users) GetBalance(ctx context.Context, userID string, bucket string) (b
var balance bsv.Satoshis
err := u.db.
WithContext(ctx).
Model(&database.UsersUTXO{}).
Model(&database.UserUTXO{}).
Where("user_id = ? AND bucket = ?", userID, bucket).
Select("COALESCE(SUM(satoshis), 0)").
Row().
Expand Down
2 changes: 1 addition & 1 deletion engine/database/testabilities/fixture_database.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ type UserUtxoFixture interface {
// WithSatoshis sets the satoshis value of the UTXO.
WithSatoshis(satoshis bsv.Satoshis) UserUtxoFixture

Storable[database.UsersUTXO]
Storable[database.UserUTXO]
}

type Storable[Data any] interface {
Expand Down
4 changes: 2 additions & 2 deletions engine/database/testabilities/user_utxo_fixture.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,8 @@ func (f *userUtxoFixture) WithSatoshis(satoshis bsv.Satoshis) UserUtxoFixture {
return f
}

func (f *userUtxoFixture) Stored() *database.UsersUTXO {
utxo := &database.UsersUTXO{
func (f *userUtxoFixture) Stored() *database.UserUTXO {
utxo := &database.UserUTXO{
UserID: f.userID,
TxID: f.txID,
Vout: f.vout,
Expand Down
6 changes: 3 additions & 3 deletions engine/database/tracked_transaction.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ type TrackedTransaction struct {
Inputs []*TrackedOutput `gorm:"foreignKey:SpendingTX"`
Outputs []*TrackedOutput `gorm:"foreignKey:TxID"`

newUTXOs []*UsersUTXO `gorm:"-"`
newUTXOs []*UserUTXO `gorm:"-"`
}

// CreateP2PKHOutput prepares a new P2PKH output and adds it to the transaction.
Expand Down Expand Up @@ -52,7 +52,7 @@ func (t *TrackedTransaction) AddInputs(inputs ...*TrackedOutput) {
func (t *TrackedTransaction) AfterCreate(tx *gorm.DB) error {
// Add new UTXOs
if len(t.newUTXOs) > 0 {
err := tx.Model(&UsersUTXO{}).Create(t.newUTXOs).Error
err := tx.Model(&UserUTXO{}).Create(t.newUTXOs).Error
if err != nil {
return spverrors.Wrapf(err, "failed to save user utxos")
}
Expand All @@ -67,7 +67,7 @@ func (t *TrackedTransaction) AfterCreate(tx *gorm.DB) error {
}
})
if len(spentOutpoints) > 0 {
err := tx.Where("(tx_id, vout) IN ?", spentOutpoints).Delete(&UsersUTXO{}).Error
err := tx.Where("(tx_id, vout) IN ?", spentOutpoints).Delete(&UserUTXO{}).Error
if err != nil {
return spverrors.Wrapf(err, "failed to delete spent utxos")
}
Expand Down
10 changes: 5 additions & 5 deletions engine/database/user_utxos.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ import (
// + 4 bytes nSequence
const EstimatedInputSizeForP2PKH = 148

// UsersUTXO is a table holding user's Unspent Transaction Outputs (UTXOs).
type UsersUTXO struct {
// UserUTXO is a table holding user's Unspent Transaction Outputs (UTXOs).
type UserUTXO struct {
UserID string `gorm:"primaryKey;uniqueIndex:idx_window,sort:asc,priority:1"`
TxID string `gorm:"primaryKey;uniqueIndex:idx_window,sort:asc,priority:4"`
Vout uint32 `gorm:"primaryKey;uniqueIndex:idx_window,sort:asc,priority:5"`
Expand All @@ -30,9 +30,9 @@ type UsersUTXO struct {
CustomInstructions datatypes.JSONSlice[CustomInstruction]
}

// NewP2PKHUserUTXO creates a new UsersUTXO instance for a P2PKH output based on the given output and custom instructions.
func NewP2PKHUserUTXO(output *TrackedOutput, customInstructions datatypes.JSONSlice[CustomInstruction]) *UsersUTXO {
return &UsersUTXO{
// NewP2PKHUserUTXO creates a new UserUTXO instance for a P2PKH output based on the given output and custom instructions.
func NewP2PKHUserUTXO(output *TrackedOutput, customInstructions datatypes.JSONSlice[CustomInstruction]) *UserUTXO {
return &UserUTXO{
UserID: output.UserID,
TxID: output.TxID,
Vout: output.Vout,
Expand Down
60 changes: 0 additions & 60 deletions engine/tester/fixtures/tx_fixtures_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,63 +62,3 @@ func TestMockTXGeneration(t *testing.T) {
})
}
}

func TestSpike(t *testing.T) {

tx4 := GivenTX(t).
WithInput(1000).
WithP2PKHOutput(100).TX()

// tx6 := tx4.InputIdx(0).SourceTransaction

tx1 := GivenTX(t).
WithInputFromUTXO(tx4, 0).
WithP2PKHOutput(1).TX()

for _, input := range tx1.Inputs {
input.UnlockingScriptTemplate = RecipientInternal.P2PKHUnlockingScriptTemplate()
}
err := tx1.Sign()
require.NoError(t, err)

tx5 := GivenTX(t).
WithInput(20).
WithP2PKHOutput(2).
WithP2PKHOutput(2).TX()

// tx7 := tx5.InputIdx(0).SourceTransaction

tx3 := GivenTX(t).
WithInputFromUTXO(tx5, 0).
WithP2PKHOutput(1).TX()
for _, input := range tx3.Inputs {
input.UnlockingScriptTemplate = RecipientInternal.P2PKHUnlockingScriptTemplate()
}
err = tx3.Sign()
require.NoError(t, err)

txn := GivenTX(t).
WithInputFromUTXO(tx5, 1).
WithP2PKHOutput(1).TX()
for _, input := range txn.Inputs {
input.UnlockingScriptTemplate = RecipientInternal.P2PKHUnlockingScriptTemplate()
}
err = txn.Sign()
require.NoError(t, err)

tx2 := GivenTX(t).
WithInput(1000).
WithP2PKHOutput(100).TX()

tx0 := GivenTX(t).
WithInputFromUTXO(tx1, 0).
WithInputFromUTXO(tx2, 0).
WithInputFromUTXO(tx3, 0).
TX()

for i, input := range tx0.Inputs {
verified, err := spv.VerifyScripts(input.SourceTransaction)
require.NoError(t, err, "input %s", i)
require.True(t, verified, "input %s", i)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,12 @@ func (c *inputsQueryComposer) build(db *gorm.DB) *gorm.DB {
utxoWithMinChange := c.searchForMinimalChangeValue(db, utxoWithChange)
selectedOutpoints := c.chooseInputsToCoverOutputsAndFeesAndHaveMinimalChange(db, utxoWithMinChange)

res := db.Model(&database.UsersUTXO{}).Where("(tx_id, vout) in (?)", selectedOutpoints)
res := db.Model(&database.UserUTXO{}).Where("(tx_id, vout) in (?)", selectedOutpoints)
return res
}

func (c *inputsQueryComposer) utxos(db *gorm.DB) *gorm.DB {
return db.Model(&database.UsersUTXO{}).
return db.Model(&database.UserUTXO{}).
Select(
txIdColumn,
voutColumn,
Expand Down
8 changes: 4 additions & 4 deletions engine/transaction/outlines/internal/inputs/selector.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ const voutColumn = "vout"

// Selector is a service that selects inputs for transaction.
type Selector interface {
SelectInputsForTransaction(ctx context.Context, userID string, satoshis bsv.Satoshis, byteSizeOfTxBeforeAddingSelectedInputs uint64) ([]*database.UsersUTXO, error)
SelectInputsForTransaction(ctx context.Context, userID string, satoshis bsv.Satoshis, byteSizeOfTxBeforeAddingSelectedInputs uint64) ([]*database.UserUTXO, error)
}

const (
Expand All @@ -39,7 +39,7 @@ func NewSelector(db *gorm.DB, feeUnit bsv.FeeUnit) Selector {
}
}

func (r *sqlInputsSelector) SelectInputsForTransaction(ctx context.Context, userID string, outputsTotalValue bsv.Satoshis, byteSizeOfTxWithoutInputs uint64) (utxos []*database.UsersUTXO, err error) {
func (r *sqlInputsSelector) SelectInputsForTransaction(ctx context.Context, userID string, outputsTotalValue bsv.Satoshis, byteSizeOfTxWithoutInputs uint64) (utxos []*database.UserUTXO, err error) {
err = r.db.WithContext(ctx).Transaction(func(db *gorm.DB) error {
inputsQuery := r.buildQueryForInputs(db, userID, outputsTotalValue, byteSizeOfTxWithoutInputs)

Expand Down Expand Up @@ -78,10 +78,10 @@ func (r *sqlInputsSelector) buildQueryForInputs(db *gorm.DB, userID string, outp
return composer.build(db)
}

func (r *sqlInputsSelector) buildUpdateTouchedAtQuery(db *gorm.DB, utxos []*database.UsersUTXO) *gorm.DB {
func (r *sqlInputsSelector) buildUpdateTouchedAtQuery(db *gorm.DB, utxos []*database.UserUTXO) *gorm.DB {
outpoints := make([][]any, 0, len(utxos))
for _, utxo := range utxos {
outpoints = append(outpoints, []any{utxo.TxID, utxo.Vout})
}
return db.Model(&database.UsersUTXO{}).Where("(tx_id, vout) in (?)", outpoints)
return db.Model(&database.UserUTXO{}).Where("(tx_id, vout) in (?)", outpoints)
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,13 @@ func ExampleSelector_buildQueryForInputs_sqlite() {

query := db.ToSQL(func(db *gorm.DB) *gorm.DB {
query := selector.buildQueryForInputs(db, "someuserid", 1, 10)
query.Find(&database.UsersUTXO{})
query.Find(&database.UserUTXO{})
return query
})

fmt.Println(query)

// Output: SELECT * FROM `xapi_users_utxos` WHERE (tx_id, vout) in (SELECT tx_id,vout FROM (SELECT tx_id,vout,change,min(case when change >= 0 then change end) over () as min_change FROM (SELECT tx_id,vout,case when remaining_value - fee_no_change_output <= 0 then remaining_value - fee_no_change_output else remaining_value - fee_with_change_output end as change FROM (SELECT `tx_id`,`vout`,sum(satoshis) over (order by touched_at ASC, created_at ASC, tx_id ASC, vout ASC) - 1 as remaining_value,ceil((sum(estimated_input_size) over (order by touched_at ASC, created_at ASC, tx_id ASC, vout ASC) + 10) / cast(1000 as float)) * 1 as fee_no_change_output,ceil((sum(estimated_input_size) over (order by touched_at ASC, created_at ASC, tx_id ASC, vout ASC) + 10 + 34) / cast(1000 as float)) * 1 as fee_with_change_output FROM `xapi_users_utxos` WHERE user_id = "someuserid") as utxo) as utxoWithChange) as utxoWithMinChange WHERE change <= min_change)
// Output: SELECT * FROM `xapi_user_utxos` WHERE (tx_id, vout) in (SELECT tx_id,vout FROM (SELECT tx_id,vout,change,min(case when change >= 0 then change end) over () as min_change FROM (SELECT tx_id,vout,case when remaining_value - fee_no_change_output <= 0 then remaining_value - fee_no_change_output else remaining_value - fee_with_change_output end as change FROM (SELECT `tx_id`,`vout`,sum(satoshis) over (order by touched_at ASC, created_at ASC, tx_id ASC, vout ASC) - 1 as remaining_value,ceil((sum(estimated_input_size) over (order by touched_at ASC, created_at ASC, tx_id ASC, vout ASC) + 10) / cast(1000 as float)) * 1 as fee_no_change_output,ceil((sum(estimated_input_size) over (order by touched_at ASC, created_at ASC, tx_id ASC, vout ASC) + 10 + 34) / cast(1000 as float)) * 1 as fee_with_change_output FROM `xapi_user_utxos` WHERE user_id = "someuserid") as utxo) as utxoWithChange) as utxoWithMinChange WHERE change <= min_change)
}

// ExampleSelector_buildQueryForInputs_postgresql demonstrates what would be the query used to select inputs for a transaction.
Expand All @@ -37,13 +37,13 @@ func ExampleSelector_buildQueryForInputs_postgresql() {

query := db.ToSQL(func(db *gorm.DB) *gorm.DB {
query := selector.buildQueryForInputs(db, "someuserid", 1, 10)
query.Find(&database.UsersUTXO{})
query.Find(&database.UserUTXO{})
return query
})

fmt.Println(query)

// Output: SELECT * FROM "xapi_users_utxos" WHERE (tx_id, vout) in (SELECT tx_id,vout FROM (SELECT tx_id,vout,change,min(case when change >= 0 then change end) over () as min_change FROM (SELECT tx_id,vout,case when remaining_value - fee_no_change_output <= 0 then remaining_value - fee_no_change_output else remaining_value - fee_with_change_output end as change FROM (SELECT "tx_id","vout",sum(satoshis) over (order by touched_at ASC, created_at ASC, tx_id ASC, vout ASC) - 1 as remaining_value,ceil((sum(estimated_input_size) over (order by touched_at ASC, created_at ASC, tx_id ASC, vout ASC) + 10) / cast(1000 as float)) * 1 as fee_no_change_output,ceil((sum(estimated_input_size) over (order by touched_at ASC, created_at ASC, tx_id ASC, vout ASC) + 10 + 34) / cast(1000 as float)) * 1 as fee_with_change_output FROM "xapi_users_utxos" WHERE user_id = 'someuserid') as utxo) as utxoWithChange) as utxoWithMinChange WHERE change <= min_change)
// Output: SELECT * FROM "xapi_user_utxos" WHERE (tx_id, vout) in (SELECT tx_id,vout FROM (SELECT tx_id,vout,change,min(case when change >= 0 then change end) over () as min_change FROM (SELECT tx_id,vout,case when remaining_value - fee_no_change_output <= 0 then remaining_value - fee_no_change_output else remaining_value - fee_with_change_output end as change FROM (SELECT "tx_id","vout",sum(satoshis) over (order by touched_at ASC, created_at ASC, tx_id ASC, vout ASC) - 1 as remaining_value,ceil((sum(estimated_input_size) over (order by touched_at ASC, created_at ASC, tx_id ASC, vout ASC) + 10) / cast(1000 as float)) * 1 as fee_no_change_output,ceil((sum(estimated_input_size) over (order by touched_at ASC, created_at ASC, tx_id ASC, vout ASC) + 10 + 34) / cast(1000 as float)) * 1 as fee_with_change_output FROM "xapi_user_utxos" WHERE user_id = 'someuserid') as utxo) as utxoWithChange) as utxoWithMinChange WHERE change <= min_change)
}

// ExampleSelector_buildUpdateTouchedAtQuery_sqlite demonstrates what would be the SQL statement used to update inputs after selecting them.
Expand All @@ -52,7 +52,7 @@ func ExampleSelector_buildUpdateTouchedAtQuery_sqlite() {

selector := givenInputsSelector(db)

utxos := []*database.UsersUTXO{
utxos := []*database.UserUTXO{
{UserID: "id_of_user_1", TxID: "tx_id_1", Vout: 0, Satoshis: 10, EstimatedInputSize: 148, Bucket: "bsv", CreatedAt: time.Now(), TouchedAt: time.Now()},
{UserID: "id_of_user_1", TxID: "tx_id_1", Vout: 1, Satoshis: 10, EstimatedInputSize: 148, Bucket: "bsv", CreatedAt: time.Now(), TouchedAt: time.Now()},
{UserID: "id_of_user_1", TxID: "tx_id_2", Vout: 0, Satoshis: 10, EstimatedInputSize: 148, Bucket: "bsv", CreatedAt: time.Now(), TouchedAt: time.Now()},
Expand All @@ -66,7 +66,7 @@ func ExampleSelector_buildUpdateTouchedAtQuery_sqlite() {

fmt.Println(query)

// Output: UPDATE `xapi_users_utxos` SET `touched_at`="2006-02-01 15:04:05" WHERE (tx_id, vout) in (("tx_id_1",0),("tx_id_1",1),("tx_id_2",0))
// Output: UPDATE `xapi_user_utxos` SET `touched_at`="2006-02-01 15:04:05" WHERE (tx_id, vout) in (("tx_id_1",0),("tx_id_1",1),("tx_id_2",0))
}

// ExampleSelector_buildUpdateTouchedAtQuery_postgres demonstrates what would be the SQL statement used to update inputs after selecting them.
Expand All @@ -75,7 +75,7 @@ func ExampleSelector_buildUpdateTouchedAtQuery_postgres() {

selector := givenInputsSelector(db)

utxos := []*database.UsersUTXO{
utxos := []*database.UserUTXO{
{UserID: "id_of_user_1", TxID: "tx_id_1", Vout: 0, Satoshis: 10, EstimatedInputSize: 148, Bucket: "bsv", CreatedAt: time.Now(), TouchedAt: time.Now()},
{UserID: "id_of_user_1", TxID: "tx_id_1", Vout: 1, Satoshis: 10, EstimatedInputSize: 148, Bucket: "bsv", CreatedAt: time.Now(), TouchedAt: time.Now()},
{UserID: "id_of_user_1", TxID: "tx_id_2", Vout: 0, Satoshis: 10, EstimatedInputSize: 148, Bucket: "bsv", CreatedAt: time.Now(), TouchedAt: time.Now()},
Expand All @@ -89,7 +89,7 @@ func ExampleSelector_buildUpdateTouchedAtQuery_postgres() {

fmt.Println(query)

// Output: UPDATE "xapi_users_utxos" SET "touched_at"='2006-02-01 15:04:05' WHERE (tx_id, vout) in (('tx_id_1',0),('tx_id_1',1),('tx_id_2',0))
// Output: UPDATE "xapi_user_utxos" SET "touched_at"='2006-02-01 15:04:05' WHERE (tx_id, vout) in (('tx_id_1',0),('tx_id_1',1),('tx_id_2',0))
}

func givenInputsSelector(db *gorm.DB) *sqlInputsSelector {
Expand Down
4 changes: 2 additions & 2 deletions engine/transaction/outlines/internal/inputs/selector_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ func TestInputsSelector(t *testing.T) {
defer cleanup()

// and: having some utxo in database
ownedInputs := []*database.UsersUTXO{
ownedInputs := []*database.UserUTXO{
given.DB().HasUTXO().OwnedBySender().P2PKH().WithSatoshis(10).Stored(),
given.DB().HasUTXO().OwnedBySender().P2PKH().WithSatoshis(10).Stored(),
given.DB().HasUTXO().OwnedBySender().P2PKH().WithSatoshis(10).Stored(),
Expand Down Expand Up @@ -132,7 +132,7 @@ func TestInputsSelector(t *testing.T) {
defer cleanup()

// and: having some utxo in database
ownedInputs := []*database.UsersUTXO{
ownedInputs := []*database.UserUTXO{
given.DB().HasUTXO().OwnedBySender().P2PKH().WithSatoshis(10).Stored(),
given.DB().HasUTXO().OwnedBySender().P2PKH().WithSatoshis(10).Stored(),
given.DB().HasUTXO().OwnedBySender().P2PKH().WithSatoshis(10).Stored(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,12 @@ type InputsSelectorAssertions interface {
}

type SuccessfullySelectedInputsAssertions interface {
SelectedInputs(inputs []*database.UsersUTXO) SelectedInputsAssertions
SelectedInputs(inputs []*database.UserUTXO) SelectedInputsAssertions
}

type SelectedInputsAssertions interface {
AreEmpty()
ComparingTo(inputs []*database.UsersUTXO) ComparingSelectedInputsAssertions
ComparingTo(inputs []*database.UserUTXO) ComparingSelectedInputsAssertions
}

type ComparingSelectedInputsAssertions interface {
Expand All @@ -29,8 +29,8 @@ type assertion struct {
t testing.TB
require *require.Assertions
assert *assert.Assertions
actual []*database.UsersUTXO
comparingSource []*database.UsersUTXO
actual []*database.UserUTXO
comparingSource []*database.UserUTXO
}

func newAssertions(t testing.TB) InputsSelectorAssertions {
Expand All @@ -47,7 +47,7 @@ func (a assertion) WithoutError(err error) SuccessfullySelectedInputsAssertions
return a
}

func (a assertion) SelectedInputs(inputs []*database.UsersUTXO) SelectedInputsAssertions {
func (a assertion) SelectedInputs(inputs []*database.UserUTXO) SelectedInputsAssertions {
a.t.Helper()
a.actual = inputs
return a
Expand All @@ -58,7 +58,7 @@ func (a assertion) AreEmpty() {
a.require.Empty(a.actual)
}

func (a assertion) ComparingTo(inputs []*database.UsersUTXO) ComparingSelectedInputsAssertions {
func (a assertion) ComparingTo(inputs []*database.UserUTXO) ComparingSelectedInputsAssertions {
a.t.Helper()
a.comparingSource = inputs
return a
Expand Down

0 comments on commit 6cd966e

Please sign in to comment.