Skip to content
/ spv Public

An SPV extension for bsv.js version 2 and above.

Notifications You must be signed in to change notification settings

MatterPool/spv

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

19 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

SPV.js

SPV.js is a bsv2 extension that enables you to work with the RAWSPV and SPVTX data structures for validating SPV proofs. Rather than enforcing a strict deserialised format such as a JSON schema, the user is free to deserialise this structure however they see fit, making it easy to develop additional libraries for other languages whilst ensuring cross-compatability between them all.

Installation

SPV.js requires the peer dependency of bsv2. You must install this dependency yourself in order to make use of SPV.js:

$ npm install @matterpool/spv bsv@beta --save

Usage

To validate an SPV proof, simply import an SPVTX from either a Hex string or Buffer and call the validate method with its corresponding block header:

import { BlockHeader } from 'bsv';
import { SPVTx } from '@matterpool/spv';

//Import block header
const header = BlockHeader.fromHex("00e0ff27e4de87cf564f157d6d07abe37df27274fd2a011bc07ec3000000000000000000e43a1de4dd9c526274b8ea9e4bf01fe8928649f8e5b94abc4e05d83b8abeb924a51c645f32a00418b3bd152b");

//Import SPVTX
const spvtx = SPVTx.fromHex("01000000017125b04467dc2e3e766a0dae2b7a2f74211c7aa7bf796d47fbf44c259be23462661100006b483045022100f1e5fdfd36837a2e84225e157d25f4d341cad49bfdc909e0332e5e5a58e849a102203b5c59d2f5cf4c6f84b2bc189a03ed802d48784f335b712f73e80f807d4cdd714121037d53430715b2bc8463847e79d7e259c11a7d81bf7d6166e003e1b103b65731ffffffffff0123020000000000001976a9140ec56960e83cd3c03c8882e0fd34d462a34c653888ac00000000000000000000000001a4147e4346fda372c622c1819ac5c31661971c0f6be7672f0fcd1c00c1726e76669911c9ffbd2975f9966fa8bb23e32bfd33bc439eb4e41167780f39009c90be8cc62b1729569b5c8d50b59bad4489e95ac7a839555c1ee7955503c702bc9ac972d2dbb46d2534559d2a268a7b06872b279015809a323f3d53c7dfdb01537035a4ef485275a727aeb29328e49c1afc4fedac87d9333f059963f54a333d21b4faa9f912ab2af2e72f6941c3d1c979331e34f62fa7dac23daf29f24c049d3395fea0e77ad4dfdf496844cf289390364ce2defdab1e2b9bc4a935d030d9cf05fb2c79325c80ab426d6ed274d5440464d7074bdbbf47551d91dc9993a8935eb4f4ec9378102a8a32d1768221ee7ba35cefcd91d1e90d39ae8de541cddb8cab43a01a960e09d820fc6c1a35cbe372d0121d22fd1938cda5f89861be9a587173dbd8c5e232ce766ea43e1dc46754b18ecc7eceb34f3e87d41db9a48befefd46134b1144963ede9b117ef7556857fb9cd4ad6f0a6a050a45bc7e3698c169149cacf761b5533d74e9c7f2c6e01ec0fba86466c86e62c3fd9fbd1462fdd558d9e2aedfc65fc8d583ddca868fa29acebaa190e42f35b8912fe353d331e64fd0ae5310b7ef3e52b1c4d2cd7e99dd0553259394f44b8b71a0ad36918c6b2d9941e1c1872daf9351606edd68bf125246b99d2cf44ecd1c526fdc06fbfa3d9c9");

//Validate SPVTX against Block Header
console.log(spvtx.validate(header));
// returns true/false

What is RAWSPV?

RAWSPV is the minimal possible encoding for a serialised SPV proof. The justifications for this claim are laid out in the footnotes. SPV proofs can be generated by any SPV Node; namely, a node that maintains a complete store of transaction indexes, merkle leaves and branches, which can then be easily validated by any SPV Client; namely, a user or wallet that maintains a full set of Bitcoin block headers.

A serialised SPV proof (RAWSPV) adopts the following byte structure¹:

Field Description Size
Block Hash BE hash of a block header 32 bytes
Index VarInt representing index of a transaction in a block 1 - 9 bytes
Depth² VarInt representing depth of the merkle tree 1 - 9 bytes
Pairing hashes³ LE hashes of the transaction and its pairing nodes³ Depth * 32 Bytes

