Giter VIP home page Giter VIP logo

bitcoinfilesjs's Introduction

BitcoinFilesJS

This is a JavaScript Library for uploading and downloading files per the Bitcoin Files Protocol specification to the Bitcoin Cash blockchain. It's important to understand that files uploaded to any blockchain are permanent and cannot be deleted. All uploaded content is associated with the public key(s) you use to pay for uploading the content.

Other tools using the Bitcoin Files Protocol include:

NPM

Installation (0.6.0+)

For node.js

npm install bitcoinfiles

For browser

<script src='https://unpkg.com/bitcoinfiles'></script>

Example File Download

const Grpc = require('grpc-bchrpc-node'); // or window.bchrpc
const Bfp = require('bitcoinfiles').Bfp;  // or window.bitcoinfiles.Bfp
const grpc = new Grpc.GrpcClient;
const bfp = new Bfp(grpc);

// 1 - download file using URI
let result;
(async function() {
    result = await bfp.downloadFile('bitcoinfile:7e4600323c934926369c136562f5483e3df79baf087c8dd2b0ed1aea69d5ee49');

    // Wait for download to complete -- Mario.png TAKES ABOUT 6 SEC TO DOWNLOAD!
    console.log("download complete.");

    // 2 - result includes a boolean check telling you if the file's sha256 matches the file's metadata
    if (result.passesHashCheck) {
        console.log("Success: downloaded file sha256 matches file's metadata");
    }

    // 3 - do something with the file...
    let fileBuffer = result.fileBuf;
})();

Example File Upload

Below is a simple example. For a more complete React.js file upload example visit SimpleToken.cash website

const Grpc = require('grpc-bchrpc-node'); // or window's property equivalents
const Bfp = require('bitcoinfiles').Bfp;
const Utils = require('bitcoinfiles').Utils;
const grpc = new Grpc.GrpcClient;
const bfp = new Bfp(grpc);


// 1 - get a file and file metadata somehow
const someFileBuffer = Buffer.from('aabbccddeeff', 'hex');
const fileName = 'a test file';
const fileExt = 'txt';
const fileSize = someFileBuffer.length
const fileSha256Hex = Utils.Sha256(someFileBuffer).toString('hex');

// 2 - estimate upload cost for funding the transaction
let uploadCost = Bfp.calculateFileUploadCost(fileSize);

// Alternatively, use the new protocol intended for larger files:
// let uploadCost = Bfp.calculateFileUploadCost(fileSize, null, 1, 2);

console.log('upload cost: ', uploadCost);

// 3 - create a funding transaction
let fundingAddress = 'bitcoincash:qqgvrkm0xpmwqgyhfm65qxv70tjtwma6lgk07ffv9u'
let fundingWif = 'KzcuA9xnDRrb9cPh29N7EQbBhQQLMWtcrDwKbEMoahmwBNACNRfa'

// 4 - Make sure address above is funded with at least uploadCost
let fundingUtxo = {
    "txid": "85c1b22c116b44539ead07353c509502b46106344bb5b4bd46a880ba8a530c27",
    "satoshis": 12000,
    "vout": 3
};

// wait for network to resolve...

// 5 - upload the file
let fileId;
(async function() {
    fileId = await bfp.uploadFile(fundingUtxo, fundingAddress, fundingWif, someFileBuffer, fileName, fileExt);
    console.log('fileId: ', fileId);
})();

// wait for upload to complete resolve... Done.

Documentation

async uploadFile(
    fundingUtxo: utxo,
    fundingAddress: string,
    fundingWif: string,
    fileDataArrayBuffer: Buffer,
    fileName?: string,
    fileExt?: string,
    prevFileSha256Hex?: string,
    fileExternalUri?: string,
    fileReceiverAddress?: string,
    signProgressCallback?: Function,
    signFinishedCallback?: Function,
    uploadProgressCallback?: Function,
    uploadFinishedCallback?: Function,
    delay_ms = 500,
    uploadMethod = 1): Promise<string>;

uploadFile is the method used to a upload file

Mandatory parameters:

  • fundingUtxo is the utxo to fund the uploading transaction(s). It must have a value no less than calculated by calculateFileUploadCost
  • fundingAddress is the address to which belongs the utxo
  • fundingWif is the private key which unlocks the funding address in Wallet Import Format
  • fileDataArrayBuffer is the data to be uploaded, which may be a NodeJS Buffer or a browser ArrayBuffer; see bottom for notes about ArrayBuffer usage

Optional parameters:

  • fileName is the file name
  • fileExt is the file extension
  • prevFileSha256Hex is a reference to the previous file
  • fileExternalUri is a URI for the file
  • fileReceiverAddress is a recipient address for the last uploading transaction, to be used instead of fundingAddress
  • signProgressCallback, signFinishedCallback, uploadProgressCallback, uploadFinishedCallback are callback functions for upload progress updates
  • delay_ms is the delay between uploading consecutive transactions
  • uploadMethod refers to the upload protocol: 1 for small data pushes and backwards compatibility, 2 for 0.6.0+ compatible more efficient data pushes intended for larger files

Returns the fileId, which contains a prefix (bitcoinfile:) and the TXID


async downloadFile(
    bfpUri: string,
    progressCallback?: Function): Promise<{
        passesHashCheck: boolean;
        fileBuf: Buffer;
}>;

downloadFile is the method used to download a file

  • bfpUri may be the TXID of the metadata-containing transaction, or the TXID prepended with bitcoinfile: or bitcoinfiles:
  • progressCallback is an optional download progress callback function

