diff --git a/README.md b/README.md
index 3028cdb..cfae64b 100644
--- a/README.md
+++ b/README.md
@@ -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:
+
+
+
+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**.
-## Operation on the main-net is untested and should not be used in production!
+## 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.
# 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 => 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)
diff --git a/package-lock.json b/package-lock.json
index 5aacee7..3be7093 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -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",
diff --git a/package.json b/package.json
index 7b54f85..5c26936 100644
--- a/package.json
+++ b/package.json
@@ -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"
}
}
diff --git a/src/util/types.ts b/src/util/types.ts
index faaf554..a447ad6 100644
--- a/src/util/types.ts
+++ b/src/util/types.ts
@@ -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
+}
\ No newline at end of file
diff --git a/src/xrpIO/ripple-binding.ts b/src/xrpIO/ripple-binding.ts
index 675946c..50002b8 100644
--- a/src/xrpIO/ripple-binding.ts
+++ b/src/xrpIO/ripple-binding.ts
@@ -150,6 +150,7 @@ export const readRaw = async (api: RippleAPI, hash: string): Promise => {
} catch (e) {
// if(debug){
console.log("READRAW ERR", e)
+ api.isConnected
// }
throw e
} finally {
diff --git a/src/xrpIO/xrpl-binding.ts b/src/xrpIO/xrpl-binding.ts
new file mode 100644
index 0000000..f275d5a
--- /dev/null
+++ b/src/xrpIO/xrpl-binding.ts
@@ -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 {
+ if (!this.api.isConnected())
+ await this.api.connect()
+ }
+
+ public async disconnect(): Promise {
+ try{
+ await this.api.disconnect()
+ }catch(e){
+ console.log("DISCONNECT ERROR", e)
+ }
+ }
+
+ private async cloneApi(): Promise {
+ 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 {
+ 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 {
+ this.dbg("Writing data", data)
+ const tx = await this.sendPayment(data, to, secret, sequence)
+ return tx.result.hash
+ }
+
+ private async getTransaction(hash: string): Promise {
+ 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 {
+ 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 {
+ 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{
+ 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{
+ 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)
+ }
+ }
+}
\ No newline at end of file
diff --git a/test/julcMfc.gif b/test/julcMfc.gif
new file mode 100644
index 0000000..495b3a0
Binary files /dev/null and b/test/julcMfc.gif differ
diff --git a/test/primitives.ts b/test/primitives.ts
index 41413bb..7ca7d32 100644
--- a/test/primitives.ts
+++ b/test/primitives.ts
@@ -1,18 +1,18 @@
-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 () {
+ before(async function(){
this.timeout(15000)
sendWallet = await makeTestnetWallet()
receiveWallet = await makeTestnetWallet()
@@ -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)
- })
+ it('getAccountSequence', async function(){
+// this.skip()
+ this.timeout(10000)
+ const seq = await api.getAccountSequence(sendWallet.address)
+ expect(seq).to.exist
+ expect(seq).to.be.a('number')
})
- describe('payment', () => {
- it('sendPayment', async function () {
- 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')
- })
+ let txHash
+ it('writeRaw', async function(){
+ this.skip()
+ this.timeout(15000)
+ txHash = await api.writeRaw({data: TEST_DATA}, receiveWallet.address, sendWallet.secret);
+ expect(txHash).to.exist
+ expect(txHash).to.be.a('string')
})
- 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('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', async function () {
- this.timeout(15000)
- const data = await treeRead(api, [treeRoot])
- expect(data).to.be.equal(TEST_DATA)
- })
+ 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 large (${longText.length} bytes)`, async function () {
- this.timeout(30000)
- treeRoot = await treeWrite(api, longText, 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 large', async function () {
- this.timeout(30000)
- const data = await treeRead(api, [treeRoot])
- expect(data).to.be.equal(longText)
- })
+ 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 tree write extra large (${htmlTxt.length} bytes)`, async function () {
- this.timeout(300000)
- treeRoot = await treeWrite(api, htmlTxt, sendWallet, receiveWallet.address)
- })
-
- it('can tree read extra large', async function () {
- this.timeout(300000)
- const data = await treeRead(api, [treeRoot])
- expect(data).to.be.equal(htmlTxt)
- })
-
- it("can r/w binary", async function () {
- this.timeout(10000);
-
- 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('treeRead XL', async function(){
+// this.skip()
+ this.timeout(450000)
+ txHash = await api.treeRead([txHash])
+ expect(txHash).to.exist
+ expect(txHash).to.be.equal(htmlTxt)
+ })
+
+ it('print open handles', function(){
+ wtf.dump()
})
})
\ No newline at end of file
diff --git a/xrpio.gif b/xrpio.gif
new file mode 100644
index 0000000..495b3a0
Binary files /dev/null and b/xrpio.gif differ