Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions packages/js-dapi-client/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,35 @@ hosted on Dash masternodes.
npm install @dashevo/dapi-client
```

### Browser usage

Response objects expose byte-valued fields as `Uint8Array` (not Node `Buffer`).
You can convert via `DAPIClient.bytes`:

```javascript
const DAPIClient = require('@dashevo/dapi-client');
const { bytesToHex, hexToBytes } = DAPIClient.bytes;

const hex = bytesToHex(proof.getQuorumHash());
```

A small number of internal code paths still construct `Buffer` instances —
notably `BlockHeadersProvider` (uses `dashcore-lib.BlockHeader` for SPV
parsing) and the `Identifier` constructor inside wasm-dpp. Node has `Buffer` built in;
browser bundlers (Vite, esbuild, webpack 5) typically auto-shim it when the
`buffer` package is installed, or you can polyfill explicitly:

```javascript
import { Buffer } from 'buffer';
globalThis.Buffer = Buffer;
```

This requirement will go away once
[dashpay/dashcore-lib#315](https://github.com/dashpay/dashcore-lib/pull/315)
(widening `BufferReader` to accept `Uint8Array`) lands and is picked up here.
Until then, browser consumers must ensure a `Buffer` global is reachable at
runtime.

## Usage

### Basic
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ const SimplifiedMNListDiff = require('@dashevo/dashcore-lib/lib/deterministicmnl
const cbor = require('cbor');

const logger = require('../logger');
const { bytesToHex } = require('../utils/bytes');

class SimplifiedMasternodeListProvider {
/**
Expand Down Expand Up @@ -100,25 +101,31 @@ class SimplifiedMasternodeListProvider {

let simplifiedMNListDiff;
let simplifiedMNListDiffObject;
let simplifiedMNListDiffBuffer;
let simplifiedMNListDiffBytes;
try {
simplifiedMNListDiffBuffer = Buffer.from(response.getMasternodeListDiff_asU8());
simplifiedMNListDiffBytes = new Uint8Array(response.getMasternodeListDiff_asU8());

simplifiedMNListDiffObject = cbor.decodeFirstSync(simplifiedMNListDiffBuffer);
simplifiedMNListDiffObject = cbor.decodeFirstSync(simplifiedMNListDiffBytes);

simplifiedMNListDiff = new SimplifiedMNListDiff(
simplifiedMNListDiffObject,
this.options.network,
);
} catch (e) {
// Guard against bytesToHex throwing (and masking the real error)
// if simplifiedMNListDiffBytes is undefined because the failure
// happened before line 106 assigned it.
const diffBytesHex = simplifiedMNListDiffBytes instanceof Uint8Array
? bytesToHex(simplifiedMNListDiffBytes)
: null;
this.logger.warn(
`Can't parse masternode list diff: ${e.message}`,
{
diffCount,
network: this.options.network,
error: e,
simplifiedMNListDiffObject,
simplifiedMNListDiffBytes: simplifiedMNListDiffBuffer.toString('hex'),
simplifiedMNListDiffBytes: diffBytesHex,
},
);

Expand Down
2 changes: 2 additions & 0 deletions packages/js-dapi-client/lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@ const DAPIClient = require('./DAPIClient');

const NotFoundError = require('./transport/GrpcTransport/errors/NotFoundError');
const BlockHeadersProvider = require('./BlockHeadersProvider/BlockHeadersProvider');
const bytes = require('./utils/bytes');

DAPIClient.Errors = {
NotFoundError,
};

DAPIClient.BlockHeadersProvider = BlockHeadersProvider;
DAPIClient.bytes = bytes;

