mirror of
https://github.com/alexgo-io/gaze-indexer.git
synced 2026-01-12 22:43:22 +08:00
Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7c0e28d8ea | ||
|
|
754fd1e997 | ||
|
|
66f03f7107 | ||
|
|
7a863987ec | ||
|
|
f9c6ef8dfd |
@@ -6,6 +6,7 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
||||
"github.com/cockroachdb/errors"
|
||||
"github.com/gaze-network/indexer-network/common/errs"
|
||||
"github.com/gaze-network/indexer-network/core/datasources"
|
||||
@@ -142,7 +143,7 @@ func (i *Indexer[T]) process(ctx context.Context) (err error) {
|
||||
// validate reorg from first input
|
||||
{
|
||||
remoteBlockHeader := firstInputHeader
|
||||
if !remoteBlockHeader.PrevBlock.IsEqual(&i.currentBlock.Hash) {
|
||||
if i.currentBlock.Hash != (chainhash.Hash{}) && !remoteBlockHeader.PrevBlock.IsEqual(&i.currentBlock.Hash) {
|
||||
logger.WarnContext(ctx, "Detected chain reorganization. Searching for fork point...",
|
||||
slogx.String("event", "reorg_detected"),
|
||||
slogx.Stringer("current_hash", i.currentBlock.Hash),
|
||||
@@ -215,7 +216,7 @@ func (i *Indexer[T]) process(ctx context.Context) (err error) {
|
||||
return errors.Wrapf(errs.InternalError, "input is not continuous, input[%d] height: %d, input[%d] height: %d", i-1, prevHeader.Height, i, header.Height)
|
||||
}
|
||||
|
||||
if !header.PrevBlock.IsEqual(&prevHeader.Hash) {
|
||||
if prevHeader.Hash != (chainhash.Hash{}) && !header.PrevBlock.IsEqual(&prevHeader.Hash) {
|
||||
logger.WarnContext(ctx, "Chain Reorganization occurred in the middle of batch fetching inputs, need to try to fetch again")
|
||||
|
||||
// end current round
|
||||
|
||||
@@ -2,12 +2,15 @@ package constants
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/Cleverse/go-utilities/utils"
|
||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
||||
"github.com/gaze-network/indexer-network/common"
|
||||
"github.com/gaze-network/indexer-network/core/types"
|
||||
"github.com/gaze-network/indexer-network/modules/runes/runes"
|
||||
"github.com/gaze-network/indexer-network/pkg/logger"
|
||||
"github.com/gaze-network/uint128"
|
||||
"github.com/samber/lo"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -16,22 +19,93 @@ const (
|
||||
EventHashVersion = 1
|
||||
)
|
||||
|
||||
// starting block heights and hashes should be 1 block before activation block, as indexer will start from the block after this value
|
||||
var StartingBlockHeader = map[common.Network]types.BlockHeader{
|
||||
common.NetworkMainnet: {
|
||||
Height: 839999,
|
||||
Hash: *utils.Must(chainhash.NewHashFromStr("0000000000000000000172014ba58d66455762add0512355ad651207918494ab")),
|
||||
},
|
||||
common.NetworkTestnet: {
|
||||
Height: 2519999,
|
||||
Hash: *utils.Must(chainhash.NewHashFromStr("000000000006f45c16402f05d9075db49d3571cf5273cf4cbeaa2aa295f7c833")),
|
||||
},
|
||||
common.NetworkFractalMainnet: {
|
||||
Height: 83999,
|
||||
Hash: *utils.Must(chainhash.NewHashFromStr("0000000000000000000000000000000000000000000000000000000000000000")), // TODO: Update this to match real hash
|
||||
},
|
||||
common.NetworkFractalTestnet: {
|
||||
Height: 83999,
|
||||
Hash: *utils.Must(chainhash.NewHashFromStr("00000000000000613ddfbdd1778b17cea3818febcbbf82762eafaa9461038343")),
|
||||
},
|
||||
}
|
||||
|
||||
type GenesisRuneConfig struct {
|
||||
RuneId runes.RuneId
|
||||
Name string
|
||||
Number uint64
|
||||
Divisibility uint8
|
||||
Premine uint128.Uint128
|
||||
SpacedRune runes.SpacedRune
|
||||
Symbol rune
|
||||
Terms *runes.Terms
|
||||
Turbo bool
|
||||
EtchingTxHash chainhash.Hash
|
||||
EtchedAt time.Time
|
||||
}
|
||||
|
||||
var GenesisRuneConfigMap = map[common.Network]GenesisRuneConfig{
|
||||
common.NetworkMainnet: {
|
||||
RuneId: runes.RuneId{BlockHeight: 1, TxIndex: 0},
|
||||
Number: 0,
|
||||
Divisibility: 0,
|
||||
Premine: uint128.Zero,
|
||||
SpacedRune: runes.NewSpacedRune(runes.NewRune(2055900680524219742), 0b10000000),
|
||||
Symbol: '\u29c9',
|
||||
Terms: &runes.Terms{
|
||||
Amount: lo.ToPtr(uint128.From64(1)),
|
||||
Cap: &uint128.Max,
|
||||
HeightStart: lo.ToPtr(uint64(840000)),
|
||||
HeightEnd: lo.ToPtr(uint64(1050000)),
|
||||
OffsetStart: nil,
|
||||
OffsetEnd: nil,
|
||||
},
|
||||
Turbo: true,
|
||||
EtchingTxHash: chainhash.Hash{},
|
||||
EtchedAt: time.Time{},
|
||||
},
|
||||
common.NetworkFractalMainnet: {
|
||||
RuneId: runes.RuneId{BlockHeight: 1, TxIndex: 0},
|
||||
Number: 0,
|
||||
Divisibility: 0,
|
||||
Premine: uint128.Zero,
|
||||
SpacedRune: runes.NewSpacedRune(runes.NewRune(2055900680524219742), 0b10000000),
|
||||
Symbol: '\u29c9',
|
||||
Terms: &runes.Terms{
|
||||
Amount: lo.ToPtr(uint128.From64(1)),
|
||||
Cap: &uint128.Max,
|
||||
HeightStart: lo.ToPtr(uint64(84000)),
|
||||
HeightEnd: lo.ToPtr(uint64(2184000)),
|
||||
OffsetStart: nil,
|
||||
OffsetEnd: nil,
|
||||
},
|
||||
Turbo: true,
|
||||
EtchingTxHash: chainhash.Hash{},
|
||||
EtchedAt: time.Time{},
|
||||
},
|
||||
common.NetworkFractalTestnet: {
|
||||
RuneId: runes.RuneId{BlockHeight: 1, TxIndex: 0},
|
||||
Number: 0,
|
||||
Divisibility: 0,
|
||||
Premine: uint128.Zero,
|
||||
SpacedRune: runes.NewSpacedRune(runes.NewRune(2055900680524219742), 0b10000000),
|
||||
Symbol: '\u29c9',
|
||||
Terms: &runes.Terms{
|
||||
Amount: lo.ToPtr(uint128.From64(1)),
|
||||
Cap: &uint128.Max,
|
||||
HeightStart: lo.ToPtr(uint64(84000)),
|
||||
HeightEnd: lo.ToPtr(uint64(2184000)),
|
||||
OffsetStart: nil,
|
||||
OffsetEnd: nil,
|
||||
},
|
||||
Turbo: true,
|
||||
EtchingTxHash: chainhash.Hash{},
|
||||
EtchedAt: time.Time{},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,6 @@ import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
||||
"github.com/btcsuite/btcd/wire"
|
||||
"github.com/cockroachdb/errors"
|
||||
"github.com/gaze-network/indexer-network/common"
|
||||
@@ -20,7 +19,6 @@ import (
|
||||
"github.com/gaze-network/indexer-network/pkg/logger/slogx"
|
||||
"github.com/gaze-network/indexer-network/pkg/reportingclient"
|
||||
"github.com/gaze-network/uint128"
|
||||
"github.com/samber/lo"
|
||||
)
|
||||
|
||||
// Make sure to implement the Bitcoin Processor interface
|
||||
@@ -120,39 +118,34 @@ func (p *Processor) ensureValidState(ctx context.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
var genesisRuneId = runes.RuneId{BlockHeight: 1, TxIndex: 0}
|
||||
|
||||
func (p *Processor) ensureGenesisRune(ctx context.Context, network common.Network) error {
|
||||
_, err := p.runesDg.GetRuneEntryByRuneId(ctx, genesisRuneId)
|
||||
genesisRuneConfig, ok := constants.GenesisRuneConfigMap[network]
|
||||
if !ok {
|
||||
logger.Panic("genesis rune config not found", slogx.Stringer("network", network))
|
||||
}
|
||||
_, err := p.runesDg.GetRuneEntryByRuneId(ctx, genesisRuneConfig.RuneId)
|
||||
if err != nil && !errors.Is(err, errs.NotFound) {
|
||||
return errors.Wrap(err, "failed to get genesis rune entry")
|
||||
}
|
||||
if errors.Is(err, errs.NotFound) {
|
||||
runeEntry := &runes.RuneEntry{
|
||||
RuneId: genesisRuneId,
|
||||
Number: 0,
|
||||
Divisibility: 0,
|
||||
Premine: uint128.Zero,
|
||||
SpacedRune: runes.NewSpacedRune(runes.NewRune(2055900680524219742), 0b10000000),
|
||||
Symbol: '\u29c9',
|
||||
Terms: &runes.Terms{
|
||||
Amount: lo.ToPtr(uint128.From64(1)),
|
||||
Cap: &uint128.Max,
|
||||
HeightStart: lo.ToPtr(network.HalvingInterval() * 4),
|
||||
HeightEnd: lo.ToPtr(network.HalvingInterval() * 5),
|
||||
OffsetStart: nil,
|
||||
OffsetEnd: nil,
|
||||
},
|
||||
Turbo: true,
|
||||
RuneId: genesisRuneConfig.RuneId,
|
||||
Number: genesisRuneConfig.Number,
|
||||
Divisibility: genesisRuneConfig.Divisibility,
|
||||
Premine: genesisRuneConfig.Premine,
|
||||
SpacedRune: genesisRuneConfig.SpacedRune,
|
||||
Symbol: genesisRuneConfig.Symbol,
|
||||
Terms: genesisRuneConfig.Terms,
|
||||
Turbo: genesisRuneConfig.Turbo,
|
||||
Mints: uint128.Zero,
|
||||
BurnedAmount: uint128.Zero,
|
||||
CompletedAt: time.Time{},
|
||||
CompletedAtHeight: nil,
|
||||
EtchingBlock: 1,
|
||||
EtchingTxHash: chainhash.Hash{},
|
||||
EtchedAt: time.Time{},
|
||||
EtchingBlock: genesisRuneConfig.RuneId.BlockHeight,
|
||||
EtchingTxHash: genesisRuneConfig.EtchingTxHash,
|
||||
EtchedAt: genesisRuneConfig.EtchedAt,
|
||||
}
|
||||
if err := p.runesDg.CreateRuneEntry(ctx, runeEntry, genesisRuneId.BlockHeight); err != nil {
|
||||
if err := p.runesDg.CreateRuneEntry(ctx, runeEntry, genesisRuneConfig.RuneId.BlockHeight); err != nil {
|
||||
return errors.Wrap(err, "failed to create genesis rune entry")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -691,7 +691,7 @@ func (p *Processor) flushBlock(ctx context.Context, blockHeader types.BlockHeade
|
||||
if err != nil && errors.Is(err, errs.NotFound) && blockHeader.Height-1 == constants.StartingBlockHeader[p.network].Height {
|
||||
prevIndexedBlock = &entity.IndexedBlock{
|
||||
Height: constants.StartingBlockHeader[p.network].Height,
|
||||
Hash: constants.StartingBlockHeader[p.network].Hash,
|
||||
Hash: chainhash.Hash{},
|
||||
EventHash: chainhash.Hash{},
|
||||
CumulativeEventHash: chainhash.Hash{},
|
||||
}
|
||||
|
||||
@@ -24,7 +24,11 @@ func VerifySignature(address string, message string, sigBase64 string, defaultNe
|
||||
return nil
|
||||
}
|
||||
|
||||
func SignTxInput(tx *wire.MsgTx, privateKey *btcec.PrivateKey, prevTxOut *wire.TxOut, inputIndex int) (*wire.MsgTx, error) {
|
||||
type SignTxInputOptions struct {
|
||||
SigHashType txscript.SigHashType
|
||||
}
|
||||
|
||||
func SignTxInput(tx *wire.MsgTx, privateKey *btcec.PrivateKey, prevTxOut *wire.TxOut, inputIndex int, options ...SignTxInputOptions) (*wire.MsgTx, error) {
|
||||
if privateKey == nil {
|
||||
return nil, errors.Wrap(errs.InvalidArgument, "PrivateKey is required")
|
||||
}
|
||||
@@ -35,6 +39,14 @@ func SignTxInput(tx *wire.MsgTx, privateKey *btcec.PrivateKey, prevTxOut *wire.T
|
||||
return nil, errors.Wrap(errs.InvalidArgument, "PrevTxOut is required")
|
||||
}
|
||||
|
||||
// defaults sigHashType to SigHashAll | SigHashAnyOneCanPay
|
||||
if len(options) == 0 {
|
||||
options = append(options, SignTxInputOptions{
|
||||
SigHashType: txscript.SigHashAll | txscript.SigHashAnyOneCanPay,
|
||||
})
|
||||
}
|
||||
sigHashType := options[0].SigHashType
|
||||
|
||||
prevOutFetcher := txscript.NewCannedPrevOutputFetcher(prevTxOut.PkScript, prevTxOut.Value)
|
||||
sigHashes := txscript.NewTxSigHashes(tx, prevOutFetcher)
|
||||
if len(tx.TxIn) <= inputIndex {
|
||||
@@ -53,7 +65,7 @@ func SignTxInput(tx *wire.MsgTx, privateKey *btcec.PrivateKey, prevTxOut *wire.T
|
||||
inputIndex,
|
||||
prevTxOut.Value,
|
||||
prevTxOut.PkScript,
|
||||
txscript.SigHashAll|txscript.SigHashAnyOneCanPay,
|
||||
sigHashType,
|
||||
privateKey)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to sign")
|
||||
@@ -66,7 +78,7 @@ func SignTxInput(tx *wire.MsgTx, privateKey *btcec.PrivateKey, prevTxOut *wire.T
|
||||
inputIndex,
|
||||
prevTxOut.Value,
|
||||
prevTxOut.PkScript,
|
||||
txscript.SigHashAll|txscript.SigHashAnyOneCanPay,
|
||||
sigHashType,
|
||||
privateKey,
|
||||
true,
|
||||
)
|
||||
@@ -79,7 +91,7 @@ func SignTxInput(tx *wire.MsgTx, privateKey *btcec.PrivateKey, prevTxOut *wire.T
|
||||
tx,
|
||||
inputIndex,
|
||||
prevTxOut.PkScript,
|
||||
txscript.SigHashAll|txscript.SigHashAnyOneCanPay,
|
||||
sigHashType,
|
||||
privateKey,
|
||||
true,
|
||||
)
|
||||
|
||||
@@ -163,6 +163,7 @@ func TestSignTxInput(t *testing.T) {
|
||||
AddOp(txscript.OP_0).
|
||||
AddData(pubKeyHash).
|
||||
Script()
|
||||
require.NoError(t, err)
|
||||
|
||||
tx, prevTxOut := generateTxAndPrevTxOutFromPkScript(pkScript)
|
||||
signedTx, err := SignTxInput(
|
||||
@@ -175,7 +176,9 @@ func TestSignTxInput(t *testing.T) {
|
||||
pubKey := privKey.PubKey()
|
||||
pubKeyHash := btcutil.Hash160(pubKey.SerializeCompressed())
|
||||
address, err := btcutil.NewAddressPubKeyHash(pubKeyHash, &chaincfg.MainNetParams)
|
||||
require.NoError(t, err)
|
||||
pkScript, err := txscript.PayToAddrScript(address)
|
||||
require.NoError(t, err)
|
||||
|
||||
tx, prevTxOut := generateTxAndPrevTxOutFromPkScript(pkScript)
|
||||
signedTx, err := SignTxInput(
|
||||
@@ -184,4 +187,61 @@ func TestSignTxInput(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
verifySignedTx(t, signedTx, prevTxOut)
|
||||
})
|
||||
t.Run("custom sighash type", func(t *testing.T) {
|
||||
pubKey := privKey.PubKey()
|
||||
pubKeyHash := btcutil.Hash160(pubKey.SerializeCompressed())
|
||||
|
||||
pkScript, err := txscript.NewScriptBuilder().
|
||||
AddOp(txscript.OP_0).
|
||||
AddData(pubKeyHash).
|
||||
Script()
|
||||
require.NoError(t, err)
|
||||
|
||||
tx, prevTxOut := generateTxAndPrevTxOutFromPkScript(pkScript)
|
||||
|
||||
sigHashTypes := []txscript.SigHashType{
|
||||
txscript.SigHashAll,
|
||||
txscript.SigHashNone,
|
||||
txscript.SigHashSingle,
|
||||
txscript.SigHashAll | txscript.SigHashAnyOneCanPay,
|
||||
txscript.SigHashNone | txscript.SigHashAnyOneCanPay,
|
||||
txscript.SigHashSingle | txscript.SigHashAnyOneCanPay,
|
||||
}
|
||||
for _, sigHashType := range sigHashTypes {
|
||||
signedTx, err := SignTxInput(
|
||||
tx, privKey, prevTxOut, 0, SignTxInputOptions{
|
||||
SigHashType: sigHashType,
|
||||
},
|
||||
)
|
||||
require.NoError(t, err)
|
||||
verifySignedTx(t, signedTx, prevTxOut)
|
||||
|
||||
// check last byte of signature equals to sigHashType
|
||||
signature := signedTx.TxIn[0].Witness[0]
|
||||
assert.Equal(t, sigHashType, txscript.SigHashType(signature[len(signature)-1]))
|
||||
}
|
||||
})
|
||||
t.Run("default sighash type", func(t *testing.T) {
|
||||
pubKey := privKey.PubKey()
|
||||
pubKeyHash := btcutil.Hash160(pubKey.SerializeCompressed())
|
||||
|
||||
pkScript, err := txscript.NewScriptBuilder().
|
||||
AddOp(txscript.OP_0).
|
||||
AddData(pubKeyHash).
|
||||
Script()
|
||||
require.NoError(t, err)
|
||||
|
||||
tx, prevTxOut := generateTxAndPrevTxOutFromPkScript(pkScript)
|
||||
|
||||
signedTx, err := SignTxInput(
|
||||
tx, privKey, prevTxOut, 0,
|
||||
)
|
||||
require.NoError(t, err)
|
||||
verifySignedTx(t, signedTx, prevTxOut)
|
||||
|
||||
// check last byte of signature equals to sigHashType
|
||||
signature := signedTx.TxIn[0].Witness[0]
|
||||
expected := txscript.SigHashAll | txscript.SigHashAnyOneCanPay
|
||||
assert.Equal(t, expected, txscript.SigHashType(signature[len(signature)-1]))
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user