Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Aens lima compatibility #687

Merged
merged 4 commits into from
Oct 2, 2019
Merged
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
2 changes: 1 addition & 1 deletion docker/aeternity_node_mean16.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ chain:
"1": 0
"2": 2
"3": 4
"4": 5
"4": 6

mining:
autostart: true
Expand Down
20 changes: 15 additions & 5 deletions es/ae/aens.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@

import * as R from 'ramda'
import { encodeBase58Check, salt } from '../utils/crypto'
import { commitmentHash, isNameValid } from '../tx/builder/helpers'
import { commitmentHash, prelimaCommitmentHash, isNameValid } from '../tx/builder/helpers'
import Ae from './'
import { CLIENT_TTL, NAME_TTL } from '../tx/builder/schema'

Expand Down Expand Up @@ -176,8 +176,11 @@ async function claim (name, salt, options = {}) {
}))

const result = await this.send(claimTx, opt)
const nameInter = this.Chain.defaults.waitMined ? await this.aensQuery(name, opt) : {}
return Object.assign(result, nameInter)
if (opt.vsn === 1) {
const nameInter = this.Chain.defaults.waitMined ? await this.aensQuery(name, opt) : {}
return Object.assign(result, nameInter)
}
return result
}

/**
Expand All @@ -190,11 +193,18 @@ async function claim (name, salt, options = {}) {
* @return {Promise<Object>}
*/
async function preclaim (name, options = {}) {
// TODO remove cross compatibility
const { version } = this.getNodeInfo()
const [majorVersion] = version.split('.')
const vsn = +majorVersion === 5 && version !== '5.0.0-rc.1' ? 2 : 1

isNameValid(name)
const opt = R.merge(this.Ae.defaults, options)
const _salt = salt()
const height = await this.height()
const hash = await commitmentHash(name, _salt)
const hash = vsn === 1
? await prelimaCommitmentHash(name, _salt)
: await commitmentHash(name, _salt)

const preclaimTx = await this.namePreclaimTx(R.merge(opt, {
accountId: await this.address(opt),
Expand All @@ -206,7 +216,7 @@ async function preclaim (name, options = {}) {
return Object.freeze({
...result,
height,
claim: options => this.aensClaim(name, _salt, { ...options, onAccount: opt.onAccount }),
claim: options => this.aensClaim(name, _salt, { ...options, onAccount: opt.onAccount, vsn }),
salt: _salt,
commitmentId: hash
})
Expand Down
18 changes: 17 additions & 1 deletion es/tx/builder/helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,22 @@ export function formatSalt (salt) {
return Buffer.from(salt.toString(16).padStart(64, '0'), 'hex')
}

/**
* Generate the commitment hash by hashing the formatted salt and
* name, base 58 encoding the result and prepending 'cm_'
*
* @alias module:@aeternity/aepp-sdk/es/tx/builder/helpers
* @function prelimaCommitmentHash
* @category async
* @rtype (name: String, salt?: String) => hash: Promise[String]
* @param {String} name - Name to be registered
* @param {Number} salt Random salt
* @return {String} Commitment hash
*/
export async function prelimaCommitmentHash (name, salt = createSalt()) {
return `cm_${encodeBase58Check(hash(Buffer.concat([nameId(name), formatSalt(salt)])))}`
}

/**
* Generate the commitment hash by hashing the formatted salt and
* name, base 58 encoding the result and prepending 'cm_'
Expand All @@ -92,7 +108,7 @@ export function formatSalt (salt) {
* @return {String} Commitment hash
*/
export async function commitmentHash (name, salt = createSalt()) {
return `cm_${encodeBase58Check(hash(Buffer.concat([nameId(name), formatSalt(salt)])))}`
return `cm_${encodeBase58Check(hash(Buffer.concat([Buffer.from(name), formatSalt(salt)])))}`
}

/**
Expand Down
24 changes: 12 additions & 12 deletions es/tx/builder/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -206,15 +206,15 @@ function getOracleRelativeTtl (params) {
* @return {String|Number}
* @example calculateMinFee('spendTx', { gas, params })
*/
export function calculateMinFee (txType, { gas = 0, params }) {
export function calculateMinFee (txType, { gas = 0, params, vsn }) {
const multiplier = BigNumber(1e9) // 10^9 GAS_PRICE
if (!params) return BigNumber(DEFAULT_FEE).times(multiplier).toString(10)

let actualFee = buildFee(txType, { params: { ...params, fee: 0 }, multiplier, gas })
let actualFee = buildFee(txType, { params: { ...params, fee: 0 }, multiplier, gas, vsn })
let expected = BigNumber(0)

while (!actualFee.eq(expected)) {
actualFee = buildFee(txType, { params: { ...params, fee: actualFee }, multiplier, gas })
actualFee = buildFee(txType, { params: { ...params, fee: actualFee }, multiplier, gas, vsn })
expected = actualFee
}
return expected.toString(10)
Expand All @@ -228,8 +228,8 @@ export function calculateMinFee (txType, { gas = 0, params }) {
* @param multiplier
* @return {BigNumber}
*/
function buildFee (txType, { params, gas = 0, multiplier }) {
const { rlpEncoded: txWithOutFee } = buildTx({ ...params }, txType)
function buildFee (txType, { params, gas = 0, multiplier, vsn }) {
const { rlpEncoded: txWithOutFee } = buildTx({ ...params }, txType, { vsn })
const txSize = txWithOutFee.length
return TX_FEE_BASE_GAS(txType)
.plus(TX_FEE_OTHER_GAS(txType)({ txSize, relativeTtl: getOracleRelativeTtl(params) }))
Expand All @@ -249,10 +249,10 @@ function buildFee (txType, { params, gas = 0, multiplier }) {
* @return {String|Number}
* @example calculateFee(null, 'spendTx', { gas, params })
*/
export function calculateFee (fee = 0, txType, { gas = 0, params, showWarning = true } = {}) {
export function calculateFee (fee = 0, txType, { gas = 0, params, showWarning = true, vsn } = {}) {
if (!params && showWarning) console.warn(`Can't build transaction fee, we will use DEFAULT_FEE(${DEFAULT_FEE})`)

const minFee = calculateMinFee(txType, { params, gas })
const minFee = calculateMinFee(txType, { params, gas, vsn })
if (fee && BigNumber(minFee).gt(BigNumber(fee)) && showWarning) console.warn(`Transaction fee is lower then min fee! Min fee: ${minFee}`)

return fee || minFee
Expand Down Expand Up @@ -333,15 +333,15 @@ export function unpackRawTx (binary, schema) {
* @throws {Error} Validation error
* @return {Object} { tx, rlpEncoded, binary } Object with tx -> Base64Check transaction hash with 'tx_' prefix, rlp encoded transaction and binary transaction
*/
export function buildTx (params, type, { excludeKeys = [], prefix = 'tx' } = {}) {
export function buildTx (params, type, { excludeKeys = [], prefix = 'tx', vsn = VSN } = {}) {
if (!TX_SERIALIZATION_SCHEMA[type]) {
throw new Error('Transaction serialization not implemented for ' + type)
}
if (!TX_SERIALIZATION_SCHEMA[type][VSN]) {
throw new Error('Transaction serialization not implemented for ' + type + ' version ' + VSN)
if (!TX_SERIALIZATION_SCHEMA[type][vsn]) {
throw new Error('Transaction serialization not implemented for ' + type + ' version ' + vsn)
}
const [schema, tag] = TX_SERIALIZATION_SCHEMA[type][VSN]
const binary = buildRawTx({ ...params, VSN, tag }, schema, { excludeKeys }).filter(e => e !== undefined)
const [schema, tag] = TX_SERIALIZATION_SCHEMA[type][vsn]
const binary = buildRawTx({ ...params, VSN: vsn, tag }, schema, { excludeKeys }).filter(e => e !== undefined)

const rlpEncoded = rlp.encode(binary)
const tx = encode(rlpEncoded, prefix)
Expand Down
17 changes: 15 additions & 2 deletions es/tx/builder/schema.js
Original file line number Diff line number Diff line change
Expand Up @@ -425,6 +425,17 @@ const NAME_CLAIM_TX = [
TX_FIELD('ttl', FIELD_TYPES.int)
]

const NAME_CLAIM_TX_2 = [
...BASE_TX,
TX_FIELD('accountId', FIELD_TYPES.id, 'ak'),
TX_FIELD('nonce', FIELD_TYPES.int),
TX_FIELD('name', FIELD_TYPES.binary, 'nm'),
TX_FIELD('nameSalt', FIELD_TYPES.int),
TX_FIELD('nameFee', FIELD_TYPES.int),
TX_FIELD('fee', FIELD_TYPES.int),
TX_FIELD('ttl', FIELD_TYPES.int)
]

const NAME_UPDATE_TX = [
...BASE_TX,
TX_FIELD('accountId', FIELD_TYPES.id, 'ak'),
Expand Down Expand Up @@ -852,7 +863,8 @@ export const TX_SERIALIZATION_SCHEMA = {
1: TX_SCHEMA_FIELD(NAME_PRE_CLAIM_TX, OBJECT_TAG_NAME_SERVICE_PRECLAIM_TRANSACTION)
},
[TX_TYPE.nameClaim]: {
1: TX_SCHEMA_FIELD(NAME_CLAIM_TX, OBJECT_TAG_NAME_SERVICE_CLAIM_TRANSACTION)
1: TX_SCHEMA_FIELD(NAME_CLAIM_TX, OBJECT_TAG_NAME_SERVICE_CLAIM_TRANSACTION),
2: TX_SCHEMA_FIELD(NAME_CLAIM_TX_2, OBJECT_TAG_NAME_SERVICE_CLAIM_TRANSACTION)
},
[TX_TYPE.nameUpdate]: {
1: TX_SCHEMA_FIELD(NAME_UPDATE_TX, OBJECT_TAG_NAME_SERVICE_UPDATE_TRANSACTION)
Expand Down Expand Up @@ -990,7 +1002,8 @@ export const TX_DESERIALIZATION_SCHEMA = {
1: TX_SCHEMA_FIELD(NAME_PRE_CLAIM_TX, OBJECT_TAG_NAME_SERVICE_PRECLAIM_TRANSACTION)
},
[OBJECT_TAG_NAME_SERVICE_CLAIM_TRANSACTION]: {
1: TX_SCHEMA_FIELD(NAME_CLAIM_TX, OBJECT_TAG_NAME_SERVICE_CLAIM_TRANSACTION)
1: TX_SCHEMA_FIELD(NAME_CLAIM_TX, OBJECT_TAG_NAME_SERVICE_CLAIM_TRANSACTION),
2: TX_SCHEMA_FIELD(NAME_CLAIM_TX_2, OBJECT_TAG_NAME_SERVICE_CLAIM_TRANSACTION)
},
[OBJECT_TAG_NAME_SERVICE_UPDATE_TRANSACTION]: {
1: TX_SCHEMA_FIELD(NAME_UPDATE_TX, OBJECT_TAG_NAME_SERVICE_UPDATE_TRANSACTION)
Expand Down
10 changes: 5 additions & 5 deletions es/tx/tx.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,13 +69,13 @@ async function namePreclaimTx ({ accountId, commitmentId }) {
return tx
}

async function nameClaimTx ({ accountId, name, nameSalt }) {
async function nameClaimTx ({ accountId, name, nameSalt, vsn = 2 }) {
// Calculate fee, get absolute ttl (ttl + height), get account nonce
const { fee, ttl, nonce } = await this.prepareTxParams(TX_TYPE.nameClaim, { senderId: accountId, ...R.head(arguments) })
const { fee, ttl, nonce } = await this.prepareTxParams(TX_TYPE.nameClaim, { senderId: accountId, ...R.head(arguments), vsn })

// Build transaction using sdk (if nativeMode) or build on `AETERNITY NODE` side
const { tx } = this.nativeMode
? buildTx(R.merge(R.head(arguments), { nonce, ttl, fee }), TX_TYPE.nameClaim)
? buildTx(R.merge(R.head(arguments), { nonce, ttl, fee }), TX_TYPE.nameClaim, { vsn })
: await this.api.postNameClaim(R.merge(R.head(arguments), { nonce, ttl, fee: parseInt(fee) }))

return tx
Expand Down Expand Up @@ -422,7 +422,7 @@ async function getAccountNonce (accountId, nonce) {
* @param {Object} params Object which contains all tx data
* @return {Object} { ttl, nonce, fee } Object with account nonce, absolute ttl and transaction fee
*/
async function prepareTxParams (txType, { senderId, nonce: n, ttl: t, fee: f, gas, absoluteTtl }) {
async function prepareTxParams (txType, { senderId, nonce: n, ttl: t, fee: f, gas, absoluteTtl, vsn }) {
const account = await this.getAccount(senderId).catch(e => ({ nonce: 0 }))
// Is GA account
if (account.contractId) {
Expand All @@ -431,7 +431,7 @@ async function prepareTxParams (txType, { senderId, nonce: n, ttl: t, fee: f, ga
n = n || (account.nonce + 1)
}
const ttl = await (calculateTtl.bind(this)(t, !absoluteTtl))
const fee = calculateFee(f, txType, { showWarning: this.showWarning, gas, params: R.merge(R.last(arguments), { nonce: n, ttl }) })
const fee = calculateFee(f, txType, { showWarning: this.showWarning, gas, params: R.merge(R.last(arguments), { nonce: n, ttl }), vsn })
return { fee, ttl, nonce: n }
}

Expand Down
60 changes: 40 additions & 20 deletions test/integration/aens.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,65 +24,75 @@ function randomName () {
return Math.floor(Math.random() * Number.MAX_SAFE_INTEGER).toString(36) + '.test'
}

plan('10000000000000000')
plan('9000000000000000000000')

describe.skip('Aens', function () {
describe('Aens', function () {
configure(this)

let aens
let nameHash
let nameAuctionsSupported
const account = generateKeyPair()
const name = randomName()

before(async function () {
aens = await ready(this)
await aens.spend('1000000000000000', account.publicKey)
const { version } = aens.getNodeInfo()
const [majorVersion] = version.split('.')
nameAuctionsSupported = +majorVersion === 5 && version !== '5.0.0-rc.1'
})

const prelima = fn => async () => !nameAuctionsSupported ? fn() : undefined
const lima = fn => async () => nameAuctionsSupported ? fn() : undefined

describe('fails on', () => {
const name = randomName()

it('querying non-existent names', async () => {
it('querying non-existent names', prelima(async () => {
return aens.aensQuery(name).should.eventually.be.rejected
})
}))

it('updating names not owned by the account', async () => {
it('updating names not owned by the account', prelima(async () => {
const preclaim = await aens.aensPreclaim(name)
const claim = await preclaim.claim()
const newAccount = generateKeyPair()

const aens2 = await BaseAe()
aens2.setKeypair(newAccount)
return aens2.aensUpdate(claim.id, newAccount.publicKey, { blocks: 1 }).should.eventually.be.rejected
})
}))
})

it('claims names', async () => {
it('claims names', prelima(async () => {
const preclaim = await aens.aensPreclaim(name)
preclaim.should.be.an('object')
return preclaim.claim().should.eventually.be.an('object')
})
preclaim.claim().should.eventually.be.an('object')
}))

it('queries names', async () => {
it('queries names', prelima(async () => {
// For some reason the node will return 404 when name is queried
// just right after claim tx has been mined so we wait 0.5s
await new Promise(resolve => setTimeout(resolve, 500))
return aens.aensQuery(name).should.eventually.be.an('object')
})
}))

it('updates names', async () => {
it('updates names', prelima(async () => {
const claim = await aens.aensQuery(name)
nameHash = claim.id
const address = await aens.address()
return claim.update(address).should.eventually.deep.include({
pointers: [R.fromPairs([['key', 'account_pubkey'], ['id', address]])]
})
})
}))

it('Spend by name', async () => {
it('Spend by name', prelima(async () => {
const current = await aens.address()
const onAccount = aens.addresses().find(acc => acc !== current)
await aens.spend(100, name, { onAccount })
})
}))

it('transfers names', async () => {
it('transfers names', prelima(async () => {
const claim = await aens.aensQuery(name)

await claim.transfer(account.publicKey)
Expand All @@ -94,9 +104,9 @@ describe.skip('Aens', function () {
return claim2.update(account.publicKey).should.eventually.deep.include({
pointers: [R.fromPairs([['key', 'account_pubkey'], ['id', account.publicKey]])]
})
})
}))

it('revoke names', async () => {
it('revoke names', prelima(async () => {
const aens2 = await BaseAe()
aens2.setKeypair(account)

Expand All @@ -105,14 +115,24 @@ describe.skip('Aens', function () {
await aensName.revoke()

return aens2.aensQuery(name).should.be.rejectedWith(Error)
})
}))

it('PreClaim name using specific account', async () => {
it('PreClaim name using specific account', prelima(async () => {
const current = await aens.address()
const onAccount = aens.addresses().find(acc => acc !== current)

const preclaim = await aens.aensPreclaim(name, { onAccount })
preclaim.should.be.an('object')
preclaim.tx.accountId.should.be.equal(onAccount)
}))

describe('name auctions', function () {
it('claims names', lima(async () => {
const name = '1234567890123456.aet'
const preclaim = await aens.aensPreclaim(name)
preclaim.should.be.an('object')
preclaim.claim({ nameFee: '1000000000000000000000' }).should.eventually.be.an('object')
aens.aensClaim(name, 0, { nameFee: '2000000000000000000000' }).should.eventually.be.an('object')
}))
})
})
7 changes: 5 additions & 2 deletions test/integration/transaction.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ const recipientId = 'ak_2iBPH7HUz3cSDVEUWiHg76MZJ6tZooVNBmmxcgVK6VV8KAE688'
const name = 'test123test.test'
const nameHash = `nm_${encodeBase58Check(Buffer.from(name))}`
const nameId = 'nm_2sFnPHi5ziAqhdApSpRBsYdomCahtmk3YGNZKYUTtUNpVSMccC'
const nameFee = '1000000000000000000000'
const pointers = [{ key: 'account_pubkey', id: senderId }]

// Oracle
Expand Down Expand Up @@ -91,13 +92,15 @@ describe('Native Transaction', function () {
accountId: senderId,
nonce,
name: nameHash,
nameSalt: _salt
nameSalt: _salt,
nameFee
})
const nativeTx = await clientNative.nameClaimTx({
accountId: senderId,
nonce,
name: nameHash,
nameSalt: _salt
nameSalt: _salt,
nameFee
})
txFromAPI.should.be.equal(nativeTx)
})
Expand Down