module.exports = DAPIClient;
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ function getBlockByHashFactory(grpcTransport) {
* @typedef {getBlockByHash}
* @param {string} hash
* @param {DAPIClientOptions} [options]
* @returns {Promise<null|Buffer>}
* @returns {Promise<null|Uint8Array>}
*/
async function getBlockByHash(hash, options = {}) {
const getBlockRequest = new GetBlockRequest();
Expand All @@ -29,7 +29,7 @@ function getBlockByHashFactory(grpcTransport) {
);
const blockBinaryArray = response.getBlock();

return Buffer.from(blockBinaryArray);
return new Uint8Array(blockBinaryArray);
}

return getBlockByHash;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ function getBlockByHeightFactory(grpcTransport) {
* @typedef {getBlockByHeight}
* @param {number} height
* @param {DAPIClientOptions} [options]
* @returns {Promise<null|Buffer>}
* @returns {Promise<null|Uint8Array>}
*/
async function getBlockByHeight(height, options = {}) {
const getBlockRequest = new GetBlockRequest();
Expand All @@ -30,7 +30,7 @@ function getBlockByHeightFactory(grpcTransport) {

const blockBinaryArray = response.getBlock();

return Buffer.from(blockBinaryArray);
return new Uint8Array(blockBinaryArray);
}

return getBlockByHeight;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,18 +29,18 @@ function getBlockchainStatusFactory(grpcTransport) {

const responseObject = response.toObject();

// Respond with Buffers instead of base64 for binary fields
// Respond with Uint8Arrays instead of base64 for binary fields

if (response.getChain()) {
if (response.getChain()
.getBestBlockHash()) {
responseObject.chain.bestBlockHash = Buffer.from(response.getChain()
responseObject.chain.bestBlockHash = new Uint8Array(response.getChain()
.getBestBlockHash());
}

if (response.getChain()
.getChainWork()) {
responseObject.chain.chainWork = Buffer.from(response.getChain()
responseObject.chain.chainWork = new Uint8Array(response.getChain()
.getChainWork());
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ const {
CorePromiseClient,
},
} = require('@dashevo/dapi-grpc');
const { base64ToBytes } = require('../../utils/bytes');

/**
* @param {GrpcTransport} grpcTransport
Expand Down Expand Up @@ -34,7 +35,7 @@ function getMasternodeStatusFactory(grpcTransport) {
responseObject.status = Object.keys(GetMasternodeStatusResponse.Status)
.find((key) => GetMasternodeStatusResponse.Status[key] === responseObject.status);

responseObject.proTxHash = Buffer.from(responseObject.proTxHash, 'base64');
responseObject.proTxHash = base64ToBytes(responseObject.proTxHash);

return responseObject;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ class GetTransactionResponse {
/**
*
* @param {object} properties
* @param {Buffer} properties.transaction
* @param {Buffer} properties.blockHash
* @param {Uint8Array} properties.transaction
* @param {Uint8Array} properties.blockHash
* @param {number} properties.height
* @param {number} properties.confirmations
* @param {boolean} properties.isInstantLocked
Expand All @@ -22,15 +22,15 @@ class GetTransactionResponse {

/**
* Get transaction
* @returns {Buffer}
* @returns {Uint8Array}
*/
getTransaction() {
return this.transaction;
}

/**
* Get block hash
* @returns {Buffer}
* @returns {Uint8Array}
*/
getBlockHash() {
return this.blockHash;
Expand Down Expand Up @@ -75,8 +75,8 @@ class GetTransactionResponse {
}

return new GetTransactionResponse({
transaction: Buffer.from(transactionBinaryArray),
blockHash: Buffer.from(proto.getBlockHash()),
transaction: new Uint8Array(transactionBinaryArray),
blockHash: new Uint8Array(proto.getBlockHash()),
height: proto.getHeight(),
confirmations: proto.getConfirmations(),
isInstantLocked: proto.getIsInstantLocked(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ const {
} = require('@dashevo/dapi-grpc');

const DAPIClientError = require('../../errors/DAPIClientError');
const { hexToBytes } = require('../../utils/bytes');

/**
* @param {GrpcTransport} grpcTransport
Expand Down Expand Up @@ -41,7 +42,7 @@ function subscribeToBlockHeadersWithChainLocksFactory(grpcTransport) {

if (options.fromBlockHash) {
request.setFromBlockHash(
Buffer.from(options.fromBlockHash, 'hex'),
hexToBytes(options.fromBlockHash),
);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ const {
} = require('@dashevo/dapi-grpc');

const DAPIClientError = require('../../errors/DAPIClientError');
const { hexToBytes } = require('../../utils/bytes');

/**
* @param {GrpcTransport} grpcTransport
Expand Down Expand Up @@ -65,7 +66,7 @@ function subscribeToTransactionsWithProofsFactory(grpcTransport) {

if (options.fromBlockHash) {
request.setFromBlockHash(
Buffer.from(options.fromBlockHash, 'hex'),
hexToBytes(options.fromBlockHash),
);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ const InvalidResponseError = require('../response/errors/InvalidResponseError');

class GetDataContractResponse extends AbstractResponse {
/**
* @param {Buffer} dataContract
* @param {Uint8Array} dataContract
* @param {Metadata} metadata
* @param {Proof} [proof]
*/
Expand All @@ -14,7 +14,7 @@ class GetDataContractResponse extends AbstractResponse {
}

/**
* @returns {Buffer}
* @returns {Uint8Array}
*/
getDataContract() {
return this.dataContract;
Expand All @@ -33,7 +33,7 @@ class GetDataContractResponse extends AbstractResponse {
}

return new GetDataContractResponse(
Buffer.from(dataContract),
new Uint8Array(dataContract),
metadata,
Comment thread
PastaPastaPasta marked this conversation as resolved.
proof,
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,20 +16,20 @@ function getDataContractFactory(grpcTransport) {
/**
* Fetch Data Contract by id
* @typedef {getDataContract}
* @param {Buffer} contractId
* @param {Uint8Array} contractId
* @param {DAPIClientOptions & {prove: boolean}} [options]
* @returns {Promise<GetDataContractResponse>}
*/
async function getDataContract(contractId, options = {}) {
const { GetDataContractRequestV0 } = GetDataContractRequest;
const getDataContractRequest = new GetDataContractRequest();

// need to convert objects inherited from Buffer to pure buffer as google protobuf
// need to convert objects inherited from Uint8Array to pure Uint8Array as google protobuf
// doesn't support extended buffers
// https://github.com/protocolbuffers/protobuf/blob/master/js/binary/utils.js#L1049
if (Buffer.isBuffer(contractId)) {
if (contractId instanceof Uint8Array) {
// eslint-disable-next-line no-param-reassign
contractId = Buffer.from(contractId);
contractId = new Uint8Array(contractId);
}

getDataContractRequest.setV0(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ function getDataContractHistoryFactory(grpcTransport) {
/**
* Fetch Data Contract by id
* @typedef {getDataContractHistory}
* @param {Buffer} contractId
* @param {Uint8Array} contractId
* @param {bigint} [startAtMs]
* @param {number} [limit]
* @param {number} [offset]
Expand All @@ -34,12 +34,12 @@ function getDataContractHistoryFactory(grpcTransport) {
const { GetDataContractHistoryRequestV0 } = GetDataContractHistoryRequest;
const getDataContractHistoryRequest = new GetDataContractHistoryRequest();

// need to convert objects inherited from Buffer to pure buffer as google protobuf
// need to convert objects inherited from Uint8Array to pure Uint8Array as google protobuf
// doesn't support extended buffers
// https://github.com/protocolbuffers/protobuf/blob/master/js/binary/utils.js#L1049
if (Buffer.isBuffer(contractId)) {
if (contractId instanceof Uint8Array) {
// eslint-disable-next-line no-param-reassign
contractId = Buffer.from(contractId);
contractId = new Uint8Array(contractId);
}

getDataContractHistoryRequest.setV0(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ const AbstractResponse = require('../response/AbstractResponse');

class GetDocumentsResponse extends AbstractResponse {
/**
* @param {Buffer[]} documents
* @param {Uint8Array[]} documents
* @param {Metadata} metadata
* @param {Proof} [proof]
*/
Expand All @@ -13,7 +13,7 @@ class GetDocumentsResponse extends AbstractResponse {
}

/**
* @returns {Buffer[]}
* @returns {Uint8Array[]}
*/
getDocuments() {
return this.documents;
Expand All @@ -30,7 +30,7 @@ class GetDocumentsResponse extends AbstractResponse {

return new GetDocumentsResponse(
documents !== undefined
? documents.getDocumentsList().map((document) => Buffer.from(document)) : [],
? documents.getDocumentsList().map((document) => new Uint8Array(document)) : [],
metadata,
proof,
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ function getDocumentsFactory(grpcTransport) {
/**
* Fetch Documents from Drive
* @typedef {getDocuments}
* @param {Buffer} contractId - Data Contract ID
* @param {Uint8Array} contractId - Data Contract ID
* @param {string} type - Document type
* @param {DAPIClientOptions & getDocumentsOptions & {prove: boolean}} [options]
* @returns {Promise<GetDocumentsResponse>}
Expand All @@ -44,15 +44,16 @@ function getDocumentsFactory(grpcTransport) {

const { GetDocumentsRequestV0 } = GetDocumentsRequest;
const getDocumentsRequest = new GetDocumentsRequest();
// need to convert Identifier to pure buffer as google protobuf doesn't support extended buffers
// need to convert Identifier to pure Uint8Array as google protobuf doesn't support
// extended buffers
// https://github.com/protocolbuffers/protobuf/blob/master/js/binary/utils.js#L1049

// need to convert objects inherited from Buffer to pure buffer as google protobuf
// need to convert objects inherited from Uint8Array to pure Uint8Array as google protobuf
// doesn't support extended buffers
// https://github.com/protocolbuffers/protobuf/blob/master/js/binary/utils.js#L1049
if (Buffer.isBuffer(contractId)) {
if (contractId instanceof Uint8Array) {
// eslint-disable-next-line no-param-reassign
contractId = Buffer.from(contractId);
contractId = new Uint8Array(contractId);
}

getDocumentsRequest.setV0(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ class GetIdentitiesContractKeysResponse extends AbstractResponse {
const keysEntries = identitiesKeys.getEntriesList();

identitiesKeysMap = keysEntries.reduce((acc, entry) => {
const identityId = Identifier.from(Buffer.from(entry.getIdentityId())).toString();
const identityId = Identifier.from(entry.getIdentityId()).toString();
if (!acc[identityId]) {
acc[identityId] = {};
}
Expand Down
Loading
Loading