A worked example of a RAWSPV for any mined transaction may be acquired and verified directly from the Mattercloud TXDB API:

RAWSPV

https://txdb.mattercloud.io/api/v1/spv/6711e4b49e43bc33fd2be323bba86f96f97529bdffc9119966766e72c1001ccd

JSON formatted RAWSPV

https://txdb.mattercloud.io/api/v1/spv/6711e4b49e43bc33fd2be323bba86f96f97529bdffc9119966766e72c1001ccd?format=json

Verify RAWSPV

https://txdb.mattercloud.io/api/v1/spv/verify/000000000000000001a4147e4346fda372c622c1819ac5c31661971c0f6be7672f0fcd1c00c1726e76669911c9ffbd2975f9966fa8bb23e32bfd33bc439eb4e41167780f39009c90be8cc62b1729569b5c8d50b59bad4489e95ac7a839555c1ee7955503c702bc9ac972d2dbb46d2534559d2a268a7b06872b279015809a323f3d53c7dfdb01537035a4ef485275a727aeb29328e49c1afc4fedac87d9333f059963f54a333d21b4faa9f912ab2af2e72f6941c3d1c979331e34f62fa7dac23daf29f24c049d3395fea0e77ad4dfdf496844cf289390364ce2defdab1e2b9bc4a935d030d9cf05fb2c79325c80ab426d6ed274d5440464d7074bdbbf47551d91dc9993a8935eb4f4ec9378102a8a32d1768221ee7ba35cefcd91d1e90d39ae8de541cddb8cab43a01a960e09d820fc6c1a35cbe372d0121d22fd1938cda5f89861be9a587173dbd8c5e232ce766ea43e1dc46754b18ecc7eceb34f3e87d41db9a48befefd46134b1144963ede9b117ef7556857fb9cd4ad6f0a6a050a45bc7e3698c169149cacf761b5533d74e9c7f2c6e01ec0fba86466c86e62c3fd9fbd1462fdd558d9e2aedfc65fc8d583ddca868fa29acebaa190e42f35b8912fe353d331e64fd0ae5310b7ef3e52b1c4d2cd7e99dd0553259394f44b8b71a0ad36918c6b2d9941e1c1872daf9351606edd68bf125246b99d2cf44ecd1c526fdc06fbfa3d9c9

¹ While we could also append a block header to the end of this structure, and the VarInt structure of the RAWSPV format does enable this, SPV as defined in the Bitcoin whitepaper requires users to maintain their own copy of the block headers for validation purposes. In absense of this, handing someone an SPV proof with a header appended to the end, while perhaps convenient, is scarcely preferable to simply handing them a RAWTX, as validating against a single header in isolation without validating the entire chain of proof of work from the Genesis Block to the chain tip does not actually mathematically prove that a transaction has been recorded in the longest chain of proof of work.

² Depth is not required to validate an SPV proof, but is provided here to enable the user to determine the remaining length of the RAWSPV buffer. While this could be calculated by dividing the remaining byte length after the transaction index by 32, this approach becomes problematic when attempting to serialise multiple SPV proofs into a single byte stream; an important optimisation, both for SPV at scale, and for SPV envelopes in the future. It is Satoshi Nakamoto's original design for the structure of a transaction including VarInt length counters that has enabled us to append a serialised SPV proof to a RAWTX to create an SPVTX today. This kind of foresight should be paid forward to whoever inevitably extends this structure in the future.

³ Assuming a user is starting from a RAWTX to validate a proof, it would be possible to omit the LE hash of the transaction, enabling us to save 32 bytes in the RAWSPV. This approach becomes problematic when an SPV proof is acquired separately from a RAWTX, such as in a serialised byte stream for a batch request, as there is no simple way to pair the two together other than maintaining the entire set of merkle leaves for the opposing block and extracting the hash via its index, or relying upon a third-party transaction index; largely defeating the primary purpose of SPV as outlined in the whitepaper. 32 bytes is a small price to pay for the ability to easily verify a proof against both a block header and a txid without immediately having either of them on hand.

SPVTX serialisation format

