Skip to content

Commit

Permalink
Merge pull request #20 from keep-network/testnet-readiness
Browse files Browse the repository at this point in the history
Testnet-ready end-to-end test script
  • Loading branch information
nkuba authored Aug 7, 2020
2 parents d0efb57 + 832166b commit 0bb27c3
Show file tree
Hide file tree
Showing 12 changed files with 332 additions and 54 deletions.
2 changes: 1 addition & 1 deletion bitcoin/bitcoind/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
FROM ubuntu:18.04

RUN apt-get update && apt-get install -y wget && rm -rf /var/lib/apt/lists/*
RUN apt-get update && apt-get install -y wget jq && rm -rf /var/lib/apt/lists/*

RUN wget -O bitcoin-core.tar.gz https://bitcoin.org/bin/bitcoin-core-0.20.0/bitcoin-0.20.0-x86_64-linux-gnu.tar.gz
RUN mkdir /bitcoin-core && tar -xzf bitcoin-core.tar.gz -C /bitcoin-core --strip-components=1
Expand Down
9 changes: 7 additions & 2 deletions bitcoin/bitcoind/entrypoint.sh
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,13 @@ sleep 10

alias btccli='./bitcoin-cli -regtest -datadir=datadir -rpcport=18332 -rpcuser=user -rpcpassword=password'

# Get an address.
address=$(btccli getnewaddress)
# Use a specific private key.
privateKey="cTj6Z9fxMr4pzfpUhiN8KssVzZjgQz9zFCfh87UrH8ZLjh3hGZKF"

btccli importprivkey "$privateKey" "main"

# Get the imported address. It should start with `bcrt1` because this is the right prefix for the regtest network.
address=$(btccli getaddressesbylabel "main" | jq -r 'with_entries(select(.key | startswith("bcrt1"))) | 'keys[0]'')

# Mine some initial blocks to unlock coinbase.
btccli generatetoaddress 1000 "$address"
Expand Down
2 changes: 2 additions & 0 deletions bitcoin/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,6 @@ services:
- COIN=BitcoinSegwit
- NET=regtest
- SERVICES=tcp://0.0.0.0:50001,ssl://0.0.0.0:50002,ws://0.0.0.0:50003,wss://127.0.0.1:50004,rpc://0.0.0.0:8000
- COST_SOFT_LIMIT=0
- COST_HARD_LIMIT=0
build: ./electrumx
10 changes: 10 additions & 0 deletions deployments/e2e-test/e2e-test-configmap.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: e2e-test-config
namespace: default
data:
bitcoin-electrum-host: "34.70.251.19"
bitcoin-electrum-port: "8080"
bitcoin-network: "testnet"
ethereum-node: "wss://ropsten.infura.io/ws/v3/880f2a054e784898a55627bd5f047917"
64 changes: 64 additions & 0 deletions deployments/e2e-test/e2e-test-cronjob.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
apiVersion: batch/v1beta1
kind: CronJob
metadata:
name: e2e-test
namespace: default
labels:
app: tbtc
type: e2e-test
spec:
schedule: '0 */4 * * *'
concurrencyPolicy: Forbid
jobTemplate:
metadata:
labels:
app: tbtc
type: e2e-test
spec:
backoffLimit: 0
activeDeadlineSeconds: 3600
template:
spec:
containers:
- name: e2e-test
image: gcr.io/keep-test-f3e0/e2e-test
args: [
"--bitcoin-electrum-host", "$(BITCOIN_ELECTRUM_HOST)",
"--bitcoin-electrum-port", "$(BITCOIN_ELECTRUM_PORT)",
"--bitcoin-network", "$(BITCOIN_NETWORK)",
"--bitcoin-depositor-pk", "$(BITCOIN_DEPOSITOR_PK)",
"--ethereum-node", "$(ETHEREUM_NODE)",
"--ethereum-pk", "$(ETHEREUM_PK)"
]
env:
- name: BITCOIN_ELECTRUM_HOST
valueFrom:
configMapKeyRef:
name: e2e-test-config
key: bitcoin-electrum-host
- name: BITCOIN_ELECTRUM_PORT
valueFrom:
configMapKeyRef:
name: e2e-test-config
key: bitcoin-electrum-port
- name: BITCOIN_NETWORK
valueFrom:
configMapKeyRef:
name: e2e-test-config
key: bitcoin-network
- name: BITCOIN_DEPOSITOR_PK
valueFrom:
secretKeyRef:
name: e2e-test-secret
key: bitcoin-depositor-pk
- name: ETHEREUM_NODE
valueFrom:
configMapKeyRef:
name: e2e-test-config
key: ethereum-node
- name: ETHEREUM_PK
valueFrom:
secretKeyRef:
name: e2e-test-secret
key: ethereum-pk
restartPolicy: Never
9 changes: 9 additions & 0 deletions deployments/e2e-test/e2e-test-secret.yml.SAMPLE
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
apiVersion: v1
kind: Secret
metadata:
name: e2e-test-secret
namespace: default
type: Opaque
data:
bitcoin-depositor-pk: "base64 encoded Bitcoin depositor private key WIF"
ethereum-pk: "base64 encoded Ethereum account private key"
1 change: 1 addition & 0 deletions e2e/.dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
node_modules
22 changes: 22 additions & 0 deletions e2e/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
FROM node:14.3.0-alpine3.11

ENV TBTCJS_VERSION 0.17.0-rc.1

RUN apk add --no-cache \
jq \
git \
python3 \
build-base

WORKDIR /e2e