Returns an object with passesHashCheck which determines if downloading was sucessful and fileBuf which has the file contents; see bottom for notes about ArrayBuffer usage


static calculateFileUploadCost(
    fileSizeBytes: number,
    configMetadataOpReturn?: FileMetadata,
    fee_rate?: number,
    uploadMethod?: number): number;

Mandatory parameter: fileSizeBytes is the length of file contents in terms of octets

Optional parameters: configMetadataOpReturn is the metadata that would be uploaded with the file, passing this instead of null may yield a better estimate with a lower calculated cost fee_rate is the fee rate in satoshis per byte uploadMethod is the upload protocol; see uploadFile documentation for details

Types

export interface FileMetadata {
    msgType: number;
    chunkCount: number;
    fileName?: string;
    fileExt?: string;
    fileSize: number;
    fileSha256Hex?: string;
    prevFileSha256Hex?: string;
    fileUri?: string;
    chunkData?: Buffer;
}
  • msgType is a synonym of uploadMethod, which is described in uploadFile documentation
  • chunkCount is a placeholder that can be set as 1
  • chunkData is a placeholder that can be set as null

The other values can be set as described earlier


export interface utxo {
    txid: string;
    vout: number;
    satoshis: number;
}

The fields that should be set are shown above for an unspent output


Buffer: This may be a NodeJS buffer or an ArrayBuffer. For use in a browser, it is suggested that an ArrayBuffer of Uint8Array should be used.

For a variable fileContents of type Uint8Array, the ArrayBuffer can be accessed as fileContents.buffer. However, this might not always work, for example if .subarray(...) was applied to fileContents before .buffer. In this case, the approach here can be taken.

bitcoinfilesjs's People

Contributors

adrianbarwicki avatar deswurstes avatar jcramer avatar nodemaster115 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

bitcoinfilesjs's Issues

Reduce pkg size via Dependency injection for BITBOX-SDK or SLP-SDK

The size of the bitcoinfilesjs pkg can be reduced significantly by allowing the consumer to inject their own version of BITBOX. Whether it be BITBOX-SDK, SLP-SDK, or a customized version. See bitbox-dep branch.

Here are comments on the existing implementation of this on the bitbox-dep branch:

Adrian Barwicki, [13.01.19 05:07]
Yeah, I implemented it.

Adrian Barwicki, [13.01.19 05:07]
This is exactly what I meant. In this way, I could inject my lightweight version of bitbox

Adrian Barwicki, [13.01.19 05:09]
One thing though - I import the source code, not the built version. What would help me a lot is static type checking to ensure that the methods and the methods’ interfaces are still the same. Otherwise, I’d have to have full test coverage which I don’t 🙂

Adrian Barwicki, [13.01.19 05:10]
The lib-files are classes anyway so if you converted the file names to TS without any other changes, I think it would work out of the box.

Adrian Barwicki, [13.01.19 05:10]
For the built, you could generate index.d.ts and then the built imports would have the types as well.

Adrian Barwicki, [13.01.19 05:11]
[ Photo ]

Adrian Barwicki, [13.01.19 05:11]
Also, is there a reason you want to have a Bitbox class and not the instance?

Adrian Barwicki, [13.01.19 05:12]
In this way, you take away the option to specify if they want to use the cloud api hosted by bitcoin.com or self-hosted one.

Adrian Barwicki, [13.01.19 05:13]
And I think you use one instance of Bitbox across the whole library, so it should be ok 🙂

Adrian Barwicki, [13.01.19 05:15]
Another feedback:

Adrian Barwicki, [13.01.19 05:15]
console.logs could be replaced with optional loggers maybe

James Cramer, [13.01.19 08:35]
[In reply to Adrian Barwicki]
Yes because switching networks (like to testnet) is handled in the constructor. Not sure if there is some network switching method.

James Cramer, [13.01.19 08:36]
[In reply to Adrian Barwicki]
Ok

Adrian Barwicki, [13.01.19 08:39]
[In reply to James Cramer]
Rest.bitcoin.com is open source and can be run locally. It’s not only about choosing mainnet vs testnet but also about specifying the restURL

James Cramer, [13.01.19 08:39]
Ah yes, that’s what I meant

File size greater than OP_RETURN example

When uploading a file size greater than the OP_RETURN size, what happens? Do you have to input the chunk_count variable as 2?

It would be great to see an example of how the library is designed to handle this, including upload & download

TypeError: Cannot read property 'passesHashCheck' of undefined

I am facing the following issue on the download script.

/home/testbed/Downloads/btcash/download.js:14
if(result.passesHashCheck){
^

TypeError: Cannot read property 'passesHashCheck' of undefined
at Object. (/home/testbed/Downloads/btcash/download.js:14:11)
at Module._compile (internal/modules/cjs/loader.js:1138:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:1158:10)
at Module.load (internal/modules/cjs/loader.js:986:32)
at Function.Module._load (internal/modules/cjs/loader.js:879:14)
at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:71:12)
at internal/main/run_main_module.js:17:47

error_passeshashcheck

Include axios as dependency

Axios is not included as a dependency in the package.json, but is used in ./lib/bitdb.js

This is failing in a Webpack build downstream because Webpack will always try to require something like that

Add type 2 file uploads using p2sh scriptSig data space

As defined in the BFP spec, type 2 file uploads represent data storage using p2sh scriptSig. Current network rules allow each input to contain up to 1650KB of data in scriptSig. With the 25 transaction chain network policy, we should be able to use this to get files uploaded that are larger than 30KB in size. This is also a more efficient way to store data, rather than using OP_RETURN space which is currently limited to 220 bytes.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.