mirror of
https://github.com/alexgo-io/gaze-indexer.git
synced 2026-04-29 12:15:13 +08:00
feat: prepare unit tests
This commit is contained in:
2
go.mod
2
go.mod
@@ -9,6 +9,7 @@ require (
|
||||
github.com/btcsuite/btcd/btcutil v1.1.5
|
||||
github.com/btcsuite/btcd/chaincfg/chainhash v1.1.0
|
||||
github.com/cockroachdb/errors v1.11.1
|
||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1
|
||||
github.com/gaze-network/uint128 v1.3.0
|
||||
github.com/gofiber/fiber/v2 v2.52.4
|
||||
github.com/golang-migrate/migrate/v4 v4.17.1
|
||||
@@ -37,7 +38,6 @@ require (
|
||||
github.com/cockroachdb/redact v1.1.5 // indirect
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
||||
github.com/decred/dcrd/crypto/blake256 v1.0.0 // indirect
|
||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 // indirect
|
||||
github.com/fsnotify/fsnotify v1.7.0 // indirect
|
||||
github.com/getsentry/sentry-go v0.18.0 // indirect
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
|
||||
2
modules/nodesale/database/postgresql/queries/test.sql
Normal file
2
modules/nodesale/database/postgresql/queries/test.sql
Normal file
@@ -0,0 +1,2 @@
|
||||
-- name: ClearEvents :exec
|
||||
DELETE FROM events;
|
||||
@@ -32,8 +32,8 @@ func (p *Processor) processDelegate(ctx context.Context, qtx gen.Querier, block
|
||||
|
||||
if valid {
|
||||
for _, node := range nodes {
|
||||
ownerAddress := p.pubkeyToAddress(node.OwnerPublicKey)
|
||||
if !bytes.Equal(
|
||||
ownerAddress, err := p.pubkeyToTaprootAddress(node.OwnerPublicKey, event.rawScript)
|
||||
if err != nil || !bytes.Equal(
|
||||
[]byte(ownerAddress.EncodeAddress()),
|
||||
[]byte(event.txAddress.EncodeAddress()),
|
||||
) {
|
||||
@@ -53,7 +53,7 @@ func (p *Processor) processDelegate(ctx context.Context, qtx gen.Querier, block
|
||||
BlockHeight: int32(block.Header.Height),
|
||||
Valid: valid,
|
||||
WalletAddress: event.txAddress.EncodeAddress(),
|
||||
Metadata: []byte{},
|
||||
Metadata: []byte("{}"),
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed to insert event : %w", err)
|
||||
@@ -63,7 +63,7 @@ func (p *Processor) processDelegate(ctx context.Context, qtx gen.Querier, block
|
||||
SaleBlock: int32(event.transaction.BlockHeight),
|
||||
SaleTxIndex: int32(event.transaction.Index),
|
||||
Delegatee: pgtype.Text{
|
||||
String: string(delegate.DelegateePublicKey),
|
||||
String: delegate.DelegateePublicKey,
|
||||
Valid: true,
|
||||
},
|
||||
NodeIds: nodeIds,
|
||||
|
||||
1
modules/nodesale/delegate_test.go
Normal file
1
modules/nodesale/delegate_test.go
Normal file
@@ -0,0 +1 @@
|
||||
package nodesale
|
||||
@@ -15,34 +15,34 @@ import (
|
||||
func (p *Processor) processDeploy(ctx context.Context, qtx gen.Querier, block *types.Block, event nodesaleEvent) error {
|
||||
valid := true
|
||||
deploy := event.eventMessage.Deploy
|
||||
sellerAddr := p.pubkeyToAddress(string(deploy.SellerPublicKey))
|
||||
if !bytes.Equal(
|
||||
sellerAddr, err := p.pubkeyToTaprootAddress(deploy.SellerPublicKey, event.rawScript)
|
||||
if err != nil || !bytes.Equal(
|
||||
[]byte(sellerAddr.EncodeAddress()),
|
||||
[]byte(event.txAddress.EncodeAddress()),
|
||||
) {
|
||||
valid = false
|
||||
}
|
||||
tiers := make([][]byte, len(deploy.Tiers))
|
||||
for _, tier := range deploy.Tiers {
|
||||
for i, tier := range deploy.Tiers {
|
||||
tierJson, err := protojson.Marshal(tier)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed to parse tiers to json : %w", err)
|
||||
}
|
||||
tiers = append(tiers, tierJson)
|
||||
tiers[i] = tierJson
|
||||
}
|
||||
|
||||
err := qtx.AddEvent(ctx, gen.AddEventParams{
|
||||
err = qtx.AddEvent(ctx, gen.AddEventParams{
|
||||
TxHash: event.transaction.TxHash.String(),
|
||||
TxIndex: int32(event.transaction.Index),
|
||||
Action: int32(event.eventMessage.Action),
|
||||
RawMessage: event.rawData,
|
||||
ParsedMessage: event.eventJson,
|
||||
BlockTimestamp: pgtype.Timestamp{Time: block.Header.Timestamp, Valid: true},
|
||||
BlockHash: block.Header.Hash.String(),
|
||||
BlockHeight: int32(block.Header.Height),
|
||||
BlockHash: event.transaction.BlockHash.String(),
|
||||
BlockHeight: int32(event.transaction.BlockHeight),
|
||||
Valid: valid,
|
||||
WalletAddress: event.txAddress.EncodeAddress(),
|
||||
Metadata: []byte{},
|
||||
Metadata: []byte("{}"),
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed to insert event : %w", err)
|
||||
@@ -61,7 +61,7 @@ func (p *Processor) processDeploy(ctx context.Context, qtx gen.Querier, block *t
|
||||
Valid: true,
|
||||
},
|
||||
Tiers: tiers,
|
||||
SellerPublicKey: string(deploy.SellerPublicKey),
|
||||
SellerPublicKey: deploy.SellerPublicKey,
|
||||
MaxPerAddress: int32(deploy.MaxPerAddress),
|
||||
DeployTxHash: event.transaction.TxHash.String(),
|
||||
MaxDiscountPercentage: int32(deploy.MaxDiscountPercentage),
|
||||
|
||||
177
modules/nodesale/deploy_test.go
Normal file
177
modules/nodesale/deploy_test.go
Normal file
@@ -0,0 +1,177 @@
|
||||
package nodesale
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/hex"
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/btcsuite/btcd/btcec/v2"
|
||||
"github.com/btcsuite/btcd/btcec/v2/schnorr"
|
||||
"github.com/btcsuite/btcd/btcutil"
|
||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
||||
"github.com/btcsuite/btcd/txscript"
|
||||
"github.com/decred/dcrd/dcrec/secp256k1/v4"
|
||||
"github.com/gaze-network/indexer-network/common"
|
||||
"github.com/gaze-network/indexer-network/core/types"
|
||||
"github.com/gaze-network/indexer-network/internal/postgres"
|
||||
"github.com/gaze-network/indexer-network/modules/nodesale/protobuf"
|
||||
repository "github.com/gaze-network/indexer-network/modules/nodesale/repository/postgres"
|
||||
"github.com/gaze-network/indexer-network/modules/nodesale/repository/postgres/gen"
|
||||
"github.com/jackc/pgx/v5"
|
||||
"google.golang.org/protobuf/encoding/protojson"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
var p *Processor
|
||||
|
||||
var postgresConf postgres.Config = postgres.Config{
|
||||
User: "postgres",
|
||||
Password: "P@ssw0rd",
|
||||
}
|
||||
|
||||
var qtx gen.Querier
|
||||
|
||||
var ctx context.Context
|
||||
|
||||
var tx pgx.Tx
|
||||
|
||||
var (
|
||||
testBlockHeigh int = 101
|
||||
testTxIndex int = 1
|
||||
)
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
// call flag.Parse() here if TestMain uses flags
|
||||
|
||||
ctx = context.Background()
|
||||
|
||||
db, _ := postgres.NewPool(ctx, postgresConf)
|
||||
|
||||
repo := repository.NewRepository(db)
|
||||
|
||||
p = &Processor{
|
||||
repository: repo,
|
||||
network: common.NetworkMainnet,
|
||||
}
|
||||
repo.Queries.ClearEvents(ctx)
|
||||
|
||||
tx, _ = p.repository.Db.Begin(ctx)
|
||||
qtx = p.repository.WithTx(tx)
|
||||
|
||||
res := m.Run()
|
||||
tx.Commit(ctx)
|
||||
os.Exit(res)
|
||||
}
|
||||
|
||||
func TestDeployInvalid(t *testing.T) {
|
||||
prvKey, _ := btcec.NewPrivateKey()
|
||||
message := &protobuf.NodeSaleEvent{
|
||||
Action: protobuf.Action_ACTION_DEPLOY,
|
||||
Deploy: &protobuf.ActionDeploy{
|
||||
Name: "testdeploy",
|
||||
StartsAt: 100,
|
||||
EndsAt: 200,
|
||||
Tiers: []*protobuf.Tier{
|
||||
{
|
||||
PriceSat: 100,
|
||||
Limit: 5,
|
||||
MaxPerAddress: 100,
|
||||
},
|
||||
{
|
||||
PriceSat: 200,
|
||||
Limit: 5,
|
||||
MaxPerAddress: 100,
|
||||
},
|
||||
},
|
||||
SellerPublicKey: "0102030405",
|
||||
MaxPerAddress: 100,
|
||||
},
|
||||
}
|
||||
|
||||
event, block := assembleTestEvent(prvKey, "0101010101", "0101010101", 0, 0, message)
|
||||
p.processDeploy(ctx, qtx, block, event)
|
||||
}
|
||||
|
||||
func assembleTestEvent(privateKey *secp256k1.PrivateKey, blockHashHex, txHashHex string, blockHeight, txIndex int, message *protobuf.NodeSaleEvent) (nodesaleEvent, *types.Block) {
|
||||
blockHash, _ := chainhash.NewHashFromStr(blockHashHex)
|
||||
txHash, _ := chainhash.NewHashFromStr(txHashHex)
|
||||
|
||||
rawData, _ := proto.Marshal(message)
|
||||
|
||||
builder := txscript.NewScriptBuilder()
|
||||
builder.AddOp(txscript.OP_FALSE)
|
||||
builder.AddOp(txscript.OP_IF)
|
||||
builder.AddData(rawData)
|
||||
builder.AddOp(txscript.OP_ENDIF)
|
||||
script, _ := builder.Script()
|
||||
tapleaf := txscript.NewBaseTapLeaf(script)
|
||||
scriptTree := txscript.AssembleTaprootScriptTree(tapleaf)
|
||||
rootHash := scriptTree.RootNode.TapHash()
|
||||
tapkey := txscript.ComputeTaprootOutputKey(privateKey.PubKey(), rootHash[:])
|
||||
|
||||
addressTaproot, _ := btcutil.NewAddressTaproot(schnorr.SerializePubKey(tapkey), p.network.ChainParams())
|
||||
|
||||
messageJson, _ := protojson.Marshal(message)
|
||||
|
||||
if blockHeight == 0 {
|
||||
blockHeight = testBlockHeigh
|
||||
testBlockHeigh++
|
||||
}
|
||||
if txIndex == 0 {
|
||||
txIndex = testTxIndex
|
||||
testTxIndex++
|
||||
}
|
||||
|
||||
event := nodesaleEvent{
|
||||
transaction: &types.Transaction{
|
||||
BlockHeight: int64(blockHeight),
|
||||
BlockHash: *blockHash,
|
||||
Index: uint32(txIndex),
|
||||
TxHash: *txHash,
|
||||
},
|
||||
rawData: rawData,
|
||||
eventMessage: message,
|
||||
eventJson: messageJson,
|
||||
txAddress: addressTaproot,
|
||||
rawScript: script,
|
||||
}
|
||||
block := &types.Block{
|
||||
Header: types.BlockHeader{
|
||||
Timestamp: time.Now().UTC(),
|
||||
},
|
||||
}
|
||||
return event, block
|
||||
}
|
||||
|
||||
func TestDeployValid(t *testing.T) {
|
||||
privateKey, _ := btcec.NewPrivateKey()
|
||||
pubkeyHex := hex.EncodeToString(privateKey.PubKey().SerializeCompressed())
|
||||
message := &protobuf.NodeSaleEvent{
|
||||
Action: protobuf.Action_ACTION_DEPLOY,
|
||||
Deploy: &protobuf.ActionDeploy{
|
||||
Name: "testdeploy",
|
||||
StartsAt: 100,
|
||||
EndsAt: 200,
|
||||
Tiers: []*protobuf.Tier{
|
||||
{
|
||||
PriceSat: 100,
|
||||
Limit: 5,
|
||||
MaxPerAddress: 100,
|
||||
},
|
||||
{
|
||||
PriceSat: 200,
|
||||
Limit: 5,
|
||||
MaxPerAddress: 100,
|
||||
},
|
||||
},
|
||||
SellerPublicKey: pubkeyHex,
|
||||
MaxPerAddress: 100,
|
||||
MaxDiscountPercentage: 50,
|
||||
},
|
||||
}
|
||||
|
||||
event, block := assembleTestEvent(privateKey, "0202020202", "0202020202", 0, 0, message)
|
||||
p.processDeploy(ctx, qtx, block, event)
|
||||
}
|
||||
@@ -23,7 +23,7 @@ import (
|
||||
)
|
||||
|
||||
type Processor struct {
|
||||
repository repository.Repository
|
||||
repository *repository.Repository
|
||||
nodesaleGenesis int32
|
||||
nodesaleGenesisHash chainhash.Hash
|
||||
btcClient *datasources.BitcoinNodeDatasource
|
||||
@@ -73,10 +73,10 @@ func (p *Processor) Name() string {
|
||||
return "nodesale"
|
||||
}
|
||||
|
||||
func extractNodesaleData(witness [][]byte) ([]byte, bool) {
|
||||
tokenizer, isTapScript := extractTapScript(witness)
|
||||
func extractNodesaleData(witness [][]byte) ([]byte, []byte, bool) {
|
||||
tokenizer, rawScript, isTapScript := extractTapScript(witness)
|
||||
if !isTapScript {
|
||||
return []byte{}, false
|
||||
return []byte{}, []byte{}, false
|
||||
}
|
||||
state := 0
|
||||
for tokenizer.Next() {
|
||||
@@ -103,12 +103,12 @@ func extractNodesaleData(witness [][]byte) ([]byte, bool) {
|
||||
case 3:
|
||||
if tokenizer.Opcode() == txscript.OP_PUSHDATA1 {
|
||||
data := tokenizer.Data()
|
||||
return data, true
|
||||
return data, rawScript, true
|
||||
}
|
||||
state = 0
|
||||
}
|
||||
}
|
||||
return []byte{}, false
|
||||
return []byte{}, []byte{}, false
|
||||
}
|
||||
|
||||
type nodesaleEvent struct {
|
||||
@@ -117,13 +117,14 @@ type nodesaleEvent struct {
|
||||
eventJson []byte
|
||||
txAddress btcutil.Address
|
||||
rawData []byte
|
||||
rawScript []byte
|
||||
}
|
||||
|
||||
func (p *Processor) parseTransactions(ctx context.Context, transactions []*types.Transaction) ([]nodesaleEvent, error) {
|
||||
events := make([]nodesaleEvent, 1)
|
||||
for _, t := range transactions {
|
||||
for _, txIn := range t.TxIn {
|
||||
data, isNodesale := extractNodesaleData(txIn.Witness)
|
||||
data, rawScript, isNodesale := extractNodesaleData(txIn.Witness)
|
||||
if !isNodesale {
|
||||
continue
|
||||
}
|
||||
@@ -162,6 +163,7 @@ func (p *Processor) parseTransactions(ctx context.Context, transactions []*types
|
||||
eventJson: eventJson,
|
||||
txAddress: addresses[0],
|
||||
rawData: data,
|
||||
rawScript: rawScript,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -151,7 +151,7 @@ type ActionDeploy struct {
|
||||
StartsAt uint32 `protobuf:"varint,2,opt,name=startsAt,proto3" json:"startsAt,omitempty"`
|
||||
EndsAt uint32 `protobuf:"varint,3,opt,name=endsAt,proto3" json:"endsAt,omitempty"`
|
||||
Tiers []*Tier `protobuf:"bytes,4,rep,name=tiers,proto3" json:"tiers,omitempty"`
|
||||
SellerPublicKey []byte `protobuf:"bytes,5,opt,name=sellerPublicKey,proto3" json:"sellerPublicKey,omitempty"`
|
||||
SellerPublicKey string `protobuf:"bytes,5,opt,name=sellerPublicKey,proto3" json:"sellerPublicKey,omitempty"`
|
||||
MaxPerAddress uint32 `protobuf:"varint,6,opt,name=maxPerAddress,proto3" json:"maxPerAddress,omitempty"`
|
||||
MaxDiscountPercentage uint32 `protobuf:"varint,7,opt,name=maxDiscountPercentage,proto3" json:"maxDiscountPercentage,omitempty"`
|
||||
}
|
||||
@@ -216,11 +216,11 @@ func (x *ActionDeploy) GetTiers() []*Tier {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *ActionDeploy) GetSellerPublicKey() []byte {
|
||||
func (x *ActionDeploy) GetSellerPublicKey() string {
|
||||
if x != nil {
|
||||
return x.SellerPublicKey
|
||||
}
|
||||
return nil
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *ActionDeploy) GetMaxPerAddress() uint32 {
|
||||
@@ -306,7 +306,7 @@ type ActionPurchase struct {
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Payload *PurchasePayload `protobuf:"bytes,1,opt,name=payload,proto3" json:"payload,omitempty"`
|
||||
SellerSignature []byte `protobuf:"bytes,2,opt,name=sellerSignature,proto3" json:"sellerSignature,omitempty"`
|
||||
SellerSignature string `protobuf:"bytes,2,opt,name=sellerSignature,proto3" json:"sellerSignature,omitempty"`
|
||||
}
|
||||
|
||||
func (x *ActionPurchase) Reset() {
|
||||
@@ -348,11 +348,11 @@ func (x *ActionPurchase) GetPayload() *PurchasePayload {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *ActionPurchase) GetSellerSignature() []byte {
|
||||
func (x *ActionPurchase) GetSellerSignature() string {
|
||||
if x != nil {
|
||||
return x.SellerSignature
|
||||
}
|
||||
return nil
|
||||
return ""
|
||||
}
|
||||
|
||||
type PurchasePayload struct {
|
||||
@@ -361,9 +361,10 @@ type PurchasePayload struct {
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
DeployID *ActionID `protobuf:"bytes,1,opt,name=deployID,proto3" json:"deployID,omitempty"`
|
||||
BuyerPublicKey []byte `protobuf:"bytes,2,opt,name=buyerPublicKey,proto3" json:"buyerPublicKey,omitempty"`
|
||||
BuyerPublicKey string `protobuf:"bytes,2,opt,name=buyerPublicKey,proto3" json:"buyerPublicKey,omitempty"`
|
||||
NodeIDs []uint32 `protobuf:"varint,3,rep,packed,name=nodeIDs,proto3" json:"nodeIDs,omitempty"`
|
||||
TotalAmountSat int64 `protobuf:"varint,4,opt,name=totalAmountSat,proto3" json:"totalAmountSat,omitempty"`
|
||||
TimeOutBlock uint64 `protobuf:"varint,5,opt,name=timeOutBlock,proto3" json:"timeOutBlock,omitempty"`
|
||||
}
|
||||
|
||||
func (x *PurchasePayload) Reset() {
|
||||
@@ -405,11 +406,11 @@ func (x *PurchasePayload) GetDeployID() *ActionID {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *PurchasePayload) GetBuyerPublicKey() []byte {
|
||||
func (x *PurchasePayload) GetBuyerPublicKey() string {
|
||||
if x != nil {
|
||||
return x.BuyerPublicKey
|
||||
}
|
||||
return nil
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *PurchasePayload) GetNodeIDs() []uint32 {
|
||||
@@ -426,6 +427,13 @@ func (x *PurchasePayload) GetTotalAmountSat() int64 {
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *PurchasePayload) GetTimeOutBlock() uint64 {
|
||||
if x != nil {
|
||||
return x.TimeOutBlock
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
type ActionID struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
@@ -486,7 +494,7 @@ type ActionDelegate struct {
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
DelegateePublicKey []byte `protobuf:"bytes,1,opt,name=delegateePublicKey,proto3" json:"delegateePublicKey,omitempty"`
|
||||
DelegateePublicKey string `protobuf:"bytes,1,opt,name=delegateePublicKey,proto3" json:"delegateePublicKey,omitempty"`
|
||||
NodeIDs []uint32 `protobuf:"varint,2,rep,packed,name=nodeIDs,proto3" json:"nodeIDs,omitempty"`
|
||||
DeployID *ActionID `protobuf:"bytes,3,opt,name=deployID,proto3" json:"deployID,omitempty"`
|
||||
}
|
||||
@@ -523,11 +531,11 @@ func (*ActionDelegate) Descriptor() ([]byte, []int) {
|
||||
return file_modules_nodesale_protobuf_nodesale_proto_rawDescGZIP(), []int{6}
|
||||
}
|
||||
|
||||
func (x *ActionDelegate) GetDelegateePublicKey() []byte {
|
||||
func (x *ActionDelegate) GetDelegateePublicKey() string {
|
||||
if x != nil {
|
||||
return x.DelegateePublicKey
|
||||
}
|
||||
return nil
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *ActionDelegate) GetNodeIDs() []uint32 {
|
||||
@@ -576,7 +584,7 @@ var file_modules_nodesale_protobuf_nodesale_proto_rawDesc = []byte{
|
||||
0x72, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x73,
|
||||
0x61, 0x6c, 0x65, 0x2e, 0x54, 0x69, 0x65, 0x72, 0x52, 0x05, 0x74, 0x69, 0x65, 0x72, 0x73, 0x12,
|
||||
0x28, 0x0a, 0x0f, 0x73, 0x65, 0x6c, 0x6c, 0x65, 0x72, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b,
|
||||
0x65, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0f, 0x73, 0x65, 0x6c, 0x6c, 0x65, 0x72,
|
||||
0x65, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x73, 0x65, 0x6c, 0x6c, 0x65, 0x72,
|
||||
0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x24, 0x0a, 0x0d, 0x6d, 0x61, 0x78,
|
||||
0x50, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0d,
|
||||
0x52, 0x0d, 0x6d, 0x61, 0x78, 0x50, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12,
|
||||
@@ -595,41 +603,43 @@ var file_modules_nodesale_protobuf_nodesale_proto_rawDesc = []byte{
|
||||
0x61, 0x6c, 0x65, 0x2e, 0x50, 0x75, 0x72, 0x63, 0x68, 0x61, 0x73, 0x65, 0x50, 0x61, 0x79, 0x6c,
|
||||
0x6f, 0x61, 0x64, 0x52, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x12, 0x28, 0x0a, 0x0f,
|
||||
0x73, 0x65, 0x6c, 0x6c, 0x65, 0x72, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18,
|
||||
0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0f, 0x73, 0x65, 0x6c, 0x6c, 0x65, 0x72, 0x53, 0x69, 0x67,
|
||||
0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x22, 0xab, 0x01, 0x0a, 0x0f, 0x50, 0x75, 0x72, 0x63, 0x68,
|
||||
0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x73, 0x65, 0x6c, 0x6c, 0x65, 0x72, 0x53, 0x69, 0x67,
|
||||
0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x22, 0xcf, 0x01, 0x0a, 0x0f, 0x50, 0x75, 0x72, 0x63, 0x68,
|
||||
0x61, 0x73, 0x65, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x12, 0x2e, 0x0a, 0x08, 0x64, 0x65,
|
||||
0x70, 0x6c, 0x6f, 0x79, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x6e,
|
||||
0x6f, 0x64, 0x65, 0x73, 0x61, 0x6c, 0x65, 0x2e, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44,
|
||||
0x52, 0x08, 0x64, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x49, 0x44, 0x12, 0x26, 0x0a, 0x0e, 0x62, 0x75,
|
||||
0x79, 0x65, 0x72, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01,
|
||||
0x28, 0x0c, 0x52, 0x0e, 0x62, 0x75, 0x79, 0x65, 0x72, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b,
|
||||
0x28, 0x09, 0x52, 0x0e, 0x62, 0x75, 0x79, 0x65, 0x72, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b,
|
||||
0x65, 0x79, 0x12, 0x18, 0x0a, 0x07, 0x6e, 0x6f, 0x64, 0x65, 0x49, 0x44, 0x73, 0x18, 0x03, 0x20,
|
||||
0x03, 0x28, 0x0d, 0x52, 0x07, 0x6e, 0x6f, 0x64, 0x65, 0x49, 0x44, 0x73, 0x12, 0x26, 0x0a, 0x0e,
|
||||
0x74, 0x6f, 0x74, 0x61, 0x6c, 0x41, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x53, 0x61, 0x74, 0x18, 0x04,
|
||||
0x20, 0x01, 0x28, 0x03, 0x52, 0x0e, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x41, 0x6d, 0x6f, 0x75, 0x6e,
|
||||
0x74, 0x53, 0x61, 0x74, 0x22, 0x3a, 0x0a, 0x08, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44,
|
||||
0x12, 0x14, 0x0a, 0x05, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52,
|
||||
0x05, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x12, 0x18, 0x0a, 0x07, 0x74, 0x78, 0x49, 0x6e, 0x64, 0x65,
|
||||
0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x74, 0x78, 0x49, 0x6e, 0x64, 0x65, 0x78,
|
||||
0x22, 0x8a, 0x01, 0x0a, 0x0e, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x44, 0x65, 0x6c, 0x65, 0x67,
|
||||
0x61, 0x74, 0x65, 0x12, 0x2e, 0x0a, 0x12, 0x64, 0x65, 0x6c, 0x65, 0x67, 0x61, 0x74, 0x65, 0x65,
|
||||
0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52,
|
||||
0x12, 0x64, 0x65, 0x6c, 0x65, 0x67, 0x61, 0x74, 0x65, 0x65, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63,
|
||||
0x4b, 0x65, 0x79, 0x12, 0x18, 0x0a, 0x07, 0x6e, 0x6f, 0x64, 0x65, 0x49, 0x44, 0x73, 0x18, 0x02,
|
||||
0x20, 0x03, 0x28, 0x0d, 0x52, 0x07, 0x6e, 0x6f, 0x64, 0x65, 0x49, 0x44, 0x73, 0x12, 0x2e, 0x0a,
|
||||
0x08, 0x64, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x49, 0x44, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32,
|
||||
0x12, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x73, 0x61, 0x6c, 0x65, 0x2e, 0x41, 0x63, 0x74, 0x69, 0x6f,
|
||||
0x6e, 0x49, 0x44, 0x52, 0x08, 0x64, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x49, 0x44, 0x2a, 0x45, 0x0a,
|
||||
0x06, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x11, 0x0a, 0x0d, 0x41, 0x43, 0x54, 0x49, 0x4f,
|
||||
0x4e, 0x5f, 0x44, 0x45, 0x50, 0x4c, 0x4f, 0x59, 0x10, 0x00, 0x12, 0x13, 0x0a, 0x0f, 0x41, 0x43,
|
||||
0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x50, 0x55, 0x52, 0x43, 0x48, 0x41, 0x53, 0x45, 0x10, 0x01, 0x12,
|
||||
0x13, 0x0a, 0x0f, 0x41, 0x43, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x44, 0x45, 0x4c, 0x45, 0x47, 0x41,
|
||||
0x54, 0x45, 0x10, 0x02, 0x42, 0x43, 0x5a, 0x41, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63,
|
||||
0x6f, 0x6d, 0x2f, 0x67, 0x61, 0x7a, 0x65, 0x2d, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x2f,
|
||||
0x69, 0x6e, 0x64, 0x65, 0x78, 0x65, 0x72, 0x2d, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x2f,
|
||||
0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x2f, 0x6e, 0x6f, 0x64, 0x65, 0x73, 0x61, 0x6c, 0x65,
|
||||
0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f,
|
||||
0x33,
|
||||
0x74, 0x53, 0x61, 0x74, 0x12, 0x22, 0x0a, 0x0c, 0x74, 0x69, 0x6d, 0x65, 0x4f, 0x75, 0x74, 0x42,
|
||||
0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0c, 0x74, 0x69, 0x6d, 0x65,
|
||||
0x4f, 0x75, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x22, 0x3a, 0x0a, 0x08, 0x41, 0x63, 0x74, 0x69,
|
||||
0x6f, 0x6e, 0x49, 0x44, 0x12, 0x14, 0x0a, 0x05, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x01, 0x20,
|
||||
0x01, 0x28, 0x04, 0x52, 0x05, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x12, 0x18, 0x0a, 0x07, 0x74, 0x78,
|
||||
0x49, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x74, 0x78, 0x49,
|
||||
0x6e, 0x64, 0x65, 0x78, 0x22, 0x8a, 0x01, 0x0a, 0x0e, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x44,
|
||||
0x65, 0x6c, 0x65, 0x67, 0x61, 0x74, 0x65, 0x12, 0x2e, 0x0a, 0x12, 0x64, 0x65, 0x6c, 0x65, 0x67,
|
||||
0x61, 0x74, 0x65, 0x65, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x18, 0x01, 0x20,
|
||||
0x01, 0x28, 0x09, 0x52, 0x12, 0x64, 0x65, 0x6c, 0x65, 0x67, 0x61, 0x74, 0x65, 0x65, 0x50, 0x75,
|
||||
0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x18, 0x0a, 0x07, 0x6e, 0x6f, 0x64, 0x65, 0x49,
|
||||
0x44, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0d, 0x52, 0x07, 0x6e, 0x6f, 0x64, 0x65, 0x49, 0x44,
|
||||
0x73, 0x12, 0x2e, 0x0a, 0x08, 0x64, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x49, 0x44, 0x18, 0x03, 0x20,
|
||||
0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x73, 0x61, 0x6c, 0x65, 0x2e, 0x41,
|
||||
0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x52, 0x08, 0x64, 0x65, 0x70, 0x6c, 0x6f, 0x79, 0x49,
|
||||
0x44, 0x2a, 0x45, 0x0a, 0x06, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x11, 0x0a, 0x0d, 0x41,
|
||||
0x43, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x44, 0x45, 0x50, 0x4c, 0x4f, 0x59, 0x10, 0x00, 0x12, 0x13,
|
||||
0x0a, 0x0f, 0x41, 0x43, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x50, 0x55, 0x52, 0x43, 0x48, 0x41, 0x53,
|
||||
0x45, 0x10, 0x01, 0x12, 0x13, 0x0a, 0x0f, 0x41, 0x43, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x44, 0x45,
|
||||
0x4c, 0x45, 0x47, 0x41, 0x54, 0x45, 0x10, 0x02, 0x42, 0x43, 0x5a, 0x41, 0x67, 0x69, 0x74, 0x68,
|
||||
0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x61, 0x7a, 0x65, 0x2d, 0x6e, 0x65, 0x74, 0x77,
|
||||
0x6f, 0x72, 0x6b, 0x2f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x65, 0x72, 0x2d, 0x6e, 0x65, 0x74, 0x77,
|
||||
0x6f, 0x72, 0x6b, 0x2f, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x2f, 0x6e, 0x6f, 0x64, 0x65,
|
||||
0x73, 0x61, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x62, 0x06, 0x70,
|
||||
0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
}
|
||||
|
||||
var (
|
||||
|
||||
@@ -23,9 +23,9 @@ message ActionDeploy {
|
||||
uint32 startsAt = 2;
|
||||
uint32 endsAt = 3;
|
||||
repeated Tier tiers = 4;
|
||||
bytes sellerPublicKey = 5;
|
||||
string sellerPublicKey = 5;
|
||||
uint32 maxPerAddress = 6;
|
||||
uint32 maxDiscountPercentage = 7;
|
||||
uint32 maxDiscountPercentage = 7;
|
||||
}
|
||||
|
||||
message Tier {
|
||||
@@ -36,14 +36,15 @@ message Tier {
|
||||
|
||||
message ActionPurchase {
|
||||
PurchasePayload payload = 1;
|
||||
bytes sellerSignature = 2;
|
||||
string sellerSignature = 2;
|
||||
}
|
||||
|
||||
message PurchasePayload {
|
||||
ActionID deployID = 1;
|
||||
bytes buyerPublicKey = 2;
|
||||
string buyerPublicKey = 2;
|
||||
repeated uint32 nodeIDs = 3;
|
||||
int64 totalAmountSat = 4;
|
||||
uint64 timeOutBlock = 5;
|
||||
}
|
||||
|
||||
message ActionID {
|
||||
@@ -52,7 +53,7 @@ message ActionID {
|
||||
}
|
||||
|
||||
message ActionDelegate {
|
||||
bytes delegateePublicKey = 1;
|
||||
string delegateePublicKey = 1;
|
||||
repeated uint32 nodeIDs = 2;
|
||||
ActionID deployID = 3;
|
||||
ActionID deployID = 3;
|
||||
}
|
||||
@@ -2,15 +2,42 @@ package nodesale
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
|
||||
"github.com/btcsuite/btcd/btcec/v2"
|
||||
"github.com/btcsuite/btcd/btcec/v2/schnorr"
|
||||
"github.com/btcsuite/btcd/btcutil"
|
||||
"github.com/btcsuite/btcd/txscript"
|
||||
)
|
||||
|
||||
func (p *Processor) pubkeyToAddress(pubkey string) btcutil.Address {
|
||||
func (p *Processor) pubkeyToTaprootAddress(pubkey string, script []byte) (btcutil.Address, error) {
|
||||
pubKeyBytes, err := hex.DecodeString(pubkey)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Failed to decode string : %w", err)
|
||||
}
|
||||
pubKey, err := btcec.ParsePubKey(pubKeyBytes)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Failed to parse pubkey : %w", err)
|
||||
}
|
||||
|
||||
tapleaf := txscript.NewBaseTapLeaf(script)
|
||||
|
||||
scriptTree := txscript.AssembleTaprootScriptTree(tapleaf)
|
||||
rootHash := scriptTree.RootNode.TapHash()
|
||||
|
||||
tapkey := txscript.ComputeTaprootOutputKey(pubKey, rootHash[:])
|
||||
|
||||
sellerAddr, err := btcutil.NewAddressTaproot(schnorr.SerializePubKey(tapkey), p.network.ChainParams())
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid taproot address: %w", err)
|
||||
}
|
||||
return sellerAddr, nil
|
||||
}
|
||||
|
||||
func (p *Processor) pubkeyToPkHashAddress(pubkey string) btcutil.Address {
|
||||
pubKeyBytes, _ := hex.DecodeString(pubkey)
|
||||
pubKey, _ := btcec.ParsePubKey(pubKeyBytes)
|
||||
sellerAddr, _ := btcutil.NewAddressTaproot(schnorr.SerializePubKey(pubKey), p.network.ChainParams())
|
||||
return sellerAddr
|
||||
addrPubKey, _ := btcutil.NewAddressPubKey(pubKey.SerializeCompressed(), p.network.ChainParams())
|
||||
addrPubKeyHash := addrPubKey.AddressPubKeyHash()
|
||||
return addrPubKeyHash
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"context"
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"slices"
|
||||
|
||||
@@ -19,13 +20,19 @@ import (
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
type metaData struct {
|
||||
ExpectedTotalAmountDiscounted int64
|
||||
ReportedTotalAmount int64
|
||||
PaidTotalAmount int64
|
||||
}
|
||||
|
||||
func (p *Processor) processPurchase(ctx context.Context, qtx gen.Querier, block *types.Block, event nodesaleEvent) error {
|
||||
valid := true
|
||||
purchase := event.eventMessage.Purchase
|
||||
payload := purchase.Payload
|
||||
|
||||
buyerAddr := p.pubkeyToAddress(string(payload.BuyerPublicKey))
|
||||
if !bytes.Equal(
|
||||
buyerAddr, err := p.pubkeyToTaprootAddress(payload.BuyerPublicKey, event.rawScript)
|
||||
if err != nil || !bytes.Equal(
|
||||
[]byte(buyerAddr.EncodeAddress()),
|
||||
[]byte(event.txAddress.EncodeAddress()),
|
||||
) {
|
||||
@@ -57,19 +64,29 @@ func (p *Processor) processPurchase(ctx context.Context, qtx gen.Querier, block
|
||||
}
|
||||
}
|
||||
|
||||
if valid {
|
||||
if payload.TimeOutBlock < uint64(event.transaction.BlockHeight) {
|
||||
valid = false
|
||||
}
|
||||
}
|
||||
|
||||
if valid {
|
||||
// verified signature
|
||||
payloadBytes, _ := proto.Marshal(payload)
|
||||
signatureBytes, _ := hex.DecodeString(string(purchase.SellerSignature))
|
||||
|
||||
signature, _ := ecdsa.ParseSignature(signatureBytes)
|
||||
hash := sha256.Sum256(payloadBytes)
|
||||
pubkeyBytes, _ := hex.DecodeString(deploy.SellerPublicKey)
|
||||
pubKey, _ := btcec.ParsePubKey(pubkeyBytes)
|
||||
verified := signature.Verify(hash[:], pubKey)
|
||||
if !verified {
|
||||
signatureBytes, _ := hex.DecodeString(purchase.SellerSignature)
|
||||
signature, err := ecdsa.ParseSignature(signatureBytes)
|
||||
if err != nil {
|
||||
valid = false
|
||||
}
|
||||
if valid {
|
||||
hash := sha256.Sum256(payloadBytes)
|
||||
pubkeyBytes, _ := hex.DecodeString(deploy.SellerPublicKey)
|
||||
pubKey, _ := btcec.ParsePubKey(pubkeyBytes)
|
||||
verified := signature.Verify(hash[:], pubKey)
|
||||
if !verified {
|
||||
valid = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var tiers []protobuf.Tier
|
||||
@@ -123,12 +140,12 @@ func (p *Processor) processPurchase(ctx context.Context, qtx gen.Querier, block
|
||||
}
|
||||
|
||||
var txPaid int64 = 0
|
||||
meta := metaData{}
|
||||
if valid {
|
||||
// get total amount paid to seller
|
||||
sellerAddr := p.pubkeyToAddress(deploy.SellerPublicKey)
|
||||
sellerAddr := p.pubkeyToPkHashAddress(deploy.SellerPublicKey)
|
||||
for _, txOut := range event.transaction.TxOut {
|
||||
_, txOutAddrs, _, _ := txscript.ExtractPkScriptAddrs(txOut.PkScript, p.network.ChainParams())
|
||||
|
||||
if len(txOutAddrs) == 1 && bytes.Equal(
|
||||
[]byte(sellerAddr.EncodeAddress()),
|
||||
[]byte(txOutAddrs[0].EncodeAddress()),
|
||||
@@ -136,13 +153,12 @@ func (p *Processor) processPurchase(ctx context.Context, qtx gen.Querier, block
|
||||
txPaid += txOut.Value
|
||||
}
|
||||
}
|
||||
meta.PaidTotalAmount = txPaid
|
||||
meta.ReportedTotalAmount = payload.TotalAmountSat
|
||||
// total amount paid is greater than report paid
|
||||
if txPaid < payload.TotalAmountSat {
|
||||
valid = false
|
||||
}
|
||||
}
|
||||
|
||||
if valid {
|
||||
// calculate total price
|
||||
var totalPrice int64 = 0
|
||||
for i := 0; i < len(tiers); i++ {
|
||||
@@ -155,6 +171,7 @@ func (p *Processor) processPurchase(ctx context.Context, qtx gen.Querier, block
|
||||
if decimal%100 >= 50 {
|
||||
maxDiscounted++
|
||||
}
|
||||
meta.ExpectedTotalAmountDiscounted = maxDiscounted
|
||||
if payload.TotalAmountSat < maxDiscounted {
|
||||
valid = false
|
||||
}
|
||||
@@ -168,12 +185,12 @@ func (p *Processor) processPurchase(ctx context.Context, qtx gen.Querier, block
|
||||
buyerOwnedNodes, err = qtx.GetNodesByOwner(ctx, gen.GetNodesByOwnerParams{
|
||||
SaleBlock: deploy.BlockHeight,
|
||||
SaleTxIndex: deploy.TxIndex,
|
||||
OwnerPublicKey: string(payload.BuyerPublicKey),
|
||||
OwnerPublicKey: payload.BuyerPublicKey,
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed to GetNodesByOwner : %w", err)
|
||||
}
|
||||
if len(buyerOwnedNodes) > int(deploy.MaxPerAddress) {
|
||||
if len(buyerOwnedNodes)+len(payload.NodeIDs) > int(deploy.MaxPerAddress) {
|
||||
valid = false
|
||||
}
|
||||
}
|
||||
@@ -183,40 +200,31 @@ func (p *Processor) processPurchase(ctx context.Context, qtx gen.Querier, block
|
||||
// count each tiers
|
||||
// check limited for each tier
|
||||
ownedTiersCount := make([]uint32, len(tiers))
|
||||
currentTier := -1
|
||||
var tierSum uint32 = 0
|
||||
for _, node := range buyerOwnedNodes {
|
||||
for uint32(node.TierIndex) >= tierSum && currentTier < len(tiers)-1 {
|
||||
currentTier++
|
||||
tierSum += tiers[currentTier].Limit
|
||||
}
|
||||
if uint32(node.TierIndex) < tierSum {
|
||||
ownedTiersCount[currentTier]++
|
||||
} else {
|
||||
valid = false
|
||||
}
|
||||
ownedTiersCount[node.TierIndex]++
|
||||
}
|
||||
for i := 0; i < len(tiers); i++ {
|
||||
ownedTiersCount[i] += buyingTiersCount[i]
|
||||
if ownedTiersCount[i] > tiers[i].Limit {
|
||||
if ownedTiersCount[i]+buyingTiersCount[i] > tiers[i].MaxPerAddress {
|
||||
valid = false
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
err := qtx.AddEvent(ctx, gen.AddEventParams{
|
||||
metaDataBytes, _ := json.Marshal(meta)
|
||||
|
||||
err = qtx.AddEvent(ctx, gen.AddEventParams{
|
||||
TxHash: event.transaction.TxHash.String(),
|
||||
TxIndex: int32(event.transaction.Index),
|
||||
Action: int32(event.eventMessage.Action),
|
||||
RawMessage: event.rawData,
|
||||
ParsedMessage: event.eventJson,
|
||||
BlockTimestamp: pgtype.Timestamp{Time: block.Header.Timestamp, Valid: true},
|
||||
BlockHash: block.Header.Hash.String(),
|
||||
BlockHeight: int32(block.Header.Height),
|
||||
BlockHash: event.transaction.BlockHash.String(),
|
||||
BlockHeight: int32(event.transaction.BlockHeight),
|
||||
Valid: valid,
|
||||
WalletAddress: event.txAddress.EncodeAddress(),
|
||||
Metadata: []byte{},
|
||||
Metadata: metaDataBytes,
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed to insert event : %w", err)
|
||||
@@ -226,12 +234,12 @@ func (p *Processor) processPurchase(ctx context.Context, qtx gen.Querier, block
|
||||
// add to node
|
||||
for _, nodeId := range payload.NodeIDs {
|
||||
err := qtx.AddNode(ctx, gen.AddNodeParams{
|
||||
SaleBlock: int32(event.transaction.BlockHeight),
|
||||
SaleTxIndex: int32(event.transaction.Index),
|
||||
SaleBlock: deploy.BlockHeight,
|
||||
SaleTxIndex: deploy.TxIndex,
|
||||
NodeID: int32(nodeId),
|
||||
TierIndex: nodeIdToTier[nodeId],
|
||||
DelegatedTo: pgtype.Text{Valid: false},
|
||||
OwnerPublicKey: string(payload.BuyerPublicKey),
|
||||
OwnerPublicKey: payload.BuyerPublicKey,
|
||||
PurchaseTxHash: event.transaction.TxHash.String(),
|
||||
DelegateTxHash: pgtype.Text{Valid: false},
|
||||
})
|
||||
|
||||
445
modules/nodesale/purchase_test.go
Normal file
445
modules/nodesale/purchase_test.go
Normal file
@@ -0,0 +1,445 @@
|
||||
package nodesale
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/btcsuite/btcd/btcec/v2"
|
||||
"github.com/btcsuite/btcd/btcutil"
|
||||
"github.com/btcsuite/btcd/txscript"
|
||||
"github.com/decred/dcrd/dcrec/secp256k1/v4/ecdsa"
|
||||
"github.com/gaze-network/indexer-network/core/types"
|
||||
"github.com/gaze-network/indexer-network/modules/nodesale/protobuf"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
func TestInvalidPurchase(t *testing.T) {
|
||||
buyerPrivateKey, _ := btcec.NewPrivateKey()
|
||||
buyerPubkeyHex := hex.EncodeToString(buyerPrivateKey.PubKey().SerializeCompressed())
|
||||
|
||||
message := &protobuf.NodeSaleEvent{
|
||||
Action: protobuf.Action_ACTION_PURCHASE,
|
||||
Purchase: &protobuf.ActionPurchase{
|
||||
Payload: &protobuf.PurchasePayload{
|
||||
DeployID: &protobuf.ActionID{
|
||||
Block: 111,
|
||||
TxIndex: 1,
|
||||
},
|
||||
BuyerPublicKey: buyerPubkeyHex,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
event, block := assembleTestEvent(buyerPrivateKey, "030303030303", "030303030303", 0, 0, message)
|
||||
|
||||
p.processPurchase(ctx, qtx, block, event)
|
||||
}
|
||||
|
||||
func TestInvalidTimestamp(t *testing.T) {
|
||||
sellerPrivateKey, _ := btcec.NewPrivateKey()
|
||||
sellerPubkeyHex := hex.EncodeToString(sellerPrivateKey.PubKey().SerializeCompressed())
|
||||
startAt := time.Now().Add(time.Hour * -1)
|
||||
endAt := time.Now().Add(time.Hour * 1)
|
||||
deployMessage := &protobuf.NodeSaleEvent{
|
||||
Action: protobuf.Action_ACTION_DEPLOY,
|
||||
Deploy: &protobuf.ActionDeploy{
|
||||
Name: "deploy_for_puchase",
|
||||
StartsAt: uint32(startAt.UTC().Unix()),
|
||||
EndsAt: uint32(endAt.UTC().Unix()),
|
||||
Tiers: []*protobuf.Tier{
|
||||
{
|
||||
PriceSat: 100,
|
||||
Limit: 5,
|
||||
MaxPerAddress: 100,
|
||||
},
|
||||
{
|
||||
PriceSat: 200,
|
||||
Limit: 5,
|
||||
MaxPerAddress: 100,
|
||||
},
|
||||
},
|
||||
SellerPublicKey: sellerPubkeyHex,
|
||||
MaxPerAddress: 100,
|
||||
MaxDiscountPercentage: 50,
|
||||
},
|
||||
}
|
||||
event, block := assembleTestEvent(sellerPrivateKey, "040404040404", "040404040404", 0, 0, deployMessage)
|
||||
p.processDeploy(ctx, qtx, block, event)
|
||||
|
||||
buyerPrivateKey, _ := btcec.NewPrivateKey()
|
||||
buyerPubkeyHex := hex.EncodeToString(buyerPrivateKey.PubKey().SerializeCompressed())
|
||||
|
||||
message := &protobuf.NodeSaleEvent{
|
||||
Action: protobuf.Action_ACTION_PURCHASE,
|
||||
Purchase: &protobuf.ActionPurchase{
|
||||
Payload: &protobuf.PurchasePayload{
|
||||
DeployID: &protobuf.ActionID{
|
||||
Block: uint64(testBlockHeigh) - 1,
|
||||
TxIndex: uint32(testTxIndex) - 1,
|
||||
},
|
||||
BuyerPublicKey: buyerPubkeyHex,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
event, block = assembleTestEvent(buyerPrivateKey, "050505050505", "050505050505", 0, 0, message)
|
||||
block.Header.Timestamp = time.Now().UTC().Add(time.Hour * 2)
|
||||
p.processPurchase(ctx, qtx, block, event)
|
||||
}
|
||||
|
||||
func TestInvalidBuyerKey(t *testing.T) {
|
||||
sellerPrivateKey, _ := btcec.NewPrivateKey()
|
||||
sellerPubkeyHex := hex.EncodeToString(sellerPrivateKey.PubKey().SerializeCompressed())
|
||||
startAt := time.Now().Add(time.Hour * -1)
|
||||
endAt := time.Now().Add(time.Hour * 1)
|
||||
deployMessage := &protobuf.NodeSaleEvent{
|
||||
Action: protobuf.Action_ACTION_DEPLOY,
|
||||
Deploy: &protobuf.ActionDeploy{
|
||||
Name: "deploy_for_puchase",
|
||||
StartsAt: uint32(startAt.UTC().Unix()),
|
||||
EndsAt: uint32(endAt.UTC().Unix()),
|
||||
Tiers: []*protobuf.Tier{
|
||||
{
|
||||
PriceSat: 100,
|
||||
Limit: 5,
|
||||
MaxPerAddress: 100,
|
||||
},
|
||||
{
|
||||
PriceSat: 200,
|
||||
Limit: 5,
|
||||
MaxPerAddress: 100,
|
||||
},
|
||||
},
|
||||
SellerPublicKey: sellerPubkeyHex,
|
||||
MaxPerAddress: 100,
|
||||
MaxDiscountPercentage: 50,
|
||||
},
|
||||
}
|
||||
event, block := assembleTestEvent(sellerPrivateKey, "060606060606", "060606060606", 0, 0, deployMessage)
|
||||
p.processDeploy(ctx, qtx, block, event)
|
||||
|
||||
buyerPrivateKey, _ := btcec.NewPrivateKey()
|
||||
|
||||
message := &protobuf.NodeSaleEvent{
|
||||
Action: protobuf.Action_ACTION_PURCHASE,
|
||||
Purchase: &protobuf.ActionPurchase{
|
||||
Payload: &protobuf.PurchasePayload{
|
||||
DeployID: &protobuf.ActionID{
|
||||
Block: uint64(testBlockHeigh) - 1,
|
||||
TxIndex: uint32(testTxIndex) - 1,
|
||||
},
|
||||
BuyerPublicKey: sellerPubkeyHex,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
event, block = assembleTestEvent(buyerPrivateKey, "0707070707", "0707070707", 0, 0, message)
|
||||
block.Header.Timestamp = time.Now().UTC().Add(time.Hour * 2)
|
||||
p.processPurchase(ctx, qtx, block, event)
|
||||
}
|
||||
|
||||
func TestTimeOut(t *testing.T) {
|
||||
sellerPrivateKey, _ := btcec.NewPrivateKey()
|
||||
sellerPubkeyHex := hex.EncodeToString(sellerPrivateKey.PubKey().SerializeCompressed())
|
||||
startAt := time.Now().Add(time.Hour * -1)
|
||||
endAt := time.Now().Add(time.Hour * 1)
|
||||
deployMessage := &protobuf.NodeSaleEvent{
|
||||
Action: protobuf.Action_ACTION_DEPLOY,
|
||||
Deploy: &protobuf.ActionDeploy{
|
||||
Name: "deploy_for_puchase",
|
||||
StartsAt: uint32(startAt.UTC().Unix()),
|
||||
EndsAt: uint32(endAt.UTC().Unix()),
|
||||
Tiers: []*protobuf.Tier{
|
||||
{
|
||||
PriceSat: 100,
|
||||
Limit: 5,
|
||||
MaxPerAddress: 100,
|
||||
},
|
||||
{
|
||||
PriceSat: 200,
|
||||
Limit: 5,
|
||||
MaxPerAddress: 100,
|
||||
},
|
||||
},
|
||||
SellerPublicKey: sellerPubkeyHex,
|
||||
MaxPerAddress: 100,
|
||||
MaxDiscountPercentage: 50,
|
||||
},
|
||||
}
|
||||
event, block := assembleTestEvent(sellerPrivateKey, "0808080808", "0808080808", 0, 0, deployMessage)
|
||||
p.processDeploy(ctx, qtx, block, event)
|
||||
|
||||
buyerPrivateKey, _ := btcec.NewPrivateKey()
|
||||
buyerPubkeyHex := hex.EncodeToString(buyerPrivateKey.PubKey().SerializeCompressed())
|
||||
|
||||
message := &protobuf.NodeSaleEvent{
|
||||
Action: protobuf.Action_ACTION_PURCHASE,
|
||||
Purchase: &protobuf.ActionPurchase{
|
||||
Payload: &protobuf.PurchasePayload{
|
||||
DeployID: &protobuf.ActionID{
|
||||
Block: uint64(testBlockHeigh) - 1,
|
||||
TxIndex: uint32(testTxIndex) - 1,
|
||||
},
|
||||
BuyerPublicKey: buyerPubkeyHex,
|
||||
TimeOutBlock: uint64(testBlockHeigh) - 5,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
event, block = assembleTestEvent(buyerPrivateKey, "090909090909", "090909090909", 0, 0, message)
|
||||
p.processPurchase(ctx, qtx, block, event)
|
||||
}
|
||||
|
||||
func TestSignatureInvalid(t *testing.T) {
|
||||
sellerPrivateKey, _ := btcec.NewPrivateKey()
|
||||
sellerPubkeyHex := hex.EncodeToString(sellerPrivateKey.PubKey().SerializeCompressed())
|
||||
startAt := time.Now().Add(time.Hour * -1)
|
||||
endAt := time.Now().Add(time.Hour * 1)
|
||||
deployMessage := &protobuf.NodeSaleEvent{
|
||||
Action: protobuf.Action_ACTION_DEPLOY,
|
||||
Deploy: &protobuf.ActionDeploy{
|
||||
Name: "deploy_for_puchase",
|
||||
StartsAt: uint32(startAt.UTC().Unix()),
|
||||
EndsAt: uint32(endAt.UTC().Unix()),
|
||||
Tiers: []*protobuf.Tier{
|
||||
{
|
||||
PriceSat: 100,
|
||||
Limit: 5,
|
||||
MaxPerAddress: 100,
|
||||
},
|
||||
{
|
||||
PriceSat: 200,
|
||||
Limit: 5,
|
||||
MaxPerAddress: 100,
|
||||
},
|
||||
},
|
||||
SellerPublicKey: sellerPubkeyHex,
|
||||
MaxPerAddress: 100,
|
||||
MaxDiscountPercentage: 50,
|
||||
},
|
||||
}
|
||||
event, block := assembleTestEvent(sellerPrivateKey, "0A0A0A0A", "0A0A0A0A", 0, 0, deployMessage)
|
||||
p.processDeploy(ctx, qtx, block, event)
|
||||
|
||||
buyerPrivateKey, _ := btcec.NewPrivateKey()
|
||||
buyerPubkeyHex := hex.EncodeToString(buyerPrivateKey.PubKey().SerializeCompressed())
|
||||
|
||||
payload := &protobuf.PurchasePayload{
|
||||
DeployID: &protobuf.ActionID{
|
||||
Block: uint64(testBlockHeigh) - 1,
|
||||
TxIndex: uint32(testTxIndex) - 1,
|
||||
},
|
||||
BuyerPublicKey: buyerPubkeyHex,
|
||||
TimeOutBlock: uint64(testBlockHeigh) + 5,
|
||||
}
|
||||
|
||||
payloadBytes, _ := proto.Marshal(payload)
|
||||
payloadHash := sha256.Sum256(payloadBytes)
|
||||
signature := ecdsa.Sign(buyerPrivateKey, payloadHash[:])
|
||||
signatureHex := hex.EncodeToString(signature.Serialize())
|
||||
|
||||
message := &protobuf.NodeSaleEvent{
|
||||
Action: protobuf.Action_ACTION_PURCHASE,
|
||||
Purchase: &protobuf.ActionPurchase{
|
||||
Payload: payload,
|
||||
SellerSignature: signatureHex,
|
||||
},
|
||||
}
|
||||
|
||||
event, block = assembleTestEvent(buyerPrivateKey, "0B0B0B", "0B0B0B", 0, 0, message)
|
||||
p.processPurchase(ctx, qtx, block, event)
|
||||
}
|
||||
|
||||
func TestValidPurchase(t *testing.T) {
|
||||
sellerPrivateKey, _ := btcec.NewPrivateKey()
|
||||
sellerPubkeyHex := hex.EncodeToString(sellerPrivateKey.PubKey().SerializeCompressed())
|
||||
startAt := time.Now().Add(time.Hour * -1)
|
||||
endAt := time.Now().Add(time.Hour * 1)
|
||||
deployMessage := &protobuf.NodeSaleEvent{
|
||||
Action: protobuf.Action_ACTION_DEPLOY,
|
||||
Deploy: &protobuf.ActionDeploy{
|
||||
Name: "deploy_for_puchase",
|
||||
StartsAt: uint32(startAt.UTC().Unix()),
|
||||
EndsAt: uint32(endAt.UTC().Unix()),
|
||||
Tiers: []*protobuf.Tier{
|
||||
{
|
||||
PriceSat: 100,
|
||||
Limit: 5,
|
||||
MaxPerAddress: 100,
|
||||
},
|
||||
{
|
||||
PriceSat: 200,
|
||||
Limit: 4,
|
||||
MaxPerAddress: 2,
|
||||
},
|
||||
{
|
||||
PriceSat: 400,
|
||||
Limit: 3,
|
||||
MaxPerAddress: 100,
|
||||
},
|
||||
},
|
||||
SellerPublicKey: sellerPubkeyHex,
|
||||
MaxPerAddress: 100,
|
||||
MaxDiscountPercentage: 50,
|
||||
},
|
||||
}
|
||||
event, block := assembleTestEvent(sellerPrivateKey, "0C0C0C0C0C", "0C0C0C0C0C", 0, 0, deployMessage)
|
||||
p.processDeploy(ctx, qtx, block, event)
|
||||
|
||||
buyerPrivateKey, _ := btcec.NewPrivateKey()
|
||||
buyerPubkeyHex := hex.EncodeToString(buyerPrivateKey.PubKey().SerializeCompressed())
|
||||
|
||||
payload := &protobuf.PurchasePayload{
|
||||
DeployID: &protobuf.ActionID{
|
||||
Block: uint64(testBlockHeigh) - 1,
|
||||
TxIndex: uint32(testTxIndex) - 1,
|
||||
},
|
||||
BuyerPublicKey: buyerPubkeyHex,
|
||||
TimeOutBlock: uint64(testBlockHeigh) + 5,
|
||||
NodeIDs: []uint32{0, 5, 6, 9},
|
||||
TotalAmountSat: 500,
|
||||
}
|
||||
|
||||
payloadBytes, _ := proto.Marshal(payload)
|
||||
payloadHash := sha256.Sum256(payloadBytes)
|
||||
signature := ecdsa.Sign(sellerPrivateKey, payloadHash[:])
|
||||
signatureHex := hex.EncodeToString(signature.Serialize())
|
||||
|
||||
message := &protobuf.NodeSaleEvent{
|
||||
Action: protobuf.Action_ACTION_PURCHASE,
|
||||
Purchase: &protobuf.ActionPurchase{
|
||||
Payload: payload,
|
||||
SellerSignature: signatureHex,
|
||||
},
|
||||
}
|
||||
|
||||
event, block = assembleTestEvent(buyerPrivateKey, "0D0D0D0D", "0D0D0D0D", 0, 0, message)
|
||||
|
||||
addr, _ := btcutil.NewAddressPubKey(sellerPrivateKey.PubKey().SerializeCompressed(), p.network.ChainParams())
|
||||
pkscript, _ := txscript.PayToAddrScript(addr.AddressPubKeyHash())
|
||||
event.transaction.TxOut = []*types.TxOut{
|
||||
{
|
||||
PkScript: pkscript,
|
||||
Value: 500,
|
||||
},
|
||||
}
|
||||
p.processPurchase(ctx, qtx, block, event)
|
||||
}
|
||||
|
||||
func TestBuyingLimit(t *testing.T) {
|
||||
sellerPrivateKey, _ := btcec.NewPrivateKey()
|
||||
sellerPubkeyHex := hex.EncodeToString(sellerPrivateKey.PubKey().SerializeCompressed())
|
||||
startAt := time.Now().Add(time.Hour * -1)
|
||||
endAt := time.Now().Add(time.Hour * 1)
|
||||
deployMessage := &protobuf.NodeSaleEvent{
|
||||
Action: protobuf.Action_ACTION_DEPLOY,
|
||||
Deploy: &protobuf.ActionDeploy{
|
||||
Name: "deploy_for_puchase",
|
||||
StartsAt: uint32(startAt.UTC().Unix()),
|
||||
EndsAt: uint32(endAt.UTC().Unix()),
|
||||
Tiers: []*protobuf.Tier{
|
||||
{
|
||||
PriceSat: 100,
|
||||
Limit: 5,
|
||||
MaxPerAddress: 100,
|
||||
},
|
||||
{
|
||||
PriceSat: 200,
|
||||
Limit: 4,
|
||||
MaxPerAddress: 2,
|
||||
},
|
||||
{
|
||||
PriceSat: 400,
|
||||
Limit: 50,
|
||||
MaxPerAddress: 3,
|
||||
},
|
||||
},
|
||||
SellerPublicKey: sellerPubkeyHex,
|
||||
MaxPerAddress: 100,
|
||||
MaxDiscountPercentage: 50,
|
||||
},
|
||||
}
|
||||
event, block := assembleTestEvent(sellerPrivateKey, "0E0E0E0E", "0E0E0E0E", 0, 0, deployMessage)
|
||||
p.processDeploy(ctx, qtx, block, event)
|
||||
|
||||
buyerPrivateKey, _ := btcec.NewPrivateKey()
|
||||
buyerPubkeyHex := hex.EncodeToString(buyerPrivateKey.PubKey().SerializeCompressed())
|
||||
|
||||
payload := &protobuf.PurchasePayload{
|
||||
DeployID: &protobuf.ActionID{
|
||||
Block: uint64(testBlockHeigh) - 1,
|
||||
TxIndex: uint32(testTxIndex) - 1,
|
||||
},
|
||||
BuyerPublicKey: buyerPubkeyHex,
|
||||
TimeOutBlock: uint64(testBlockHeigh) + 5,
|
||||
NodeIDs: []uint32{9, 10, 11},
|
||||
TotalAmountSat: 600,
|
||||
}
|
||||
|
||||
payloadBytes, _ := proto.Marshal(payload)
|
||||
payloadHash := sha256.Sum256(payloadBytes)
|
||||
signature := ecdsa.Sign(sellerPrivateKey, payloadHash[:])
|
||||
signatureHex := hex.EncodeToString(signature.Serialize())
|
||||
|
||||
message := &protobuf.NodeSaleEvent{
|
||||
Action: protobuf.Action_ACTION_PURCHASE,
|
||||
Purchase: &protobuf.ActionPurchase{
|
||||
Payload: payload,
|
||||
SellerSignature: signatureHex,
|
||||
},
|
||||
}
|
||||
|
||||
event, block = assembleTestEvent(buyerPrivateKey, "0F0F0F0F0F", "0F0F0F0F0F", 0, 0, message)
|
||||
|
||||
addr, _ := btcutil.NewAddressPubKey(sellerPrivateKey.PubKey().SerializeCompressed(), p.network.ChainParams())
|
||||
pkscript, _ := txscript.PayToAddrScript(addr.AddressPubKeyHash())
|
||||
event.transaction.TxOut = []*types.TxOut{
|
||||
{
|
||||
PkScript: pkscript,
|
||||
Value: 600,
|
||||
},
|
||||
}
|
||||
p.processPurchase(ctx, qtx, block, event)
|
||||
|
||||
tx.Commit(ctx)
|
||||
tx, _ = p.repository.Db.Begin(ctx)
|
||||
qtx = p.repository.WithTx(tx)
|
||||
|
||||
payload = &protobuf.PurchasePayload{
|
||||
DeployID: &protobuf.ActionID{
|
||||
Block: uint64(testBlockHeigh) - 2,
|
||||
TxIndex: uint32(testTxIndex) - 2,
|
||||
},
|
||||
BuyerPublicKey: buyerPubkeyHex,
|
||||
TimeOutBlock: uint64(testBlockHeigh) + 5,
|
||||
NodeIDs: []uint32{12, 13, 14},
|
||||
TotalAmountSat: 600,
|
||||
}
|
||||
|
||||
payloadBytes, _ = proto.Marshal(payload)
|
||||
payloadHash = sha256.Sum256(payloadBytes)
|
||||
signature = ecdsa.Sign(sellerPrivateKey, payloadHash[:])
|
||||
signatureHex = hex.EncodeToString(signature.Serialize())
|
||||
|
||||
message = &protobuf.NodeSaleEvent{
|
||||
Action: protobuf.Action_ACTION_PURCHASE,
|
||||
Purchase: &protobuf.ActionPurchase{
|
||||
Payload: payload,
|
||||
SellerSignature: signatureHex,
|
||||
},
|
||||
}
|
||||
|
||||
event, block = assembleTestEvent(buyerPrivateKey, "10101010", "10101010", 0, 0, message)
|
||||
|
||||
addr, _ = btcutil.NewAddressPubKey(sellerPrivateKey.PubKey().SerializeCompressed(), p.network.ChainParams())
|
||||
pkscript, _ = txscript.PayToAddrScript(addr.AddressPubKeyHash())
|
||||
event.transaction.TxOut = []*types.TxOut{
|
||||
{
|
||||
PkScript: pkscript,
|
||||
Value: 600,
|
||||
},
|
||||
}
|
||||
p.processPurchase(ctx, qtx, block, event)
|
||||
}
|
||||
@@ -14,6 +14,7 @@ type Querier interface {
|
||||
AddNode(ctx context.Context, arg AddNodeParams) error
|
||||
AddNodesale(ctx context.Context, arg AddNodesaleParams) error
|
||||
ClearDelegate(ctx context.Context) (int64, error)
|
||||
ClearEvents(ctx context.Context) error
|
||||
GetBlock(ctx context.Context, blockHeight int32) (Block, error)
|
||||
GetLastProcessedBlock(ctx context.Context) (Block, error)
|
||||
GetNodes(ctx context.Context, arg GetNodesParams) ([]Node, error)
|
||||
|
||||
19
modules/nodesale/repository/postgres/gen/test.sql.go
Normal file
19
modules/nodesale/repository/postgres/gen/test.sql.go
Normal file
@@ -0,0 +1,19 @@
|
||||
// Code generated by sqlc. DO NOT EDIT.
|
||||
// versions:
|
||||
// sqlc v1.26.0
|
||||
// source: test.sql
|
||||
|
||||
package gen
|
||||
|
||||
import (
|
||||
"context"
|
||||
)
|
||||
|
||||
const clearEvents = `-- name: ClearEvents :exec
|
||||
DELETE FROM events
|
||||
`
|
||||
|
||||
func (q *Queries) ClearEvents(ctx context.Context) error {
|
||||
_, err := q.db.Exec(ctx, clearEvents)
|
||||
return err
|
||||
}
|
||||
@@ -2,14 +2,14 @@ package nodesale
|
||||
|
||||
import "github.com/btcsuite/btcd/txscript"
|
||||
|
||||
func extractTapScript(witness [][]byte) (txscript.ScriptTokenizer, bool) {
|
||||
func extractTapScript(witness [][]byte) (txscript.ScriptTokenizer, []byte, bool) {
|
||||
witness = removeAnnexFromWitness(witness)
|
||||
if len(witness) < 2 {
|
||||
return txscript.ScriptTokenizer{}, false
|
||||
return txscript.ScriptTokenizer{}, nil, false
|
||||
}
|
||||
script := witness[len(witness)-2]
|
||||
|
||||
return txscript.MakeScriptTokenizer(0, script), true
|
||||
return txscript.MakeScriptTokenizer(0, script), script, true
|
||||
}
|
||||
|
||||
func removeAnnexFromWitness(witness [][]byte) [][]byte {
|
||||
|
||||
Reference in New Issue
Block a user