COPY . .

RUN jq '.dependencies."@keep-network/tbtc.js" = env.TBTCJS_VERSION' \
package.json > package.json.tmp && mv package.json.tmp package.json

RUN npm install

ENTRYPOINT ["node", "--experimental-json-modules", "e2e-test.js"]

CMD []
20 changes: 11 additions & 9 deletions e2e/assertions.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {getTBTCTokenBalance, getReceivedBtcAmount} from "./common.js";
import {getTBTCTokenBalance, getBtcBalance} from "./common.js";

export const assertMintedTbtcAmount = (web3, deposit, expectedTbtcAmount) => {
const actualTbtcAmountBn = web3.utils.toBN(deposit.tbtcAmount)
Expand Down Expand Up @@ -31,18 +31,20 @@ export const assertTbtcAccountBalance = async (
}
}

export const assertReceivedBtcAmount = async (
bitcoinRpc,
export const assertBtcBalance = async (
web3,
BitcoinHelpers,
address,
expectedReceivedBtcAmount
expectedBtcBalance
) => {
const actualReceivedBtcAmount = await getReceivedBtcAmount(bitcoinRpc, address)
const actualBtcBalanceBn = await getBtcBalance(web3, BitcoinHelpers, address)
const expectedBtcBalanceBn = web3.utils.toBN(expectedBtcBalance)

if (actualReceivedBtcAmount !== expectedReceivedBtcAmount) {
if (!actualBtcBalanceBn.eq(expectedBtcBalanceBn)) {
throw new Error(
`unexpected received BTC amount for address ${address}:
actual: ${actualReceivedBtcAmount}
expected: ${expectedReceivedBtcAmount}`
`unexpected BTC balance for address ${address}:
actual: ${actualBtcBalanceBn}
expected: ${expectedBtcBalanceBn}`
)
}
}
124 changes: 117 additions & 7 deletions e2e/common.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,126 @@ export const getTBTCTokenBalance = async (web3, tbtc, account) => {
return web3.utils.toBN(balance)
}

export const getReceivedBtcAmount = async (bitcoinRpc, address) => {
const received = (await bitcoinRpc.listreceivedbyaddressAsync(1, false, true, address)).result
export const getBtcBalance = async (web3, BitcoinHelpers, address) => {
const balance = await BitcoinHelpers.Transaction.getBalance(address);

let receivedBtcAmount = 0
return web3.utils.toBN(balance)
}

export const importBitcoinPrivateKey = async (
bcoin,
wif,
wallet, privateKey
) => {
const decodedPrivateKey = wif.decode(privateKey);

const keyRing = new bcoin.KeyRing({
witness: true,
privateKey: decodedPrivateKey.privateKey,
compressed: decodedPrivateKey.compressed
});

await wallet.importKey(0, keyRing)

return keyRing
}

export const generateBitcoinPrivateKey = async (bcoin, wallet) => {
const keyRing = bcoin.KeyRing.generate(true)
keyRing.witness = true

await wallet.importKey(0, keyRing)

return keyRing
}

export const sendBitcoinTransaction = async(
bcoin,
BitcoinHelpers,
targetAddress,
amount,
keyRing,
subtractFee = false
) => {
const sourceAddress = keyRing.getAddress("string");

console.log(`Sending transaction from ${sourceAddress} to ${targetAddress}`)

const utxos = await BitcoinHelpers.Transaction.findAllUnspent(sourceAddress)

const coins = []
let coinsAmount = 0

for (let i = 0; i < received.length; i++) {
if (received[i].address === address) {
receivedBtcAmount += received[i].amount
// Start from the oldest UTXO.
for (const utxo of utxos.reverse()) {
// Make sure the selected coins amount covers the 110% of the amount.
// The additional 10% is taken as a big reserve to make sure that input
// coins will cover the transaction fee.
if (coinsAmount >= 1.1 * amount.toNumber()) {
break
}

const tx = await BitcoinHelpers.withElectrumClient(async electrumClient => {
return electrumClient.getTransaction(utxo.transactionID)
})

coins.push(bcoin.Coin.fromTX(
bcoin.MTX.fromRaw(tx.hex, 'hex'),
utxo.outputPosition,
-1
))

coinsAmount += utxo.value
}

return receivedBtcAmount
const transaction = new bcoin.MTX()

transaction.addOutput({
script: bcoin.Script.fromAddress(targetAddress),
value: amount.toNumber(),
})

await transaction.fund(
coins,
{
rate: null, // set null explicitly to always use the default value
changeAddress: sourceAddress,
subtractFee: subtractFee
}
)

transaction.sign(keyRing)

const broadcastOutcome = await BitcoinHelpers.Transaction.broadcast(
transaction.toRaw().toString('hex')
)

console.log(`Transaction ${broadcastOutcome.transactionID} sent`)
}

export const returnBitcoinToDepositor = async (
web3,
bcoin,
BitcoinHelpers,
depositorKeyRing,
redeemerKeyRing
) => {
const redeemerBalance = await getBtcBalance(
web3,
BitcoinHelpers,
redeemerKeyRing.getAddress("string")
)

const depositorAddress = depositorKeyRing.getAddress("string")

console.log(`Returning ${redeemerBalance} satoshis to depositor ${depositorAddress}`)

await sendBitcoinTransaction(
bcoin,
BitcoinHelpers,
depositorAddress,
redeemerBalance,
redeemerKeyRing,
true
)
}
Loading

0 comments on commit 0bb27c3

Please sign in to comment.