An SPVTX is an extension of a serialised Bitcoin transaction, also known as a RAWTX. An SPVTX takes a RAWTX buffer and concatenates it with a RAWSPV buffer. As such, in its raw form, an SPVTX is backwards compatible with any Bitcoin library currently using RAWTX buffers that acquires nLockTime by reading in a Uint32_t from the transaction buffer, such as bsv2. This enables an SPVTX to be used interchangeably with a RAWTX in many existing protocols, such as PayMail, defaulting to a higher standard of proof before falling back to a lower one. This may not be the case for libraries that instead acquire nLockTime by simply reading to the end of the entire buffer structure, but can be made compatible rather trivially by simply truncating the RAWSPV buffer from the end.

The structure of a transaction is outlined in detail by the BitcoinSV wiki: https://wiki.bitcoinsv.io/index.php/Bitcoin_Transactions

An SPVTX simply appends the above RAWSPV structure to the end of the transaction buffer directly after nLockTime.

A worked example of an SPVTX for any mined transaction may be acquired and verified directly from the Mattercloud TXDB API:

SPVTX

https://txdb.mattercloud.io/api/v1/spvtx/6711e4b49e43bc33fd2be323bba86f96f97529bdffc9119966766e72c1001ccd

JSON formatted SPVTX

https://txdb.mattercloud.io/api/v1/spvtx/6711e4b49e43bc33fd2be323bba86f96f97529bdffc9119966766e72c1001ccd?format=json

Verify SPVTX

https://txdb.mattercloud.io/api/v1/spvtx/verify/01000000017125b04467dc2e3e766a0dae2b7a2f74211c7aa7bf796d47fbf44c259be23462661100006b483045022100f1e5fdfd36837a2e84225e157d25f4d341cad49bfdc909e0332e5e5a58e849a102203b5c59d2f5cf4c6f84b2bc189a03ed802d48784f335b712f73e80f807d4cdd714121037d53430715b2bc8463847e79d7e259c11a7d81bf7d6166e003e1b103b65731ffffffffff0123020000000000001976a9140ec56960e83cd3c03c8882e0fd34d462a34c653888ac00000000000000000000000001a4147e4346fda372c622c1819ac5c31661971c0f6be7672f0fcd1c00c1726e76669911c9ffbd2975f9966fa8bb23e32bfd33bc439eb4e41167780f39009c90be8cc62b1729569b5c8d50b59bad4489e95ac7a839555c1ee7955503c702bc9ac972d2dbb46d2534559d2a268a7b06872b279015809a323f3d53c7dfdb01537035a4ef485275a727aeb29328e49c1afc4fedac87d9333f059963f54a333d21b4faa9f912ab2af2e72f6941c3d1c979331e34f62fa7dac23daf29f24c049d3395fea0e77ad4dfdf496844cf289390364ce2defdab1e2b9bc4a935d030d9cf05fb2c79325c80ab426d6ed274d5440464d7074bdbbf47551d91dc9993a8935eb4f4ec9378102a8a32d1768221ee7ba35cefcd91d1e90d39ae8de541cddb8cab43a01a960e09d820fc6c1a35cbe372d0121d22fd1938cda5f89861be9a587173dbd8c5e232ce766ea43e1dc46754b18ecc7eceb34f3e87d41db9a48befefd46134b1144963ede9b117ef7556857fb9cd4ad6f0a6a050a45bc7e3698c169149cacf761b5533d74e9c7f2c6e01ec0fba86466c86e62c3fd9fbd1462fdd558d9e2aedfc65fc8d583ddca868fa29acebaa190e42f35b8912fe353d331e64fd0ae5310b7ef3e52b1c4d2cd7e99dd0553259394f44b8b71a0ad36918c6b2d9941e1c1872daf9351606edd68bf125246b99d2cf44ecd1c526fdc06fbfa3d9c9

Acknowledgements

@deanmlittle/u40 - Creator of RAWSPV and SPVTX formats, SPV.js bsv2 extension, SPV Client, SPV Node and Mattercloud SPV API software.

@attilaaros/u205 - Creator of TXDB, the enabling technology that allowed us to prove that SPV truly does work at scale.

License

The idea of exclusive licensing becomes somewhat arbitrary when a piece of software is only really useful on a UTXO-based blockchain with massive scale. To anyone wishing to use this elsewhere, we wish you the best of luck, you're going to need it.

About

An SPV extension for bsv.js version 2 and above.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages