Skip to content

Commit

Permalink
datagen: add datagen functions for testing reporter (#190)
Browse files Browse the repository at this point in the history
  • Loading branch information
SebastianElvis authored Nov 7, 2022
1 parent 9badebd commit 103dd52
Show file tree
Hide file tree
Showing 3 changed files with 192 additions and 2 deletions.
110 changes: 110 additions & 0 deletions testutil/datagen/btc_blockchain.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
package datagen

import (
"math/big"
"math/rand"

"github.com/babylonchain/babylon/btctxformatter"
"github.com/btcsuite/btcd/blockchain"
"github.com/btcsuite/btcd/chaincfg"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/wire"
)

// GenRandomBtcdBlock generates a random BTC block, which can include Babylon txs.
// Specifically,
// - when numBabylonTxs == 0 or numBabylonTxs > 2, it generates a BTC block with 3 random txs.
// - when numBabylonTxs == 1, it generates a BTC block with 2 random txs and a Babylon tx.
// - when numBabylonTxs == 2, it generates a BTC block with 1 random tx and 2 Babylon txs that constitute a raw BTC checkpoint.
// When numBabylonTxs == 2, the function will return the BTC raw checkpoint as well.
func GenRandomBtcdBlock(numBabylonTxs int, prevHash *chainhash.Hash) (*wire.MsgBlock, *btctxformatter.RawBtcCheckpoint) {
var (
randomTxs []*wire.MsgTx = []*wire.MsgTx{GenRandomTx(), GenRandomTx()}
rawCkpt *btctxformatter.RawBtcCheckpoint = nil
)

if numBabylonTxs == 2 {
randomTxs, rawCkpt = GenRandomBabylonTxPair()
} else if numBabylonTxs == 1 {
bbnTxs, _ := GenRandomBabylonTxPair()
idx := rand.Intn(2)
randomTxs[idx] = bbnTxs[idx]
}
coinbaseTx := createCoinbaseTx(rand.Int31(), &chaincfg.SimNetParams)
msgTxs := []*wire.MsgTx{coinbaseTx}
msgTxs = append(msgTxs, randomTxs...)

// calculate correct Merkle root
merkleRoot := calcMerkleRoot(msgTxs)
// don't apply any difficulty
difficulty, _ := new(big.Int).SetString("7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 16)
workBits := blockchain.BigToCompact(difficulty)

header := GenRandomBtcdHeader()
header.MerkleRoot = merkleRoot
header.Bits = workBits
if prevHash != nil {
header.PrevBlock = *prevHash
}
// find a nonce that satisfies difficulty
SolveBlock(header)

block := &wire.MsgBlock{
Header: *header,
Transactions: msgTxs,
}
return block, rawCkpt
}

// GenRandomBtcdBlockchainWithBabylonTx generates a blockchain of `n` blocks, in which each block has some probability of including some Babylon txs
// Specifically, each block
// - has `oneTxThreshold` probability of including 1 Babylon tx that does not has any match
// - has `twoTxThreshold - oneTxThreshold` probability of including 2 Babylon txs that constitute a checkpoint
// - has `1 - twoTxThreshold` probability of including no Babylon tx
func GenRandomBtcdBlockchainWithBabylonTx(n uint64, oneTxThreshold float32, twoTxThreshold float32) ([]*wire.MsgBlock, int, []*btctxformatter.RawBtcCheckpoint) {
blocks := []*wire.MsgBlock{}
numCkptSegs := 0
rawCkpts := []*btctxformatter.RawBtcCheckpoint{}
if oneTxThreshold < 0 || oneTxThreshold > 1 {
panic("oneTxThreshold should be [0, 1]")
}
if twoTxThreshold < oneTxThreshold || twoTxThreshold > 1 {
panic("fullPercentage should be [oneTxThreshold, 1]")
}
if n == 0 {
panic("n should be > 0")
}

// genesis block
genesisBlock, rawCkpt := GenRandomBtcdBlock(0, nil)
blocks = append(blocks, genesisBlock)
rawCkpts = append(rawCkpts, rawCkpt)

// blocks after genesis
for i := uint64(1); i < n; i++ {
var msgBlock *wire.MsgBlock
prevHash := blocks[len(blocks)-1].BlockHash()
if rand.Float32() < oneTxThreshold {
msgBlock, rawCkpt = GenRandomBtcdBlock(1, &prevHash)
numCkptSegs += 1
} else if rand.Float32() < twoTxThreshold {
msgBlock, rawCkpt = GenRandomBtcdBlock(2, &prevHash)
numCkptSegs += 2
} else {
msgBlock, rawCkpt = GenRandomBtcdBlock(0, &prevHash)
}

blocks = append(blocks, msgBlock)
rawCkpts = append(rawCkpts, rawCkpt)
}
return blocks, numCkptSegs, rawCkpts
}

// GenRandomBtcdHash generates a random hash in type `chainhash.Hash`, without any hash operations
func GenRandomBtcdHash() chainhash.Hash {
hash, err := chainhash.NewHashFromStr(GenRandomHexStr(32))
if err != nil {
panic(err)
}
return *hash
}
69 changes: 68 additions & 1 deletion testutil/datagen/btc_transaction.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"runtime"
"time"

"github.com/babylonchain/babylon/btctxformatter"
bbn "github.com/babylonchain/babylon/types"
btcctypes "github.com/babylonchain/babylon/x/btccheckpoint/types"
"github.com/btcsuite/btcd/blockchain"
Expand Down Expand Up @@ -315,11 +316,77 @@ func CreateBlockWithTransaction(
proof, err := btcctypes.SpvProofFromHeaderAndTransactions(headerBytes.MustMarshal(), txBytes, 1)

if err != nil {
panic("couldnt calculate prroof")
panic("could not calculate proof")
}

return &BtcHeaderWithProof{
HeaderBytes: headerBytes,
SpvProof: proof,
}
}

func GenRandomTx() *wire.MsgTx {
// structure of the below tx is from https://github.com/btcsuite/btcd/blob/master/wire/msgtx_test.go
tx := &wire.MsgTx{
Version: 1,
TxIn: []*wire.TxIn{
{
PreviousOutPoint: wire.OutPoint{
Hash: GenRandomBtcdHash(),
Index: rand.Uint32(),
},
SignatureScript: GenRandomByteArray(10),
Sequence: rand.Uint32(),
},
},
TxOut: []*wire.TxOut{
{
Value: rand.Int63(),
PkScript: GenRandomByteArray(80),
},
},
LockTime: 0,
}

return tx
}

func GenRandomBabylonTxPair() ([]*wire.MsgTx, *btctxformatter.RawBtcCheckpoint) {
txs := []*wire.MsgTx{GenRandomTx(), GenRandomTx()}
builder := txscript.NewScriptBuilder()

// fake a raw checkpoint
rawBTCCkpt := GetRandomRawBtcCheckpoint()
// encode raw checkpoint to two halves
firstHalf, secondHalf, err := btctxformatter.EncodeCheckpointData(
btctxformatter.TestTag(48), // TODO: randomise the tag ID
btctxformatter.CurrentVersion,
rawBTCCkpt,
)
if err != nil {
panic(err)
}

dataScript1, err := builder.AddOp(txscript.OP_RETURN).AddData(firstHalf).Script()
if err != nil {
panic(err)
}
txs[0].TxOut[0] = wire.NewTxOut(0, dataScript1)

// reset builder
builder = txscript.NewScriptBuilder()

dataScript2, err := builder.AddOp(txscript.OP_RETURN).AddData(secondHalf).Script()
if err != nil {
panic(err)
}
txs[1].TxOut[0] = wire.NewTxOut(0, dataScript2)

return txs, rawBTCCkpt
}

func GenRandomBabylonTx() *wire.MsgTx {
txs, _ := GenRandomBabylonTxPair()
idx := rand.Intn(2)
return txs[idx]
}
15 changes: 14 additions & 1 deletion testutil/datagen/raw_checkpoint.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,25 @@
package datagen

import (
"math/rand"

"github.com/babylonchain/babylon/btctxformatter"
"github.com/babylonchain/babylon/crypto/bls12381"
"github.com/babylonchain/babylon/x/checkpointing/types"
"github.com/boljen/go-bitmap"
"math/rand"
)

func GetRandomRawBtcCheckpoint() *btctxformatter.RawBtcCheckpoint {
rawCkpt := GenRandomRawCheckpoint()
return &btctxformatter.RawBtcCheckpoint{
Epoch: rawCkpt.EpochNum,
LastCommitHash: *rawCkpt.LastCommitHash,
BitMap: rawCkpt.Bitmap,
SubmitterAddress: GenRandomByteArray(btctxformatter.AddressLength),
BlsSig: rawCkpt.BlsMultiSig.Bytes(),
}
}

func GenRandomRawCheckpointWithMeta() *types.RawCheckpointWithMeta {
ckptWithMeta := &types.RawCheckpointWithMeta{
Ckpt: GenRandomRawCheckpoint(),
Expand Down

0 comments on commit 103dd52

Please sign in to comment.