Merge remote-tracking branch 'origin/feat/brc20-module' into feature/brc20-module-api

This commit is contained in:
Gaze
2024-06-11 14:35:47 +07:00
9 changed files with 205 additions and 121 deletions

View File

@@ -26,6 +26,19 @@ http_server:
# Meta-protocol modules configuration options.
modules:
# Configuration options for BRC20 module. Can be removed if not used.
brc20:
database: "postgres" # Database to store BRC20 data. current supported databases: "postgres"
datasource: "database" # Data source to be used for Bitcoin data. current supported data sources: "bitcoin-node".
api_handlers: # API handlers to enable. current supported handlers: "http"
- http
postgres:
host: "localhost"
port: 5432
user: "postgres"
password: "password"
db_name: "postgres"
# url: "postgres://postgres:password@localhost:5432/postgres?sslmode=prefer" # [Optional] This will override other database credentials above.
# Configuration options for Runes module. Can be removed if not used.
runes:
database: "postgres" # Database to store Runes data. current supported databases: "postgres"

View File

@@ -167,6 +167,8 @@ CREATE TABLE IF NOT EXISTS "brc20_inscription_entry_states" (
CREATE TABLE IF NOT EXISTS "brc20_inscription_transfers" (
"inscription_id" TEXT NOT NULL,
"inscription_number" BIGINT NOT NULL,
"inscription_sequence_number" BIGINT NOT NULL,
"block_height" INT NOT NULL,
"tx_index" INT NOT NULL,
"tx_hash" TEXT NOT NULL,

View File

@@ -209,19 +209,19 @@ INSERT INTO "brc20_inscription_entries" ("id", "number", "sequence_number", "del
INSERT INTO "brc20_inscription_entry_states" ("id", "block_height", "transfer_count") VALUES ($1, $2, $3);
-- name: CreateInscriptionTransfers :batchexec
INSERT INTO "brc20_inscription_transfers" ("inscription_id", "block_height", "tx_index", "tx_hash", "from_input_index", "old_satpoint_tx_hash", "old_satpoint_out_idx", "old_satpoint_offset", "new_satpoint_tx_hash", "new_satpoint_out_idx", "new_satpoint_offset", "new_pkscript", "new_output_value", "sent_as_fee", "transfer_count") VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15);
INSERT INTO "brc20_inscription_transfers" ("inscription_id", "inscription_number", "inscription_sequence_number", "block_height", "tx_index", "tx_hash", "from_input_index", "old_satpoint_tx_hash", "old_satpoint_out_idx", "old_satpoint_offset", "new_satpoint_tx_hash", "new_satpoint_out_idx", "new_satpoint_offset", "new_pkscript", "new_output_value", "sent_as_fee", "transfer_count") VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17);
-- name: CreateEventDeploys :batchexec
INSERT INTO "brc20_event_deploys" ("inscription_id", "inscription_number", "tick", "original_tick", "tx_hash", "block_height", "tx_index", "timestamp", "pkscript", "satpoint", "total_supply", "decimals", "limit_per_mint", "is_self_mint") VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14);
INSERT INTO "brc20_event_deploys" ("id", "inscription_id", "inscription_number", "tick", "original_tick", "tx_hash", "block_height", "tx_index", "timestamp", "pkscript", "satpoint", "total_supply", "decimals", "limit_per_mint", "is_self_mint") VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15);
-- name: CreateEventMints :batchexec
INSERT INTO "brc20_event_mints" ("inscription_id", "inscription_number", "tick", "original_tick", "tx_hash", "block_height", "tx_index", "timestamp", "pkscript", "satpoint", "amount", "parent_id") VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12);
INSERT INTO "brc20_event_mints" ("id", "inscription_id", "inscription_number", "tick", "original_tick", "tx_hash", "block_height", "tx_index", "timestamp", "pkscript", "satpoint", "amount", "parent_id") VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13);
-- name: CreateEventInscribeTransfers :batchexec
INSERT INTO "brc20_event_inscribe_transfers" ("inscription_id", "inscription_number", "tick", "original_tick", "tx_hash", "block_height", "tx_index", "timestamp", "pkscript", "satpoint", "output_index", "sats_amount", "amount") VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13);
INSERT INTO "brc20_event_inscribe_transfers" ("id", "inscription_id", "inscription_number", "tick", "original_tick", "tx_hash", "block_height", "tx_index", "timestamp", "pkscript", "satpoint", "output_index", "sats_amount", "amount") VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14);
-- name: CreateEventTransferTransfers :batchexec
INSERT INTO "brc20_event_transfer_transfers" ("inscription_id", "inscription_number", "tick", "original_tick", "tx_hash", "block_height", "tx_index", "timestamp", "from_pkscript", "from_satpoint", "from_input_index", "to_pkscript", "to_satpoint", "to_output_index", "spent_as_fee", "amount") VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16);
INSERT INTO "brc20_event_transfer_transfers" ("id", "inscription_id", "inscription_number", "tick", "original_tick", "tx_hash", "block_height", "tx_index", "timestamp", "from_pkscript", "from_satpoint", "from_input_index", "to_pkscript", "to_satpoint", "to_output_index", "spent_as_fee", "amount") VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17);
-- name: CreateBalances :batchexec
INSERT INTO "brc20_balances" ("pkscript", "block_height", "tick", "overall_balance", "available_balance") VALUES ($1, $2, $3, $4, $5);

View File

@@ -7,6 +7,8 @@ import (
type InscriptionTransfer struct {
InscriptionId ordinals.InscriptionId
InscriptionNumber int64
InscriptionSequenceNumber uint64
BlockHeight uint64
TxIndex uint32
TxHash chainhash.Hash

View File

@@ -73,7 +73,7 @@ func (b *CreateBalancesBatchResults) Close() error {
}
const createEventDeploys = `-- name: CreateEventDeploys :batchexec
INSERT INTO "brc20_event_deploys" ("inscription_id", "inscription_number", "tick", "original_tick", "tx_hash", "block_height", "tx_index", "timestamp", "pkscript", "satpoint", "total_supply", "decimals", "limit_per_mint", "is_self_mint") VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14)
INSERT INTO "brc20_event_deploys" ("id", "inscription_id", "inscription_number", "tick", "original_tick", "tx_hash", "block_height", "tx_index", "timestamp", "pkscript", "satpoint", "total_supply", "decimals", "limit_per_mint", "is_self_mint") VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15)
`
type CreateEventDeploysBatchResults struct {
@@ -83,6 +83,7 @@ type CreateEventDeploysBatchResults struct {
}
type CreateEventDeploysParams struct {
Id int64
InscriptionID string
InscriptionNumber int64
Tick string
@@ -103,6 +104,7 @@ func (q *Queries) CreateEventDeploys(ctx context.Context, arg []CreateEventDeplo
batch := &pgx.Batch{}
for _, a := range arg {
vals := []interface{}{
a.Id,
a.InscriptionID,
a.InscriptionNumber,
a.Tick,
@@ -146,7 +148,7 @@ func (b *CreateEventDeploysBatchResults) Close() error {
}
const createEventInscribeTransfers = `-- name: CreateEventInscribeTransfers :batchexec
INSERT INTO "brc20_event_inscribe_transfers" ("inscription_id", "inscription_number", "tick", "original_tick", "tx_hash", "block_height", "tx_index", "timestamp", "pkscript", "satpoint", "output_index", "sats_amount", "amount") VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13)
INSERT INTO "brc20_event_inscribe_transfers" ("id", "inscription_id", "inscription_number", "tick", "original_tick", "tx_hash", "block_height", "tx_index", "timestamp", "pkscript", "satpoint", "output_index", "sats_amount", "amount") VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14)
`
type CreateEventInscribeTransfersBatchResults struct {
@@ -156,6 +158,7 @@ type CreateEventInscribeTransfersBatchResults struct {
}
type CreateEventInscribeTransfersParams struct {
Id int64
InscriptionID string
InscriptionNumber int64
Tick string
@@ -175,6 +178,7 @@ func (q *Queries) CreateEventInscribeTransfers(ctx context.Context, arg []Create
batch := &pgx.Batch{}
for _, a := range arg {
vals := []interface{}{
a.Id,
a.InscriptionID,
a.InscriptionNumber,
a.Tick,
@@ -217,7 +221,7 @@ func (b *CreateEventInscribeTransfersBatchResults) Close() error {
}
const createEventMints = `-- name: CreateEventMints :batchexec
INSERT INTO "brc20_event_mints" ("inscription_id", "inscription_number", "tick", "original_tick", "tx_hash", "block_height", "tx_index", "timestamp", "pkscript", "satpoint", "amount", "parent_id") VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12)
INSERT INTO "brc20_event_mints" ("id", "inscription_id", "inscription_number", "tick", "original_tick", "tx_hash", "block_height", "tx_index", "timestamp", "pkscript", "satpoint", "amount", "parent_id") VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13)
`
type CreateEventMintsBatchResults struct {
@@ -227,6 +231,7 @@ type CreateEventMintsBatchResults struct {
}
type CreateEventMintsParams struct {
Id int64
InscriptionID string
InscriptionNumber int64
Tick string
@@ -245,6 +250,7 @@ func (q *Queries) CreateEventMints(ctx context.Context, arg []CreateEventMintsPa
batch := &pgx.Batch{}
for _, a := range arg {
vals := []interface{}{
a.Id,
a.InscriptionID,
a.InscriptionNumber,
a.Tick,
@@ -286,7 +292,7 @@ func (b *CreateEventMintsBatchResults) Close() error {
}
const createEventTransferTransfers = `-- name: CreateEventTransferTransfers :batchexec
INSERT INTO "brc20_event_transfer_transfers" ("inscription_id", "inscription_number", "tick", "original_tick", "tx_hash", "block_height", "tx_index", "timestamp", "from_pkscript", "from_satpoint", "from_input_index", "to_pkscript", "to_satpoint", "to_output_index", "spent_as_fee", "amount") VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16)
INSERT INTO "brc20_event_transfer_transfers" ("id", "inscription_id", "inscription_number", "tick", "original_tick", "tx_hash", "block_height", "tx_index", "timestamp", "from_pkscript", "from_satpoint", "from_input_index", "to_pkscript", "to_satpoint", "to_output_index", "spent_as_fee", "amount") VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17)
`
type CreateEventTransferTransfersBatchResults struct {
@@ -296,6 +302,7 @@ type CreateEventTransferTransfersBatchResults struct {
}
type CreateEventTransferTransfersParams struct {
Id int64
InscriptionID string
InscriptionNumber int64
Tick string
@@ -318,6 +325,7 @@ func (q *Queries) CreateEventTransferTransfers(ctx context.Context, arg []Create
batch := &pgx.Batch{}
for _, a := range arg {
vals := []interface{}{
a.Id,
a.InscriptionID,
a.InscriptionNumber,
a.Tick,
@@ -489,7 +497,7 @@ func (b *CreateInscriptionEntryStatesBatchResults) Close() error {
}
const createInscriptionTransfers = `-- name: CreateInscriptionTransfers :batchexec
INSERT INTO "brc20_inscription_transfers" ("inscription_id", "block_height", "tx_index", "tx_hash", "from_input_index", "old_satpoint_tx_hash", "old_satpoint_out_idx", "old_satpoint_offset", "new_satpoint_tx_hash", "new_satpoint_out_idx", "new_satpoint_offset", "new_pkscript", "new_output_value", "sent_as_fee", "transfer_count") VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15)
INSERT INTO "brc20_inscription_transfers" ("inscription_id", "inscription_number", "inscription_sequence_number", "block_height", "tx_index", "tx_hash", "from_input_index", "old_satpoint_tx_hash", "old_satpoint_out_idx", "old_satpoint_offset", "new_satpoint_tx_hash", "new_satpoint_out_idx", "new_satpoint_offset", "new_pkscript", "new_output_value", "sent_as_fee", "transfer_count") VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17)
`
type CreateInscriptionTransfersBatchResults struct {
@@ -500,6 +508,8 @@ type CreateInscriptionTransfersBatchResults struct {
type CreateInscriptionTransfersParams struct {
InscriptionID string
InscriptionNumber int64
InscriptionSequenceNumber int64
BlockHeight int32
TxIndex int32
TxHash string
@@ -521,6 +531,8 @@ func (q *Queries) CreateInscriptionTransfers(ctx context.Context, arg []CreateIn
for _, a := range arg {
vals := []interface{}{
a.InscriptionID,
a.InscriptionNumber,
a.InscriptionSequenceNumber,
a.BlockHeight,
a.TxIndex,
a.TxHash,

View File

@@ -656,7 +656,7 @@ func (q *Queries) GetInscriptionParentsByIds(ctx context.Context, inscriptionIds
}
const getInscriptionTransfersInOutPoints = `-- name: GetInscriptionTransfersInOutPoints :many
SELECT it.inscription_id, it.block_height, it.tx_index, it.tx_hash, it.from_input_index, it.old_satpoint_tx_hash, it.old_satpoint_out_idx, it.old_satpoint_offset, it.new_satpoint_tx_hash, it.new_satpoint_out_idx, it.new_satpoint_offset, it.new_pkscript, it.new_output_value, it.sent_as_fee, it.transfer_count, "ie"."content" FROM (
SELECT it.inscription_id, it.inscription_number, it.inscription_sequence_number, it.block_height, it.tx_index, it.tx_hash, it.from_input_index, it.old_satpoint_tx_hash, it.old_satpoint_out_idx, it.old_satpoint_offset, it.new_satpoint_tx_hash, it.new_satpoint_out_idx, it.new_satpoint_offset, it.new_pkscript, it.new_output_value, it.sent_as_fee, it.transfer_count, "ie"."content" FROM (
SELECT
unnest($1::text[]) AS "tx_hash",
unnest($2::int[]) AS "tx_out_idx"
@@ -672,6 +672,8 @@ type GetInscriptionTransfersInOutPointsParams struct {
type GetInscriptionTransfersInOutPointsRow struct {
InscriptionID string
InscriptionNumber int64
InscriptionSequenceNumber int64
BlockHeight int32
TxIndex int32
TxHash string
@@ -700,6 +702,8 @@ func (q *Queries) GetInscriptionTransfersInOutPoints(ctx context.Context, arg Ge
var i GetInscriptionTransfersInOutPointsRow
if err := rows.Scan(
&i.InscriptionID,
&i.InscriptionNumber,
&i.InscriptionSequenceNumber,
&i.BlockHeight,
&i.TxIndex,
&i.TxHash,

View File

@@ -129,6 +129,8 @@ type Brc20InscriptionEntryState struct {
type Brc20InscriptionTransfer struct {
InscriptionID string
InscriptionNumber int64
InscriptionSequenceNumber int64
BlockHeight int32
TxIndex int32
TxHash string

View File

@@ -301,6 +301,8 @@ func mapInscriptionTransferModelToType(src gen.GetInscriptionTransfersInOutPoint
return entity.InscriptionTransfer{
InscriptionId: inscriptionId,
InscriptionNumber: src.InscriptionNumber,
InscriptionSequenceNumber: uint64(src.InscriptionSequenceNumber),
BlockHeight: uint64(src.BlockHeight),
TxIndex: uint32(src.TxIndex),
TxHash: *txHash,
@@ -318,6 +320,8 @@ func mapInscriptionTransferModelToType(src gen.GetInscriptionTransfersInOutPoint
func mapInscriptionTransferTypeToParams(src entity.InscriptionTransfer) gen.CreateInscriptionTransfersParams {
return gen.CreateInscriptionTransfersParams{
InscriptionID: src.InscriptionId.String(),
InscriptionNumber: src.InscriptionNumber,
InscriptionSequenceNumber: int64(src.InscriptionSequenceNumber),
BlockHeight: int32(src.BlockHeight),
TxIndex: int32(src.TxIndex),
TxHash: src.TxHash.String(),
@@ -377,6 +381,7 @@ func mapEventDeployTypeToParams(src entity.EventDeploy) (gen.CreateEventDeploysP
timestamp = pgtype.Timestamp{Time: src.Timestamp, Valid: true}
}
return gen.CreateEventDeploysParams{
Id: src.Id,
InscriptionID: src.InscriptionId.String(),
InscriptionNumber: src.InscriptionNumber,
Tick: src.Tick,
@@ -446,6 +451,7 @@ func mapEventMintTypeToParams(src entity.EventMint) (gen.CreateEventMintsParams,
parentId = pgtype.Text{String: src.ParentId.String(), Valid: true}
}
return gen.CreateEventMintsParams{
Id: src.Id,
InscriptionID: src.InscriptionId.String(),
InscriptionNumber: src.InscriptionNumber,
Tick: src.Tick,
@@ -502,6 +508,7 @@ func mapEventInscribeTransferTypeToParams(src entity.EventInscribeTransfer) (gen
timestamp = pgtype.Timestamp{Time: src.Timestamp, Valid: true}
}
return gen.CreateEventInscribeTransfersParams{
Id: src.Id,
InscriptionID: src.InscriptionId.String(),
InscriptionNumber: src.InscriptionNumber,
Tick: src.Tick,
@@ -570,6 +577,7 @@ func mapEventTransferTransferTypeToParams(src entity.EventTransferTransfer) (gen
timestamp = pgtype.Timestamp{Time: src.Timestamp, Valid: true}
}
return gen.CreateEventTransferTransfersParams{
Id: src.Id,
InscriptionID: src.InscriptionId.String(),
InscriptionNumber: src.InscriptionNumber,
Tick: src.Tick,

View File

@@ -46,6 +46,11 @@ func (p *Processor) processInscriptionTx(ctx context.Context, tx *types.Transact
return nil
}
// Ensure outpoint values exists for all inputs. Some tx inputs may not be prefetched if it contains inscriptions transfers from other txs in the same block.
if err := p.ensureOutPointValues(ctx, outpointValues, inputOutPoints); err != nil {
return errors.Wrap(err, "failed to ensure outpoint values")
}
floatingInscriptions := make([]*entity.Flotsam, 0)
totalInputValue := uint64(0)
totalOutputValue := lo.SumBy(tx.TxOut, func(txOut *types.TxOut) uint64 { return uint64(txOut.Value) })
@@ -64,7 +69,10 @@ func (p *Processor) processInscriptionTx(ctx context.Context, tx *types.Transact
Hash: input.PreviousOutTxHash,
Index: input.PreviousOutIndex,
}
inputValue := outpointValues[inputOutPoint]
inputValue, ok := outpointValues[inputOutPoint]
if !ok {
return errors.Wrapf(errs.NotFound, "outpoint value not found for %s", inputOutPoint.String())
}
transfersInOutPoint := transfersInOutPoints[inputOutPoint]
for satPoint, transfers := range transfersInOutPoint {
@@ -293,6 +301,8 @@ func (p *Processor) updateInscriptionLocation(ctx context.Context, newSatPoint o
entry.TransferCount++
transfer := &entity.InscriptionTransfer{
InscriptionId: flotsam.InscriptionId,
InscriptionNumber: entry.Number,
InscriptionSequenceNumber: entry.SequenceNumber,
BlockHeight: uint64(flotsam.Tx.BlockHeight), // use flotsam's tx to track tx that initiated the transfer
TxIndex: flotsam.Tx.Index, // use flotsam's tx to track tx that initiated the transfer
TxHash: flotsam.Tx.TxHash,
@@ -337,6 +347,8 @@ func (p *Processor) updateInscriptionLocation(ctx context.Context, newSatPoint o
}
transfer := &entity.InscriptionTransfer{
InscriptionId: flotsam.InscriptionId,
InscriptionNumber: inscriptionNumber,
InscriptionSequenceNumber: sequenceNumber,
BlockHeight: uint64(flotsam.Tx.BlockHeight), // use flotsam's tx to track tx that initiated the transfer
TxIndex: flotsam.Tx.Index, // use flotsam's tx to track tx that initiated the transfer
TxHash: flotsam.Tx.TxHash,
@@ -374,6 +386,26 @@ func (p *Processor) updateInscriptionLocation(ctx context.Context, newSatPoint o
panic("unreachable")
}
func (p *Processor) ensureOutPointValues(ctx context.Context, outPointValues map[wire.OutPoint]uint64, outPoints []wire.OutPoint) error {
missingOutPoints := make([]wire.OutPoint, 0)
for _, outPoint := range outPoints {
if _, ok := outPointValues[outPoint]; !ok {
missingOutPoints = append(missingOutPoints, outPoint)
}
}
if len(missingOutPoints) == 0 {
return nil
}
missingOutPointValues, err := p.getOutPointValues(ctx, missingOutPoints)
if err != nil {
return errors.Wrap(err, "failed to get outpoint values")
}
for outPoint, value := range missingOutPointValues {
outPointValues[outPoint] = value
}
return nil
}
type brc20Inscription struct {
P string `json:"p"`
}
@@ -456,6 +488,7 @@ func (p *Processor) getOutPointValues(ctx context.Context, outPoints []wire.OutP
}
func (p *Processor) getInscriptionTransfersInOutPoints(ctx context.Context, outPoints []wire.OutPoint) (map[wire.OutPoint]map[ordinals.SatPoint][]*entity.InscriptionTransfer, error) {
outPoints = lo.Uniq(outPoints)
// try to get from flush buffer if exists
result := make(map[wire.OutPoint]map[ordinals.SatPoint][]*entity.InscriptionTransfer)
@@ -487,6 +520,14 @@ func (p *Processor) getInscriptionTransfersInOutPoints(ctx context.Context, outP
}
result[satPoint.OutPoint][satPoint] = append(result[satPoint.OutPoint][satPoint], transferList...)
}
for _, transfersBySatPoint := range result {
for satPoint := range transfersBySatPoint {
// sort all transfers by sequence number
slices.SortFunc(transfersBySatPoint[satPoint], func(i, j *entity.InscriptionTransfer) int {
return int(i.InscriptionSequenceNumber) - int(j.InscriptionSequenceNumber)
})
}
}
return result, nil
}