Skip to content

Commit

Permalink
contrib: add signet scripts (issuer, etc)
Browse files Browse the repository at this point in the history
  • Loading branch information
kallewoof committed Jan 15, 2020
1 parent 1a8c3a1 commit a3f7b59
Show file tree
Hide file tree
Showing 10 changed files with 480 additions and 1 deletion.
60 changes: 60 additions & 0 deletions contrib/signet/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
Contents
========
This directory contains tools related to Signet, both for running a Signet yourself and for using one.

The `args.sh` script is a helper script used by the other scripts and should not be invoked directly.

getcoins.sh
===========

A script to call a faucet to get Signet coins.

Syntax: `getcoins.sh [--help] [--cmd=<bitcoin-cli path>] [--faucet=<faucet URL>] [--addr=<signet bech32 address>] [--password=<faucet password>] [--] [<bitcoin-cli args>]`

* `--cmd` lets you customize the bitcoin-cli path. By default it will look for it in the PATH, then in `../../src/`
* `--faucet` lets you specify which faucet to use; the faucet is assumed to be compatible with https://github.com/kallewoof/bitcoin-faucet
* `--addr` lets you specify a Signet address; by default, the address must be a bech32 address. This and `--cmd` above complement each other (i.e. you do not need `bitcoin-cli` if you use `--addr`)
* `--password` lets you specify a faucet password; this is handy if you are in a classroom and set up your own faucet for your students; (above faucet does not limit by IP when password is enabled)

If using the default network, invoking the script with no arguments should be sufficient under normal
circumstances, but if multiple people are behind the same IP address, the faucet will by default only
accept one claim per day. See `--password` above.

issuer.sh
=========

A script to regularly issue Signet blocks.

Syntax: `issuer.sh <idle time> [--help] [--cmd=<bitcoin-cli path>] [--] [<bitcoin-cli args>]`

* `<idle time>` is a time in seconds to wait between each block generation
* `--cmd` lets you customize the bitcoin-cli path. By default it will look for it in the PATH, then in `../../src/`

Signet, just like other bitcoin networks, uses proof of work alongside the block signature; this
includes the difficulty adjustment every 2016 blocks.
The `<idle time>` exists to allow you to maintain a relatively low difficulty over an extended period
of time. E.g. an idle time of 540 means your node will end up spending roughly 1 minute grinding
hashes for each block, and wait 9 minutes after every time.

mkblock.sh
==========

A script to generate one Signet block.

Syntax: `mkblock.sh <bitcoin-cli path> [<bitcoin-cli args>]`

This script is called by the other block issuing scripts, but can be invoked independently to generate
1 block immediately.

secondary.sh
============

A script to act as backup generator in case the primary issuer goes offline.

Syntax: `secondary.sh <trigger time> <idle time> [--cmd=<bitcoin-cli path>] [<bitcoin-cli args>]`

* `<trigger time>` is the time in seconds that must have passed since the last block was seen for the secondary issuer to kick into motion
* `<idle time>` is the time in seconds to wait after generating a block, and should preferably be the same as the idle time of the main issuer

Running a Signet network, it is recommended to have at least one secondary running in a different
place, so it doesn't go down together with the main issuer.
57 changes: 57 additions & 0 deletions contrib/signet/addtxtoblock.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
#!/usr/bin/env python3
# Copyright (c) 2019-2020 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.

import sys
import os
import argparse

# dirty hack but makes CBlock etc available
sys.path.append('/'.join(os.getcwd().split('/')[:-2]) + '/test/functional')

from test_framework.messages import (
CBlock,
CTransaction,
FromHex,
ToHex,
)

from test_framework.blocktools import add_witness_commitment

def main():

# Parse arguments and pass through unrecognised args
parser = argparse.ArgumentParser(add_help=False,
usage='%(prog)s [addtxtoblock options] [bitcoin block file] [tx file] [fee]',
description=__doc__,
epilog='''Help text and arguments:''',
formatter_class=argparse.RawTextHelpFormatter)
_, unknown_args = parser.parse_known_args()

if len(unknown_args) != 3:
print("Need three arguments (block file, tx file, and fee)")
sys.exit(1)

[blockfile, txfile, feestr] = unknown_args

with open(blockfile, "r", encoding="utf8") as f:
blockhex = f.read().strip()
with open(txfile, "r", encoding="utf8") as f:
txhex = f.read().strip()

