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 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 # 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**. 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 /> <br />
# Quickstart # Quickstart
```typescript ```typescript
import {RippleAPI} from 'ripple-lib' import { xrpIO } from "xrpio"
import {treeRead, treeWrite} from 'xrpio'
const api = new RippleAPI({ server: "..." }) const api = new xrpIO("wss://some_ripple_node.net:51233")
await api.connect() await api.connect()
const dataRootHash = await treeWrite( txHash = await api.treeWrite("arbitrary text 123", receiveWallet.address, sendWallet.secret)
api, data = await api.treeRead([txHash])
"Arbitrary string data 123",
{
address: "Sender address",
secret: "Sender private key"
},
"Receiver address"
)
const data = await treeRead(api, [dataRootHash]) console.log(data) //"arbitrary text 123"
console.log(data) //"Arbitrary string data 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) # [Full documentation](https://gitea.nitowa.xyz/docs/xrpio)
+137 -4
View File
@@ -1,6 +1,6 @@
{ {
"name": "xrpio", "name": "xrpio",
"version": "0.0.7", "version": "0.0.10",
"lockfileVersion": 1, "lockfileVersion": 1,
"requires": true, "requires": true,
"dependencies": { "dependencies": {
@@ -174,6 +174,53 @@
"integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==",
"dev": true "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": { "bn.js": {
"version": "5.2.0", "version": "5.2.0",
"resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.0.tgz", "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": { "buffer": {
"version": "5.6.0", "version": "5.6.0",
"resolved": "https://registry.npmjs.org/buffer/-/buffer-5.6.0.tgz", "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.6.0.tgz",
@@ -447,7 +512,6 @@
"version": "1.1.7", "version": "1.1.7",
"resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz",
"integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==",
"dev": true,
"requires": { "requires": {
"cipher-base": "^1.0.3", "cipher-base": "^1.0.3",
"create-hash": "^1.1.0", "create-hash": "^1.1.0",
@@ -653,6 +717,11 @@
"safe-buffer": "^5.1.1" "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": { "fill-range": {
"version": "7.0.1", "version": "7.0.1",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", "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", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" "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": { "nanoid": {
"version": "3.2.0", "version": "3.2.0",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.2.0.tgz", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.2.0.tgz",
@@ -1445,7 +1519,6 @@
"version": "3.1.1", "version": "3.1.1",
"resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.1.tgz", "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.1.tgz",
"integrity": "sha512-4Ejy1OPxi9f2tt1rRV7Go7zmfDQ+ZectEQz3VGUQhgq62HtIRPDyG/JtnwIxs6x3uNMwo2V7q1fMvKjb+Tnpqg==", "integrity": "sha512-4Ejy1OPxi9f2tt1rRV7Go7zmfDQ+ZectEQz3VGUQhgq62HtIRPDyG/JtnwIxs6x3uNMwo2V7q1fMvKjb+Tnpqg==",
"dev": true,
"requires": { "requires": {
"create-hash": "^1.1.2", "create-hash": "^1.1.2",
"create-hmac": "^1.1.4", "create-hmac": "^1.1.4",
@@ -1504,7 +1577,6 @@
"version": "2.1.0", "version": "2.1.0",
"resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
"integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==",
"dev": true,
"requires": { "requires": {
"safe-buffer": "^5.1.0" "safe-buffer": "^5.1.0"
} }
@@ -1740,6 +1812,25 @@
"has-flag": "^4.0.0" "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": { "to-regex-range": {
"version": "5.0.1", "version": "5.0.1",
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
@@ -1831,6 +1922,11 @@
"handlebars": "^4.7.7" "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": { "typescript": {
"version": "4.5.5", "version": "4.5.5",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.5.5.tgz", "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.5.5.tgz",
@@ -1941,6 +2037,14 @@
"is-typed-array": "^1.1.7" "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": { "wordwrap": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", "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", "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.7.tgz",
"integrity": "sha512-KMvVuFzpKBuiIXW3E4u3mySRO2/mCHSyZDJQM5NQ9Q9KHWHWh0NHgfbRMLLrceUK5qAL4ytALJbpRMjixFZh8A==" "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": { "y18n": {
"version": "5.0.8", "version": "5.0.8",
"resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
+5 -3
View File
@@ -1,6 +1,6 @@
{ {
"name": "xrpio", "name": "xrpio",
"version": "0.0.10", "version": "0.1.0",
"repository": { "repository": {
"type": "git", "type": "git",
"url": "https://gitea.nitowa.xyz/npm-packages/xrpio.git" "url": "https://gitea.nitowa.xyz/npm-packages/xrpio.git"
@@ -28,7 +28,8 @@
"author": "nitowa", "author": "nitowa",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"ripple-lib": "^1.10.0" "ripple-lib": "^1.10.0",
"xrpl": "^2.1.1"
}, },
"devDependencies": { "devDependencies": {
"@types/chai": "^4.2.21", "@types/chai": "^4.2.21",
@@ -45,6 +46,7 @@
"typedoc": "^0.22.11", "typedoc": "^0.22.11",
"typedoc-plugin-markdown": "^3.11.12", "typedoc-plugin-markdown": "^3.11.12",
"typescript": "^4.5.0", "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 PublicKey = string
export type Amount = number export type Amount = number
export type TxHash = string 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) { } catch (e) {
// if(debug){ // if(debug){
console.log("READRAW ERR", e) console.log("READRAW ERR", e)
api.isConnected
// } // }
throw e throw e
} finally { } 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

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

After

Width:  |  Height:  |  Size: 9.7 KiB