-
Notifications
You must be signed in to change notification settings - Fork 31
Bitcoin SPV, Funding Proof and Electrum Client #8
Changes from all commits
ac441e2
18b8a7e
3ef3857
8cfd877
2651ff8
811af2d
38a74a6
be35a6a
79cede8
faeb58b
7899a95
95c81ff
c909fa8
c82cc2c
5eccbea
15b2517
4502cd7
1700fcf
05c262a
852f091
9838f60
e22ecc9
b69025b
56b1602
e25f475
3b86872
c101d81
0a5c26b
f11e0a3
535c9d5
bf4e03c
129d115
db7e7f9
7cf4471
68b0fe0
9ea6d93
cbe5d6c
253756e
c0917b4
d7400c2
4aa6a47
5b2860e
2b65fd8
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
node_modules/ | ||
*.code-workspace |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
{ | ||
"extends": "eslint-config-keep", | ||
"parserOptions": { | ||
"ecmaVersion": 2017, | ||
"sourceType": "module" | ||
}, | ||
"env": { | ||
"es6": true, | ||
"mocha": true | ||
}, | ||
"rules": { | ||
"semi": [ | ||
2, | ||
"never" | ||
] | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
{ | ||
"electrum": { | ||
"testnet": { | ||
"server": "electrumx-server.tbtc.svc.cluster.local", | ||
"port": 50002, | ||
"protocol": "tls" | ||
} | ||
} | ||
} |
Large diffs are not rendered by default.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
{ | ||
"name": "tbtc-client", | ||
"version": "0.0.1", | ||
"description": "", | ||
"scripts": { | ||
"test": "CONFIG_FILE=${npm_package_config_file} mocha --timeout 5000", | ||
"js:lint": "eslint .", | ||
"js:lint:fix": "eslint --fix ." | ||
}, | ||
"config": { | ||
"file": "./config/config.json" | ||
}, | ||
"author": "Jakub Nowakowski <[email protected]>", | ||
"license": "ISC", | ||
"dependencies": { | ||
"tbtc-helpers": "file:../lib/tbtc-helpers" | ||
}, | ||
"devDependencies": { | ||
"chai": "^4.2.0", | ||
"fs": "0.0.1-security", | ||
"mocha": "^6.2.0", | ||
"rewire": "^4.0.1", | ||
"eslint": "^5.16.0", | ||
"eslint-config-keep": "git+https://github.com/keep-network/eslint-config-keep.git#0.2.0" | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
// PAGE 1: MAKE A DEPOSIT | ||
liamzebedee marked this conversation as resolved.
Show resolved
Hide resolved
|
||
async function createDeposit() { | ||
// TODO: Implement: | ||
// Call the deposit factory to get a new deposit | ||
// return the deposit address. | ||
} | ||
|
||
// PAGE 2: PUT A BOND | ||
async function initializeDeposit(depositAddress) { | ||
// TODO: Implement: | ||
// 1. Call deposit to create new keep | ||
// 2. Watch for ECDSAKeepCreated event from ECDSAKeepFactory contract | ||
// 3. call get public key | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
const BitcoinTxParser = require('tbtc-helpers').BitcoinTxParser | ||
const bitcoinSPV = require('tbtc-helpers').BitcoinSPV | ||
const ElectrumClient = require('tbtc-helpers').ElectrumClient | ||
|
||
const fs = require('fs') | ||
|
||
/** | ||
* Reads electrum client configuration details from a config file. | ||
* @param {string} configFilePath Path to the configuration file. | ||
* @return {ElectrumClient.Config} Electrum client configuration. | ||
*/ | ||
function readElectrumConfig(configFilePath) { | ||
const configFile = fs.readFileSync(configFilePath, 'utf8') | ||
liamzebedee marked this conversation as resolved.
Show resolved
Hide resolved
|
||
config = JSON.parse(configFile) | ||
|
||
return new ElectrumClient.Config( | ||
config.electrum.testnet.server, | ||
config.electrum.testnet.port, | ||
config.electrum.testnet.protocol | ||
) | ||
} | ||
|
||
const electrumConfig = readElectrumConfig(process.env.CONFIG_FILE) | ||
|
||
/** | ||
* Gets transaction SPV proof from BitcoinSPV. | ||
* @param {string} txID Transaction ID | ||
* @param {number} confirmations Required number of confirmations | ||
*/ | ||
async function getTransactionProof(txID, confirmations) { | ||
bitcoinSPV.initialize(electrumConfig) | ||
|
||
const spvProof = await bitcoinSPV.getTransactionProof(txID, confirmations) | ||
.catch((err) => { | ||
bitcoinSPV.close() | ||
return Promise.reject(new Error(`failed to get bitcoin spv proof: ${err}`)) | ||
}) | ||
|
||
bitcoinSPV.close() | ||
|
||
return { | ||
merkleProof: spvProof.merkleProof, | ||
txInBlockIndex: spvProof.txInBlockIndex, | ||
chainHeaders: spvProof.chainHeaders, | ||
} | ||
} | ||
|
||
// PAGE 5: Submit Proof | ||
// 1. Get transaction proof | ||
// 2. Submit proof to tBTC | ||
|
||
/** | ||
* Calculates deposit funding proof and submits it to tBTC. | ||
* @param {string} txID Funding transaction ID. | ||
* @param {number} fundingOutputIndex Position of a funding output in the transaction. | ||
*/ | ||
async function calculateAndSubmitFundingProof(txID, fundingOutputIndex) { | ||
if (txID.length != 64) { | ||
return Promise.reject( | ||
new Error(`invalid transaction id length [${txID.length}], required: [64]`) | ||
) | ||
} | ||
|
||
// TODO: We need to calculate confirmations value in a special way: | ||
// See: https://github.com/keep-network/tbtc-dapp/pull/8#discussion_r307438648 | ||
const confirmations = 6 | ||
|
||
const spvProof = await getTransactionProof(electrumConfig, txID, confirmations) | ||
|
||
// 2. Parse transaction to get required details. | ||
const txDetails = await BitcoinTxParser.parse(spvProof.tx) | ||
.cath((err) => { | ||
return Promise.reject(new Error(`failed to parse spv proof: ${err}`)) | ||
}) | ||
|
||
// 3. Submit proof to the contracts | ||
// version: txDetails.version, | ||
// txInVector: txDetails.txInVector, | ||
// txOutVector: txDetails.txOutVector, | ||
// fundingOutputIndex: fundingOutputIndex, | ||
// locktime: txDetails.locktime, | ||
// merkleProof: spvProof.merkleProof, | ||
// txInBlockIndex: spvProof.txInBlockIndex, | ||
// chainHeaders: spvProof.chainHeaders, | ||
|
||
|
||
// return eth transaction id to later convert it to etherscan link | ||
} | ||
|
||
module.exports = { | ||
calculateAndSubmitFundingProof, | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
// PAGE 3: Pay BTC | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
None of the BTC functions are implemented, only ETH-related ones. But I have started building a little skeleton since there is crossover in the flow. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Mentioning this because while it's not necessarily related to the review, it's easier (?) to communicate information here with context than in Flowdock with no code. :) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Get address will be implemented in #14 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nice one with implementing ETH part! |
||
async function getAddress(depositAddress) { | ||
// TODO: Implement: | ||
// 1. Get keep public key from the deposit | ||
// 2. Calculate P2WPKH address from the key | ||
} | ||
|
||
// Transition from PAGE 3 to PAGE 4 | ||
// 1. Wait for transaction on chain | ||
// 2. Return transaction ID | ||
async function getFundingTransactionID(electrumConfig, bitcoinAddress) { | ||
// TODO: Implement | ||
} | ||
|
||
// PAGE 4. WAITING FOR CONFIRMATIONS | ||
async function waitForConfirmations(transactionID) { | ||
// TODO: Implement: | ||
// 1. Wait for required number of confirmations for the transaction | ||
// 2. Monitor confirmations on the chain and return when ready | ||
} | ||
|
||
module.exports = { | ||
getAddress, getFundingTransactionID, waitForConfirmations, | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
const rewire = require('rewire') | ||
const FundingProof = rewire('../src/FundingProof') | ||
|
||
const fs = require('fs') | ||
const chai = require('chai') | ||
const assert = chai.assert | ||
|
||
const TX_ID = '72e7fd57c2adb1ed2305c4247486ff79aec363296f02ec65be141904f80d214e' | ||
const CONFIRMATIONS = 6 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Note that confirmations is not a reliable indication. We need to add a routine to get new headers until we reach sufficient accumulated difficulty. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, I noticed this problem on testnet when blocks get difficulty of A required accumulated difficulty would be difficulty from the block where the transaction was included multiplied by the factor (now 6), right? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. the difficulty A reasonable accumulated difficulty must be determined by the verifier. For TBTC's purposes this is a system parameter that adjusts with the current chain difficulty. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can we expect that tBTC will expose the required difficulty so we could get it here to check if the transaction has enough confirmations and we can start proof submission? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, this will be available as a view function, or similar There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For now we can leave this and add a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Raised an issue for this: keep-network/tbtc#223 |
||
|
||
describe('FundingProof', async () => { | ||
it('getTransactionProof', async () => { | ||
const proofFile = fs.readFileSync('./test/data/proof.json', 'utf8') | ||
const expectedResult = JSON.parse(proofFile) | ||
|
||
const result = await FundingProof.__get__('getTransactionProof')(TX_ID, CONFIRMATIONS) | ||
liamzebedee marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
assert.deepEqual(result, expectedResult) | ||
}) | ||
}) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
{ | ||
"merkleProof": "4e210df8041914be65ec026f2963c3ae79ff867424c40523edb1adc257fde77252846fd232df9ac2952dbdff1981c904abeae46ff4d4fa70bf2767df5bbb5b8bb9984f0773ca4efc53aba90ef129dac6161b1d86360822a8e46579b0ac7b6353bcdfe49c319a2c576f477fc49a38c6a4c2e942297e2105eb4c098d1038e76702b4744892e0ddd033729ec659613232546d2db8522bca7896d9480cc5ee0de03413a9d78eed747819794321140354f05879f1010951aedb0c62a3866c5e43537a5b7fd1e8290632d71b53e9a18cb3e80570145a5cc3d46ca1ea0c35ceb7db15632f5d72f7ea5eed3a46ce0543102ffffddcf92a951e870862640602dcda0c384037700982aea6e09db84bbd503634409a31830546656841f2cfd11fa7e6ba745df933d20827a26696c8fb73debac281ffb65fd18e7c11ad9a00e059c6cfdc6d29583b7a45472123fac1003384cc60fce2129c8d7364969dfa35021ab26c0b0449", | ||
"txInBlockIndex": 177, | ||
"chainHeaders": "00000020a114bf2d1e930390044cc4e00dd2f490a36dcecb4b6bb702b502000000000000583b7a45472123fac1003384cc60fce2129c8d7364969dfa35021ab26c0b0449bccc2e5dffff001d061013a10000ff3f3210404a744c3170cdd6ad7fc901194c913004faa87f291cd3faac2b00000000ecc1620341eeee4881423cab631e6e4a0b003c05ffc2dfc132a2a902a45df2c573d02e5d148c031af7358d5f00e0ff3fd83c1e679a4766043e3dbc622870e64ba4c2cacfa2f45563210100000000000071d244c45daecf0abf15c5f4e47f12310912918ca56b89c3dfb68103371ae6bf98d42e5d148c031aca5d525e00000020d2a6ad5304a5bbe4948666fd6775dc2cde9c0cef7060a471fe01000000000000597701d1165c140f471f2684f1f6b3e97765ee5492619582af5e6d192895e7d34cd92e5dffff001dbb34c42400000020b9b3fcbb515c899b10bf3889d432ca2782cfad01f9c2cf329fb60e000000000048d580fbe9ccf1cadaffe0e780eab57ea401f6260f38bd459d32cc3eef6cbd33ffd92e5d148c031a3c4277f40000002024af4d64067c20a1ed5cb9fbd432a98fe659e3653378e6b9ed00000000000000fea85a41c80b307f9cdfd22ac52521ba89ea6467769206d89889663cb7742e7358db2e5d148c031a7d30031a0000ff3f6418122efc0ddf2416189b01c0d98ab7e5072fe1e99c3e275401000000000000496c06f87b8d442db7c6bd36ff05e3a7a0edb3e0124d26c61d44c584ba1f8ff86bdc2e5d148c031a411e00ae" | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
{ | ||
"extends": "eslint-config-keep", | ||
"parserOptions": { | ||
"ecmaVersion": 2017, | ||
"sourceType": "module" | ||
}, | ||
"env": { | ||
"es6": true, | ||
"mocha": true | ||
}, | ||
"rules": { | ||
"semi": [ | ||
2, | ||
"never" | ||
] | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
const BitcoinSPV = require('./src/BitcoinSPV') | ||
const BitcoinTxParser = require('./src/BitcoinTxParser') | ||
const ElectrumClient = require('./src/ElectrumClient') | ||
|
||
module.exports = { | ||
BitcoinSPV, BitcoinTxParser, ElectrumClient | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should break this into
testnet
andmainnet
sectionsNB: Testnet electrum servers can be extremely unreliable. we're in the process of standing up our own. If you guys are interested in running one as well, we should coordinate
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We noticed the instability of the testnet electrum servers. We're in the middle of setting up our own instance as well.
CC: @sthompson22, @pdyraga