Skip to content

Commit

Permalink
add holding account verifications for the import side - check signers…
Browse files Browse the repository at this point in the history
… and thresholds

support stellarNetwork 'localnet' (core/horizon running on local machine)
rename cli-verify to cli-verifysig
  • Loading branch information
Chris Hatch committed Sep 29, 2017
1 parent 79eea75 commit c916d6a
Show file tree
Hide file tree
Showing 22 changed files with 351 additions and 87 deletions.
14 changes: 9 additions & 5 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
# babel transpile destination
lib

# local xcat config.json - see config.json.template
config.json

# local xcat tradedb.json - see trade-db.js
tradedb.json

# Logs
logs
*.log
Expand Down Expand Up @@ -60,8 +69,3 @@ typings/
# coveralls
coverage

# babel transpile destination
lib

# local config.json - see config.json.template
config.json
9 changes: 4 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,14 +50,13 @@
"jest-cli": "^21.0.0",
"nsp": "^2.6.3"
},
"files": [
"lib"
],
"files": ["lib"],
"jest": {
"roots": ["src/"],
"testEnvironment": "node",
"transform": {
"^.+\\.jsx?$": "babel-jest"
},
"testEnvironment": "node"
}
},
"eslintConfig": {
"extends": "xo-space",
Expand Down
File renamed without changes.
42 changes: 42 additions & 0 deletions src/__tests__/__data__/loadAccountRsp_holdingAccount.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
{
"id": "GCVG6GGMTEOERQ2QRALNLITHULKRHPUJE6RON7B2H5PEGLTODFD6DTLD",
"account_id": "GCVG6GGMTEOERQ2QRALNLITHULKRHPUJE6RON7B2H5PEGLTODFD6DTLD",
"sequence": "18060990314708992",
"subentry_count": 2,
"thresholds": {
"low_threshold": 2,
"med_threshold": 2,
"high_threshold": 2
},
"flags": {
"auth_required": false,
"auth_revocable": false
},
"balances": [
{
"balance": "40.0000000",
"asset_type": "native"
}
],
"signers": [
{
"public_key": "XARL6CZ5HDJL5RZCN3VP2ZLRZXKFFU2KPH5U44XZRYSG2NZMNKMFKVAT",
"weight": 1,
"key": "XARL6CZ5HDJL5RZCN3VP2ZLRZXKFFU2KPH5U44XZRYSG2NZMNKMFKVAT",
"type": "sha256_hash"
},
{
"public_key": "GCG52B2LBYVTPUCIQFDB7VBXARK4OUV5NSEQ5R6T343FW7GR4MBUM3V6",
"weight": 1,
"key": "GCG52B2LBYVTPUCIQFDB7VBXARK4OUV5NSEQ5R6T343FW7GR4MBUM3V6",
"type": "ed25519_public_key"
},
{
"public_key": "GCVG6GGMTEOERQ2QRALNLITHULKRHPUJE6RON7B2H5PEGLTODFD6DTLD",
"weight": 0,
"key": "GCVG6GGMTEOERQ2QRALNLITHULKRHPUJE6RON7B2H5PEGLTODFD6DTLD",
"type": "ed25519_public_key"
}
],
"data": {}
}
File renamed without changes.
3 changes: 2 additions & 1 deletion src/__tests__/__snapshots__/config.test.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,9 @@ exports[`config throws if unknown stellarNetwork 1`] = `
\\"schemaPath\\": \\"#/properties/stellarNetwork/enum\\",
\\"params\\": {
\\"allowedValues\\": [
\\"public\\",
\\"testnet\\",
\\"public\\"
\\"localnet\\"
]
},
\\"message\\": \\"should be equal to one of the allowed values\\"
Expand Down
2 changes: 1 addition & 1 deletion src/__tests__/config.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import expect from 'expect'
import {clone} from '../utils'
import Config from '../config'

const config1 = require('./data/config1.json')
const config1 = require('./__data__/config1.json')

describe('config', () => {
it('creates new Config that has all properties of the given config object', () => {
Expand Down
4 changes: 2 additions & 2 deletions src/__tests__/protocol.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import Trade from '../trade'
import Config from '../config'
import Protocol from '../protocol'

import config1 from './data/config1'
import trade1 from './data/trade1'
import config1 from './__data__/config1'
import trade1 from './__data__/trade1'

describe('protocol', () => {
const config = new Config(config1)
Expand Down
116 changes: 113 additions & 3 deletions src/__tests__/stellar.test.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,44 @@
import expect from 'expect'
import Promise from 'bluebird'
import sdk from 'stellar-sdk'
import Stellar from '../stellar'
import {clone, stellarEncodeHash} from '../utils'

import loadAccountRspHoldAcc from './__data__/loadAccountRsp_holdingAccount'

/*
* Test Data
*/

const HOLDING_ACC = 'GCVG6GGMTEOERQ2QRALNLITHULKRHPUJE6RON7B2H5PEGLTODFD6DTLD'
const WITHDRAWER_ACC =
'GCG52B2LBYVTPUCIQFDB7VBXARK4OUV5NSEQ5R6T343FW7GR4MBUM3V6'
const RANDOM_ACC = sdk.Keypair.random().publicKey()

const HASH_X =
'22bf0b3d38d2bec7226eeafd6571cdd452d34a79fb4e72f98e246d372c6a9855'
const HASH_X_STELLAR_ENCODING = stellarEncodeHash(HASH_X)

const SIGNERS = [
{
public_key: HASH_X_STELLAR_ENCODING,
weight: 1,
key: HASH_X_STELLAR_ENCODING,
type: 'sha256_hash',
},
{
public_key: WITHDRAWER_ACC,
weight: 1,
key: WITHDRAWER_ACC,
type: 'ed25519_public_key',
},
{
public_key: HOLDING_ACC,
weight: 0,
key: HOLDING_ACC,
type: 'ed25519_public_key',
},
]

describe('stellar', () => {
it('creates a new instance for public network', () => {
Expand All @@ -23,22 +61,94 @@ describe('stellar', () => {
)
})

describe('calling isValidHoldingAccount', () => {
describe('validHoldingAccountSignerSetup', () => {
const expectValid = (opts = {}, valid = true) => {
expect(
Stellar.validHoldingAccountSignerSetup(
opts.signers ? opts.signers : SIGNERS,
opts.holdingAcc ? opts.holdingAcc : HOLDING_ACC,
opts.withdrawer ? opts.withdrawer : WITHDRAWER_ACC,
opts.hashX ? opts.hashX : HASH_X
)
).toEqual(valid)
}

it('passes correct set of signers', () => {
expectValid()
})

it('fails a non matching hashX', () => {
const DIFF_HASH = HASH_X.replace('a', 'f')
expectValid({hashX: DIFF_HASH}, false)
})

it('fails a non matching withdrawer', () => {
expectValid({withdrawer: RANDOM_ACC}, false)
})

it('fails if master key weight non 0', () => {
const SIGNERS_MASTER_NON_ZERO = clone(SIGNERS)
SIGNERS_MASTER_NON_ZERO[2].weight = 1
expectValid({signers: SIGNERS_MASTER_NON_ZERO}, false)
})

it('fails if withdrawer key weight not 1', () => {
const SIGNERS_WITHDRAWER_NOT_ONE = clone(SIGNERS)
SIGNERS_WITHDRAWER_NOT_ONE[1].weight = 2
expectValid({signers: SIGNERS_WITHDRAWER_NOT_ONE}, false)
})

it('fails if hashx key weight not 1', () => {
const SIGNERS_HASH_X_NOT_ONE = clone(SIGNERS)
SIGNERS_HASH_X_NOT_ONE[0].weight = 2
expectValid({signers: SIGNERS_HASH_X_NOT_ONE}, false)
})
})

describe('validHoldingAccountThresholds', () => {
const thresholds = (l, m, h) => {
return {low_threshold: l, med_threshold: m, high_threshold: h}
}
const expectValid = (l, m, h, valid = true) =>
expect(
Stellar.validHoldingAccountThresholds(thresholds(l, m, h))
).toEqual(valid)

it('returns true for a valid thesholds', () => {
expectValid(2, 2, 2)
})

it('returns false for invalid thresholds', () => {
expectValid(1, 2, 2, false)
expectValid(2, 1, 2, false)
expectValid(2, 2, 1, false)
expectValid(0, 0, 0, false)
expectValid(1, 1, 1, false)
expectValid(2, 2, 3, false)
})
})

describe('isValidHoldingAccount', () => {
const st = new Stellar(sdk, 'testnet')

it('returns true for a valid holding account', async () => {
st.server.loadAccount = () =>
new Promise(resolve => resolve(loadAccountRspHoldAcc))
const retVal = await st.isValidHoldingAccount(
'GCVG6GGMTEOERQ2QRALNLITHULKRHPUJE6RON7B2H5PEGLTODFD6DTLD',
'GCOCD2SVBEOB4PWMS7FEOFM27TPSZBO5LFR24NBMT6Q73OIUKBKDKFBS',
'GCG52B2LBYVTPUCIQFDB7VBXARK4OUV5NSEQ5R6T343FW7GR4MBUM3V6',
'22bf0b3d38d2bec7226eeafd6571cdd452d34a79fb4e72f98e246d372c6a9855'
)
expect(retVal).toEqual(true)
})

it('returns false if holding account does not exist', async () => {
st.server.loadAccount = () =>
new Promise(() => {
throw new st.sdk.NotFoundError()
})
const retVal = await st.isValidHoldingAccount(
'GCVGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG'
'GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG'
)
expect(retVal).toEqual(false)
})
Expand Down
14 changes: 12 additions & 2 deletions src/__tests__/trade-db.test.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import expect from 'expect'
import {existsSync, unlinkSync} from 'fs'
import {existsSync, renameSync, unlinkSync} from 'fs'

import {clone} from '../utils'
import TradeDB from '../trade-db'
import testTrade from './data/trade1.json'
import testTrade from './__data__/trade1.json'

const DEFAULT_DB_PATH = './tradedb.json'
const TRADE_ID_REGEX = /^[^-]*-[^-]*-[^-]*$/
Expand All @@ -13,6 +13,16 @@ const deleteIfExists = filename => {
}

describe('trade-db', () => {
const BACKUP_DB_PATH = './tradedb.json.backup'

beforeAll(() => {
if (existsSync(DEFAULT_DB_PATH)) renameSync(DEFAULT_DB_PATH, BACKUP_DB_PATH)
})

afterAll(() => {
if (existsSync(BACKUP_DB_PATH)) renameSync(BACKUP_DB_PATH, DEFAULT_DB_PATH)
})

afterEach(() => {
deleteIfExists(DEFAULT_DB_PATH)
})
Expand Down
2 changes: 1 addition & 1 deletion src/__tests__/trade.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import expect from 'expect'
import {clone} from '../utils'
import Trade from '../trade'

const trade1 = require('./data/trade1.json')
const trade1 = require('./__data__/trade1.json')

describe('trade', () => {
it('creates new Trade that has all properties of the given trade object', () => {
Expand Down
12 changes: 11 additions & 1 deletion src/__tests__/utils.test.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import expect from 'expect'
import {isSha256Hash, sign, verify} from '../utils'
import {isSha256Hash, sign, stellarEncodeHash, verify} from '../utils'
import stellarSdk from 'stellar-sdk'

// https://stackoverflow.com/a/8571649
Expand Down Expand Up @@ -36,4 +36,14 @@ describe('utils', () => {
).toEqual(true)
})
})

describe('stellarEncodeHash', () => {
it('encodes sha256 hash to Stellars internal hashx signer form', () => {
expect(
stellarEncodeHash(
'22bf0b3d38d2bec7226eeafd6571cdd452d34a79fb4e72f98e246d372c6a9855'
)
).toEqual('XARL6CZ5HDJL5RZCN3VP2ZLRZXKFFU2KPH5U44XZRYSG2NZMNKMFKVAT')
})
})
})
29 changes: 28 additions & 1 deletion src/cli/cli-import.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,5 +40,32 @@ console.log(`Check status running ...`)
protocol.status().then(status => {
console.log(`status: ${status}`)

// prompt for next action or show waiting for counterparty action
// next step is Ethereum prepare by this local user
if (
status === Protocol.Status.ETHEREUM_PREPARE &&
protocol.trade.ethereum.depositor === protocol.config.ethereumPublicAddress
) {
// TODO: show a summary of the trade deal to the importer

// TODO: prompt the importer before going ahead with this step....

// HTTPProvider NOT supported! :
// protocol.eth.htlc.events.allEvents((error, event) => {
// if (error) console.log(error)
// console.log(event)
// })

// could try web3.eth.subscribe too ...

protocol
.ethereumPrepare(
receipt =>
console.log(`EthereumPrepare completed: ${JSON.stringify(receipt)}!`),
error => console.log(`EthereumPrepare failed: ${JSON.stringify(error)}`)
)
.then(rec => console.log(`REC:` + JSON.stringify(rec)))
.catch(err => console.error(`ERR:${JSON.stringify(err)}`))
} else {
// subscribe and wait for counterparty to complete EthereumPrepare
}
})
8 changes: 4 additions & 4 deletions src/cli/cli-verify.js → src/cli/cli-verifysig.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,16 @@ import chalk from 'chalk'
import {existsSync} from 'fs'

import Trade from '../trade'
import {verifyArgTradeFile} from './utils'
import {commander as program, fileToObj, fileToStr, verify} from '../utils'
import {commander as program, verifyArgTradeFile} from './utils'
import {fileToObj, fileToStr, verify} from '../utils'

let signatureFile, tradeJSON
program
.description(
'Verify a signature for the trade file was produced by the stellar depositor.\n'
)
.arguments('<trade.json> <trade.json.sig>')
.action(function(jsonFile, sigFile) {
.action((jsonFile, sigFile) => {
tradeJSON = jsonFile
signatureFile = sigFile
})
Expand All @@ -20,7 +20,7 @@ program
if (!verifyArgTradeFile(tradeJSON)) program.help()
if (!existsSync(signatureFile)) program.help()

console.log(`Verifying signature ...`)
console.log(`Verifying signature ...\n`)
const trade = new Trade(fileToObj(tradeJSON))
const signer = trade.stellar.depositor
const signature = fileToStr(signatureFile)
Expand Down
4 changes: 2 additions & 2 deletions src/cli/cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ program
.alias('n')
.command('import <trade.json>', 'Import a trade from a trade.json file')
.alias('i')
.command('status <tradeId>', 'Import a trade from a trade.json file')
.command('status <tradeId>', 'Check status of a trade')
.alias('s')
.command(
'verify <trade.json> <trade.json.sig>',
'verifysig <trade.json> <trade.json.sig>',
'Verify signature for a trade.json'
)
.alias('v')
Expand Down
Loading

0 comments on commit c916d6a

Please sign in to comment.