fee = int(feestr)

block = CBlock()
FromHex(block, blockhex)

tx = CTransaction()
FromHex(tx, txhex)

block.vtx[0].vout[0].nValue += fee
block.vtx.append(tx)
add_witness_commitment(block)
print(ToHex(block))

if __name__ == '__main__':
main()
55 changes: 55 additions & 0 deletions contrib/signet/args.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
#!/usr/bin/env bash
# Copyright (c) 2019-2020 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.

export LC_ALL=C

args="-signet"
eoc=

command -v bitcoin-cli > /dev/null \
&& bcli="bitcoin-cli" \
|| bcli="$(dirname $0)/../../src/bitcoin-cli"

if [ "$VARCHECKS" = "" ]; then
VARCHECKS='if [ "$varname" = "cmd" ]; then bcli=$value;'
fi

# compatibility; previously the bitcoin-cli path was given as first argument
if [[ "$1" != "" && "${1:$((${#1}-11))}" = "bitcoin-cli" ]]; then
echo "using $1 as bcli"
bcli=$1
shift
fi

for i in "$@"; do
if [ $eoc ]; then
args="$args $i"
elif [ "$i" = "--" ]; then
# end of commands; rest into args for bitcoin-cli
eoc=1
continue
elif [ "${i:0:2}" = "--" ]; then
# command
j=${i:2}
if [ "$j" = "help" ]; then
>&2 echo -e $HELPSTRING
exit 1
fi
export varname=${j%=*}
export value=${j#*=}
eval $VARCHECKS '
else
>&2 echo "unknown parameter $varname (from \"$i\"); for help, type: $0 --help"
exit 1
fi'
else
# arg
args="$args $i"
fi
done

if ! [ -e "$bcli" ]; then
command -v "$bcli" >/dev/null 2>&1 || { echo >&2 "error: unable to find bitcoin-cli binary: $bcli"; exit 1; }
fi
74 changes: 74 additions & 0 deletions contrib/signet/forker.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
#!/usr/bin/env bash
# Copyright (c) 2019-2020 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.

export LC_ALL=C

#
# Take the hex formatted line separated transactions in reorg-list.txt where every even transaction is put into the even set, and every odd transaction is put into the odd set.
# That is, transactions on line 1, 3, 5, 7, ... go into the odd set, and transactions on line 2, 4, 6, 8, ... go into the even set.
#
# - Generate two blocks A and B, where A contains all or some of the odd set, and B contains the corresponding even set.
# - Sign, grind, and broadcast block A
# - Wait a random amount of time (1-10 mins)
# - Invalidate block A
# - Sign, grind, and broadcast block B
#

bcli=$1
shift

function log()
{
echo "- $(date +%H:%M:%S): $*"
}

if [ ! -e "reorg-list.txt" ]; then
echo "reorg-list.txt not found"
exit 1
fi

# get address for coinbase output
addr=$($bcli "$@" getnewaddress)

# create blocks A and B
$bcli "$@" getnewblockhex $addr > $PWD/block-a
cp block-a block-b

odd=1
while read -r line; do
if [ "$line" = "" ]; then continue; fi
echo $line > tx
if [ $odd -eq 1 ]; then blk="block-a"; else blk="block-b"; fi
./addtxtoblock.py $blk tx 100 > t # note: we are throwing away all fees above 100 satoshis for now; should figure out a way to determine fees
mv t $blk
(( odd=1-odd ))
done < reorg-list.txt

rm reorg-list.txt

log "mining block A (to-orphan block)"
while true; do
$bcli "$@" signblock $PWD/block-a > signed-a
blockhash_a=$($bcli "$@" grindblock $PWD/signed-a 1000000000)
if [ "$blockhash_a" != "false" ]; then break; fi
done
log "mined block with hash $blockhash_a"
(( waittime=RANDOM%570 ))
(( waittime=30+waittime ))
log "waiting for $waittime s"
sleep $waittime
log "invalidating $blockhash_a"
$bcli "$@" invalidateblock $blockhash_a

log "mining block B (replace block)"
while true; do
$bcli "$@" signblock $PWD/block-b > signed-b
blockhash_b=$($bcli "$@" grindblock $PWD/signed-b 1000000000)
if [ "$blockhash_b" != "false" ]; then break; fi
done

echo "mined $blockhash_b"
echo "cleaning up"
rm block-b signed-b block-a signed-a
43 changes: 43 additions & 0 deletions contrib/signet/getcoins.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
#!/usr/bin/env bash
# Copyright (c) 2019-2020 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.

export LC_ALL=C

#
# Get coins from Signet Faucet
#

export VARCHECKS='
if [ "$varname" = "cmd" ]; then
bcli=$value;
elif [ "$varname" = "faucet" ]; then
faucet=$value;
elif [ "$varname" = "addr" ]; then
addr=$value;
elif [ "$varname" = "password" ]; then
password=$value;
'
export HELPSTRING="syntax: $0 [--help] [--cmd=<bitcoin-cli path>] [--faucet=<faucet URL>] [--addr=<signet bech32 address>] [--password=<faucet password>] [--] [<bitcoin-cli args>]"

bcli=
args=
password=
addr=
faucet="https://signet.bc-2.jp/claim"

# shellcheck source=contrib/signet/args.sh
source $(dirname $0)/args.sh "$@"

if [ "$addr" = "" ]; then
# get address for receiving coins
addr=$($bcli $args getnewaddress faucet bech32) || { echo >&2 "for help, type: $0 --help"; exit 1; }
fi

# shellcheck disable=SC2015
command -v "curl" > /dev/null \
&& curl -X POST -d "address=$addr&password=$password" $faucet \
|| wget -qO - --post-data "address=$addr&password=$password" $faucet

echo
60 changes: 60 additions & 0 deletions contrib/signet/issuer.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
#!/usr/bin/env bash
# Copyright (c) 2019-2020 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.

export LC_ALL=C

#
# Issue blocks using a local node at a given interval.
#

export HELPSTRING="syntax: $0 <idle time> [--help] [--cmd=<bitcoin-cli path>] [--] [<bitcoin-cli args>]"

if [ $# -lt 1 ]; then
echo $HELPSTRING
exit 1
fi

function log()
{
echo "- $(date +%H:%M:%S): $*"
}

idletime=$1
shift

bcli=
args=

# shellcheck source=contrib/signet/args.sh
source $(dirname $0)/args.sh "$@"

MKBLOCK=$(dirname $0)/mkblock.sh

if [ ! -e "$MKBLOCK" ]; then
>&2 echo "error: cannot locate mkblock.sh (expected to find in $MKBLOCK"
exit 1
fi

echo "- checking node status"
conns=$($bcli $args getconnectioncount) || { echo >&2 "node error"; exit 1; }

if [ $conns -lt 1 ]; then
echo "warning: node is not connected to any other node"
fi

log "node OK with $conns connection(s)"
log "mining at maximum capacity with $idletime second delay between each block"
log "hit ^C to stop"

while true; do
if [ -e "reorg-list.txt" ]; then
./forker.sh $bcli $args
else
log "generating next block"
blockhash=$("$MKBLOCK" "$bcli" $args) || { echo "node error; aborting" ; exit 1; }
log "mined block $($bcli $args getblockcount) $blockhash to $($bcli $args getconnectioncount) peer(s); idling for $idletime seconds"
fi
sleep $idletime
done
37 changes: 37 additions & 0 deletions contrib/signet/mkblock.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
#!/usr/bin/env bash
# Copyright (c) 2019-2020 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.

export LC_ALL=C

#
# Generate a block
#

if [ $# -lt 1 ]; then
>&2 echo "syntax: $0 <bitcoin-cli path> [<bitcoin-cli args>]" ; exit 1
fi

bcli=$1
shift

if ! [ -e "$bcli" ]; then
command -v "$bcli" >/dev/null 2>&1 || { echo >&2 "error: unable to find bitcoin binary: $bcli"; exit 1; }
fi

# get address for coinbase output
addr=$($bcli "$@" getnewaddress)
# start looping; we re-create the block every time we fail to grind as that resets the nonce and gives us an updated
# version of the block
while true; do
# create an unsigned, un-PoW'd block
$bcli "$@" getnewblockhex $addr > $PWD/unsigned
# sign it
$bcli "$@" signblock $PWD/unsigned > $PWD/signed
# grind proof of work; this ends up broadcasting the block, if successful (akin to "generatetoaddress")
blockhash=$($bcli "$@" grindblock $PWD/signed 10000000)
if [ "$blockhash" != "false" ]; then break; fi
done

echo $blockhash
Loading

0 comments on commit a3f7b59

Please sign in to comment.