move to new xrpl library

This commit is contained in:
nitowa
2022-03-27 18:55:14 +02:00
parent ca8498707b
commit 33201638ad
9 changed files with 401 additions and 113 deletions
+21 -42
View File
@@ -12,61 +12,40 @@ xrpio is a library that allows you to write and read arbitrary data in the rippl
npm i xrpio
```
# How it works
Transactions on the ripple blockchain are allowed to carry up to 1kB of arbitrary data via the memo field.
We can use this to store data of any size by building a tree of references between these transactions that can then be reassembled by reading them back from the blockchain.
In order to generate these transactions xrpio sends payments with the minimum denomination between two wallets controlled by the user.
xrpio automatically takes care of the logistics behind this technique as well as compression of the data.
Highly simplified, you can visualize the process like this:
![xrpio treewrite](https://i.imgur.com/G2HofSE.gif)
In practice each node does of course store significantly more data.
# Caution
This library is in an early stage of development and **breaking changes may occur spontaneously and without regard of semantic versioning until the v1.0.0 release**.
## <span style="color:red"> Operation on the main-net is untested and should not be used in production! </span>
## <span style="color:red"> Operation on the main-net is untested and should not be used in production! If you want to deploy this library with the main-net please download the sources and modify them to your needs.</span>
<br />
# Quickstart
```typescript
import {RippleAPI} from 'ripple-lib'
import {treeRead, treeWrite} from 'xrpio'
import { xrpIO } from "xrpio"
const api = new RippleAPI({ server: "..." })
const api = new xrpIO("wss://some_ripple_node.net:51233")
await api.connect()
const dataRootHash = await treeWrite(
api,
"Arbitrary string data 123",
{
address: "Sender address",
secret: "Sender private key"
},
"Receiver address"
)
txHash = await api.treeWrite("arbitrary text 123", receiveWallet.address, sendWallet.secret)
data = await api.treeRead([txHash])
const data = await treeRead(api, [dataRootHash])
console.log(data) //"Arbitrary string data 123"
```
console.log(data) //"arbitrary text 123"
# A simple ready-to-run example for the testnet
```typescript
import { treeRead, treeWrite, Wallet } from 'xrpio'
import { RippleAPI } from 'ripple-lib'
import fetch from 'node-fetch'
export const makeTestnetWallet = () : Promise<Wallet> => fetch('https://faucet.altnet.rippletest.net/accounts', {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
}).then((raw:any) => {
return raw.json().then(content => content.account)
});
(async()=>{
const api = new RippleAPI({server: 'wss://s.altnet.rippletest.net:51233'})
await api.connect()
const fromWallet = await makeTestnetWallet()
const toWallet = await makeTestnetWallet()
await new Promise((res, rej) => setTimeout(res, 10000)) //it takes a moment for the wallets to become active
const rootHash = await treeWrite(api, "test123", fromWallet, toWallet.address)
const data = await treeRead(api, [rootHash])
console.log(data)
})()
```
# [Full documentation](https://gitea.nitowa.xyz/docs/xrpio)
+137 -4
View File
@@ -1,6 +1,6 @@
{
"name": "xrpio",
"version": "0.0.7",
"version": "0.0.10",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
@@ -174,6 +174,53 @@
"integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==",
"dev": true
},
"bindings": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz",
"integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==",
"requires": {
"file-uri-to-path": "1.0.0"
}
},
"bip32": {
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/bip32/-/bip32-2.0.6.tgz",
"integrity": "sha512-HpV5OMLLGTjSVblmrtYRfFFKuQB+GArM0+XP8HGWfJ5vxYBqo+DesvJwOdC2WJ3bCkZShGf0QIfoIpeomVzVdA==",
"requires": {
"@types/node": "10.12.18",
"bs58check": "^2.1.1",
"create-hash": "^1.2.0",
"create-hmac": "^1.1.7",
"tiny-secp256k1": "^1.1.3",
"typeforce": "^1.11.5",
"wif": "^2.0.6"
},
"dependencies": {
"@types/node": {
"version": "10.12.18",
"resolved": "https://registry.npmjs.org/@types/node/-/node-10.12.18.tgz",
"integrity": "sha512-fh+pAqt4xRzPfqA6eh3Z2y6fyZavRIumvjhaCL753+TVkGKGhpPeyrJG2JftD0T9q4GF00KjefsQ+PQNDdWQaQ=="
}
}
},
"bip39": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/bip39/-/bip39-3.0.4.tgz",
"integrity": "sha512-YZKQlb752TrUWqHWj7XAwCSjYEgGAk+/Aas3V7NyjQeZYsztO8JnQUaCWhcnL4T+jL8nvB8typ2jRPzTlgugNw==",
"requires": {
"@types/node": "11.11.6",
"create-hash": "^1.1.0",
"pbkdf2": "^3.0.9",
"randombytes": "^2.0.1"
},
"dependencies": {
"@types/node": {
"version": "11.11.6",
"resolved": "https://registry.npmjs.org/@types/node/-/node-11.11.6.tgz",
"integrity": "sha512-Exw4yUWMBXM3X+8oqzJNRqZSwUAaS4+7NdvHqQuFi/d+synz++xmX3QIf+BFqneW8N31R8Ky+sikfZUXq07ggQ=="
}
}
},
"bn.js": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.0.tgz",
@@ -290,6 +337,24 @@
}
}
},
"bs58": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz",
"integrity": "sha1-vhYedsNU9veIrkBx9j806MTwpCo=",
"requires": {
"base-x": "^3.0.2"
}
},
"bs58check": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/bs58check/-/bs58check-2.1.2.tgz",
"integrity": "sha512-0TS1jicxdU09dwJMNZtVAfzPi6Q6QeN0pM1Fkzrjn+XYHvzMKPU3pHVpva+769iNVSfIYWf7LJ6WR+BuuMf8cA==",
"requires": {
"bs58": "^4.0.0",
"create-hash": "^1.1.0",
"safe-buffer": "^5.1.2"
}
},
"buffer": {
"version": "5.6.0",
"resolved": "https://registry.npmjs.org/buffer/-/buffer-5.6.0.tgz",
@@ -447,7 +512,6 @@
"version": "1.1.7",
"resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz",
"integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==",
"dev": true,
"requires": {
"cipher-base": "^1.0.3",
"create-hash": "^1.1.0",
@@ -653,6 +717,11 @@
"safe-buffer": "^5.1.1"
}
},
"file-uri-to-path": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz",
"integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw=="
},
"fill-range": {
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
@@ -1326,6 +1395,11 @@
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
},
"nan": {
"version": "2.15.0",
"resolved": "https://registry.npmjs.org/nan/-/nan-2.15.0.tgz",
"integrity": "sha512-8ZtvEnA2c5aYCZYd1cvgdnU6cqwixRoYg70xPLWUws5ORTa/lnw+u4amixRS/Ac5U5mQVgp9pnlSUnbNWFaWZQ=="
},
"nanoid": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.2.0.tgz",
@@ -1445,7 +1519,6 @@
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.1.tgz",
"integrity": "sha512-4Ejy1OPxi9f2tt1rRV7Go7zmfDQ+ZectEQz3VGUQhgq62HtIRPDyG/JtnwIxs6x3uNMwo2V7q1fMvKjb+Tnpqg==",
"dev": true,
"requires": {
"create-hash": "^1.1.2",
"create-hmac": "^1.1.4",
@@ -1504,7 +1577,6 @@
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
"integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==",
"dev": true,
"requires": {
"safe-buffer": "^5.1.0"
}
@@ -1740,6 +1812,25 @@
"has-flag": "^4.0.0"
}
},
"tiny-secp256k1": {
"version": "1.1.6",
"resolved": "https://registry.npmjs.org/tiny-secp256k1/-/tiny-secp256k1-1.1.6.tgz",
"integrity": "sha512-FmqJZGduTyvsr2cF3375fqGHUovSwDi/QytexX1Se4BPuPZpTE5Ftp5fg+EFSuEf3lhZqgCRjEG3ydUQ/aNiwA==",
"requires": {
"bindings": "^1.3.0",
"bn.js": "^4.11.8",
"create-hmac": "^1.1.7",
"elliptic": "^6.4.0",
"nan": "^2.13.2"
},
"dependencies": {
"bn.js": {
"version": "4.12.0",
"resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz",
"integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA=="
}
}
},
"to-regex-range": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
@@ -1831,6 +1922,11 @@
"handlebars": "^4.7.7"
}
},
"typeforce": {
"version": "1.18.0",
"resolved": "https://registry.npmjs.org/typeforce/-/typeforce-1.18.0.tgz",
"integrity": "sha512-7uc1O8h1M1g0rArakJdf0uLRSSgFcYexrVoKo+bzJd32gd4gDy2L/Z+8/FjPnU9ydY3pEnVPtr9FyscYY60K1g=="
},
"typescript": {
"version": "4.5.5",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.5.5.tgz",
@@ -1941,6 +2037,14 @@
"is-typed-array": "^1.1.7"
}
},
"wif": {
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/wif/-/wif-2.0.6.tgz",
"integrity": "sha1-CNP1IFbGZnkplyb63g1DKudLRwQ=",
"requires": {
"bs58check": "<3.0.0"
}
},
"wordwrap": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz",
@@ -1975,6 +2079,35 @@
"resolved": "https://registry.npmjs.org/ws/-/ws-7.5.7.tgz",
"integrity": "sha512-KMvVuFzpKBuiIXW3E4u3mySRO2/mCHSyZDJQM5NQ9Q9KHWHWh0NHgfbRMLLrceUK5qAL4ytALJbpRMjixFZh8A=="
},
"wtfnode": {
"version": "0.9.1",
"resolved": "https://registry.npmjs.org/wtfnode/-/wtfnode-0.9.1.tgz",
"integrity": "sha512-Ip6C2KeQPl/F3aP1EfOnPoQk14Udd9lffpoqWDNH3Xt78svxPbv53ngtmtfI0q2Te3oTq79XKTnRNXVIn/GsPA==",
"dev": true
},
"xrpl": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/xrpl/-/xrpl-2.1.1.tgz",
"integrity": "sha512-s8qg5ll0m1WuPji+qLOO02uhk8tu12zA68vspwwabH2XH4kzzDnABxTeQQlZisjr+B1EBalmlt0yMI+Gv7fnbg==",
"requires": {
"bignumber.js": "^9.0.0",
"bip32": "^2.0.6",
"bip39": "^3.0.4",
"https-proxy-agent": "^5.0.0",
"lodash": "^4.17.4",
"ripple-address-codec": "^4.2.3",
"ripple-binary-codec": "^1.3.0",
"ripple-keypairs": "^1.1.3",
"ws": "^8.2.2"
},
"dependencies": {
"ws": {
"version": "8.5.0",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.5.0.tgz",
"integrity": "sha512-BWX0SWVgLPzYwF8lTzEy1egjhS4S4OEAHfsO8o65WOVsrnSRGaSiUaa9e0ggGlkMTtBlmOpEXiie9RUcBO86qg=="
}
}
},
"y18n": {
"version": "5.0.8",
"resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
+5 -3
View File
@@ -1,6 +1,6 @@
{
"name": "xrpio",
"version": "0.0.10",
"version": "0.1.0",
"repository": {
"type": "git",
"url": "https://gitea.nitowa.xyz/npm-packages/xrpio.git"
@@ -28,7 +28,8 @@
"author": "nitowa",
"license": "MIT",
"dependencies": {
"ripple-lib": "^1.10.0"
"ripple-lib": "^1.10.0",
"xrpl": "^2.1.1"
},
"devDependencies": {
"@types/chai": "^4.2.21",
@@ -45,6 +46,7 @@
"typedoc": "^0.22.11",
"typedoc-plugin-markdown": "^3.11.12",
"typescript": "^4.5.0",
"utf8": "^3.0.0"
"utf8": "^3.0.0",
"wtfnode": "^0.9.1"
}
}
+4
View File
@@ -13,3 +13,7 @@ export type Secret = string
export type PublicKey = string
export type Amount = number
export type TxHash = string
export type Options = {
debug: boolean,
connectionTimeout: number
}
+1
View File
@@ -150,6 +150,7 @@ export const readRaw = async (api: RippleAPI, hash: string): Promise<Memo> => {
} catch (e) {
// if(debug){
console.log("READRAW ERR", e)
api.isConnected
// }
throw e
} finally {
+175
View File
@@ -0,0 +1,175 @@
import { Memo, Options } from '../util/types'
import { Client, Payment, TxResponse, Wallet } from 'xrpl'
import * as zlib from 'zlib'
import * as util from 'util'
const compressB64 = async (data: string) => (await util.promisify(zlib.deflate)(Buffer.from(data, 'utf-8'))).toString('base64')
const decompressB64 = async (data: string) => (await util.promisify(zlib.inflate)(Buffer.from(data, 'base64'))).toString('utf-8')
const hexDecode = (str: string) => Buffer.from(str, 'hex').toString('utf8')
const hexEncode = (str: string) => Buffer.from(str, 'utf8').toString('hex').toUpperCase()
const chunkString = (str: string, length: number) => str.match(new RegExp('.{1,' + length + '}', 'gs'));
const PAYLOAD_SIZE = 925
export class xrpIO {
private api: Client
constructor(
private server: string,
private options: Options = {
debug: false,
connectionTimeout: 100000
}
) {
this.api = new Client(server, {
connectionTimeout: this.options.connectionTimeout
})
}
public async connect(): Promise<void> {
if (!this.api.isConnected())
await this.api.connect()
}
public async disconnect(): Promise<void> {
try{
await this.api.disconnect()
}catch(e){
console.log("DISCONNECT ERROR", e)
}
}
private async cloneApi(): Promise<Client> {
let _api = new Client(this.server, {
connectionTimeout: this.options.connectionTimeout
})
while(!_api.isConnected()){
try{
await _api.connect()
return _api
}catch(e){
this.dbg('CLONEAPI ERR', 'Connection failed', String(e['message']))
await _api.disconnect()
_api = new Client(this.server, {
connectionTimeout: this.options.connectionTimeout
})
}
}
}
private async sendPayment(data: Memo, to: string, secret: string, sequence?: number): Promise<TxResponse> {
const wallet = Wallet.fromSecret(secret)
this.dbg("Sending payment", wallet.address, '->', to)
const _api = await this.cloneApi()
try {
const payment: Payment = await _api.autofill({
TransactionType: 'Payment',
Account: wallet.address,
Destination: to,
Sequence: sequence,
Amount: "1",
Memos: [{
Memo: {
MemoData: hexEncode(data.data || ""),
MemoFormat: hexEncode(data.format || ""),
MemoType: hexEncode(data.type || "")
}
}]
})
const response = await _api.submitAndWait(payment, { wallet })
await _api.disconnect()
this.dbg("Tx finalized", response.result.hash, response.result.Sequence)
return response
} catch (error: any) {
this.dbg("SENDPAYMENT ERROR", error)
await _api.disconnect()
throw error
}
}
public async writeRaw(data: Memo, to: string, secret: string, sequence?: number): Promise<string> {
this.dbg("Writing data", data)
const tx = await this.sendPayment(data, to, secret, sequence)
return tx.result.hash
}
private async getTransaction(hash: string): Promise<TxResponse> {
this.dbg("Getting Tx", hash)
let _api = await this.cloneApi()
while(true){
try{
const response = await _api.request({
command: 'tx',
transaction: hash,
})
await _api.disconnect()
return response
}catch(e){
this.dbg("Retrying to get", hash)
await _api.disconnect()
_api = await this.cloneApi()
}
}
}
public async readRaw(hash: string): Promise<Memo> {
const tx = await this.getTransaction(hash)
const memo = tx.result.Memos[0].Memo
const memoParsed = {
data: hexDecode(memo.MemoData),
format: hexDecode(memo.MemoFormat),
type: hexDecode(memo.MemoType)
}
this.dbg(hash, "data", memoParsed)
return memoParsed
}
public async treeWrite(data: string, to: string, secret: string, format: 'L' | 'N' = 'L'): Promise<string> {
const wallet = Wallet.fromSecret(secret)
data = await compressB64(data)
const chunks = chunkString(data, PAYLOAD_SIZE)
const latestSequence = await this.getAccountSequence(wallet.address)
const hashes = await Promise.all(Object.entries(chunks).map(([i, chunk]) => this.writeRaw({ data: chunk, format: format }, to, secret, latestSequence+Number(i))))
if (hashes.length === 1) {
return hashes[0]
}
return await this.treeWrite(JSON.stringify(hashes), to, secret, 'N')
}
public async treeRead(hashes: string[]): Promise<string>{
const memos = await Promise.all(hashes.map(hash => this.readRaw(hash)))
const payload: string = await decompressB64(memos.map(memo => memo.data).join(''))
if (memos.some(memo => memo.format === 'N')) {
return await this.treeRead(JSON.parse(payload))
}
return payload
}
public async getAccountSequence(address: string): Promise<number>{
this.dbg("Getting acc info for", address)
const accountInfo = await this.api.request({
command: 'account_info',
account: address,
strict: true,
})
this.dbg("Got account_info", accountInfo)
return Number(accountInfo.result.account_data.Sequence)
}
private dbg(...args: any[]) {
if (this.options.debug) {
console.log.apply(console, args)
}
}
}
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 9.7 KiB

+50 -56
View File
@@ -1,15 +1,15 @@
import { RippleAPI } from 'ripple-lib'
import { htmlTxt, longText, makeTestnetWallet, TEST_CONFIG, TEST_DATA } from './CONSTANTS'
import { getLatestSequence, sendPayment, treeRead, treeWrite } from '../src/xrpIO/ripple-binding'
import { xrpIO } from '../src/xrpIO/xrpl-binding'
import * as chai from 'chai';
import { Wallet } from '../src/util/types';
const utf8 = require('utf8')
const base64 = require('base-64')
var wtf = require('wtfnode');
const expect = chai.expect
let sendWallet: Wallet
let receiveWallet: Wallet
let api: RippleAPI
let api: xrpIO
const ONLY_LARGE_TESTS = true
describe('XRPIO', () => {
before(async function(){
@@ -21,7 +21,7 @@ describe('XRPIO', () => {
beforeEach(async () => {
try {
api = new RippleAPI({ server: TEST_CONFIG.rippleNode })
api = new xrpIO(TEST_CONFIG.rippleNode, {debug: false, connectionTimeout: 100000})
return await api.connect()
} catch (e) {
console.log(e)
@@ -37,70 +37,64 @@ describe('XRPIO', () => {
}
})
let latestSeq
describe('plumbing', () => {
it('getLatestSequence', async () => {
latestSeq = await getLatestSequence(api, sendWallet.address)
expect(latestSeq).to.exist
expect(latestSeq).to.be.a('number')
expect(latestSeq).to.be.greaterThan(0)
})
})
describe('payment', () => {
it('sendPayment', async function () {
it('getAccountSequence', async function(){
// this.skip()
this.timeout(10000)
const result = await sendPayment(api, [{ data: "123" }], sendWallet.address, receiveWallet.address, sendWallet.secret, latestSeq + 1)
expect(result).to.exist
expect(result.resultCode).to.be.equal('tesSUCCESS')
})
const seq = await api.getAccountSequence(sendWallet.address)
expect(seq).to.exist
expect(seq).to.be.a('number')
})
describe('I/O', () => {
let treeRoot
it(`can tree write (${TEST_DATA.length} bytes)`, async function () {
this.timeout(10000)
treeRoot = await treeWrite(api, TEST_DATA, sendWallet, receiveWallet.address)
})
it('can tree read', async function () {
let txHash
it('writeRaw', async function(){
this.skip()
this.timeout(15000)
const data = await treeRead(api, [treeRoot])
expect(data).to.be.equal(TEST_DATA)
txHash = await api.writeRaw({data: TEST_DATA}, receiveWallet.address, sendWallet.secret);
expect(txHash).to.exist
expect(txHash).to.be.a('string')
})
it(`can tree write large (${longText.length} bytes)`, async function () {
this.timeout(30000)
treeRoot = await treeWrite(api, longText, sendWallet, receiveWallet.address)
it('readRaw', async function () {
this.skip()
this.timeout(15000)
const memo = await api.readRaw(txHash)
expect(memo).to.exist
expect(memo.data).to.be.equal(TEST_DATA)
})
it('can tree read large', async function () {
this.timeout(30000)
const data = await treeRead(api, [treeRoot])
expect(data).to.be.equal(longText)
it('treeWrite', async function(){
this.skip()
this.timeout(45000)
txHash = await api.treeWrite(longText, receiveWallet.address, sendWallet.secret)
expect(txHash).to.exist
expect(txHash).to.be.a('string')
})
it(`can tree write extra large (${htmlTxt.length} bytes)`, async function () {
this.timeout(300000)
treeRoot = await treeWrite(api, htmlTxt, sendWallet, receiveWallet.address)
it('treeRead', async function(){
this.skip()
this.timeout(45000)
txHash = await api.treeRead([txHash])
expect(txHash).to.exist
expect(txHash).to.be.equal(longText)
})
it('can tree read extra large', async function () {
this.timeout(300000)
const data = await treeRead(api, [treeRoot])
expect(data).to.be.equal(htmlTxt)
it('treeWrite XL', async function(){
// this.skip()
this.timeout(450000)
txHash = await api.treeWrite(htmlTxt, receiveWallet.address, sendWallet.secret)
expect(txHash).to.exist
expect(txHash).to.be.a('string')
})
it("can r/w binary", async function () {
this.timeout(10000);
it('treeRead XL', async function(){
// this.skip()
this.timeout(450000)
txHash = await api.treeRead([txHash])
expect(txHash).to.exist
expect(txHash).to.be.equal(htmlTxt)
})
const bytes = utf8.encode(TEST_DATA)
const encoded = base64.encode(bytes)
const txHash = await treeWrite(api, encoded, sendWallet, receiveWallet.address)
const res = await treeRead(api, [txHash])
const decoded_bytes = base64.decode(res)
const text = utf8.decode(decoded_bytes)
expect(text).to.be.equal(TEST_DATA)
})
it('print open handles', function(){
wtf.dump()
})
})
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 9.7 KiB