From 5890f9fa3b789fbeda2bac2b468b6a5ff09eef64 Mon Sep 17 00:00:00 2001 From: Daniel Byrne Date: Tue, 5 Jan 2021 16:12:14 -0800 Subject: [PATCH 1/7] feat(node): Update all native contracts for preview4 changes --- packages/neo-one-client-common/src/crypto.ts | 10 ++ .../neo-one-client-common/src/models/types.ts | 1 + .../src/models/ContractStateModel.ts | 20 +-- .../neo-one-node-core/src/ContractState.ts | 52 +++--- .../neo-one-node-core/src/DesignationRole.ts | 4 + packages/neo-one-node-core/src/Native.ts | 39 +++- .../neo-one-node-core/src/OracleRequest.ts | 62 +++++++ packages/neo-one-node-core/src/index.ts | 2 + .../src/manifest/ContractManifest.ts | 18 +- .../src/CachedCommittee.ts | 31 ++++ .../src/DesignationContract.ts | 63 +++++++ packages/neo-one-node-native/src/GASToken.ts | 8 +- .../neo-one-node-native/src/KeyBuilder.ts | 14 ++ .../src/ManagementContract.ts | 42 +++++ packages/neo-one-node-native/src/NEOToken.ts | 169 +++++++++++------- .../src/NativeContainer.ts | 9 + .../neo-one-node-native/src/NativeContract.ts | 8 +- .../src/{Nep5.ts => Nep17.ts} | 18 +- .../neo-one-node-native/src/OracleContract.ts | 95 ++++++++++ packages/neo-one-node-native/src/Policy.ts | 35 +++- packages/neo-one-node-native/src/index.ts | 2 +- packages/neo-one-node-vm/lib/Dispatcher.cs | 2 +- .../src/__tests__/Dispatcher.test.ts | 4 + 23 files changed, 554 insertions(+), 154 deletions(-) create mode 100644 packages/neo-one-node-core/src/DesignationRole.ts create mode 100644 packages/neo-one-node-core/src/OracleRequest.ts create mode 100644 packages/neo-one-node-native/src/CachedCommittee.ts create mode 100644 packages/neo-one-node-native/src/DesignationContract.ts create mode 100644 packages/neo-one-node-native/src/ManagementContract.ts rename packages/neo-one-node-native/src/{Nep5.ts => Nep17.ts} (66%) create mode 100644 packages/neo-one-node-native/src/OracleContract.ts diff --git a/packages/neo-one-client-common/src/crypto.ts b/packages/neo-one-client-common/src/crypto.ts index f2cd912838..fdb684dd72 100644 --- a/packages/neo-one-client-common/src/crypto.ts +++ b/packages/neo-one-client-common/src/crypto.ts @@ -187,6 +187,15 @@ const createPrivateKey = (): PrivateKey => common.bufferToPrivateKey(randomBytes const toScriptHash = hash160; +const getContractHash = (sender: UInt160, script: Buffer) => { + const builder = new ScriptBuilder(); + builder.emitOp('ABORT'); + builder.emitPushUInt160(sender); + builder.emitPush(script); + + return toScriptHash(builder.build()); +}; + // Takes various formats and converts to standard ECPoint const toECPoint = (publicKey: Buffer): ECPoint => toECPointFromKeyPair(ec().keyFromPublic(publicKey)); @@ -891,6 +900,7 @@ export const crypto = { verify, privateKeyToPublicKey, toScriptHash, + getContractHash, toECPoint, createKeyPair, scriptHashToAddress, diff --git a/packages/neo-one-client-common/src/models/types.ts b/packages/neo-one-client-common/src/models/types.ts index 05fdfe479a..9d6085cf31 100644 --- a/packages/neo-one-client-common/src/models/types.ts +++ b/packages/neo-one-client-common/src/models/types.ts @@ -389,6 +389,7 @@ export interface ContractParameterDefinitionJSON { export interface ContractJSON { readonly id: number; + readonly updatecounter: number; readonly hash: string; readonly script: string; readonly manifest: ContractManifestJSON; diff --git a/packages/neo-one-client-full-common/src/models/ContractStateModel.ts b/packages/neo-one-client-full-common/src/models/ContractStateModel.ts index ee418e1f6d..b2d5c6e11b 100644 --- a/packages/neo-one-client-full-common/src/models/ContractStateModel.ts +++ b/packages/neo-one-client-full-common/src/models/ContractStateModel.ts @@ -1,28 +1,26 @@ -import { BinaryWriter, createSerializeWire, SerializableWire, SerializeWire } from '@neo-one/client-common'; import { ContractManifestModel } from './manifest'; +import { UInt160 } from '@neo-one/client-common'; export interface ContractStateModelAdd { readonly id: number; + readonly updateCounter: number; + readonly hash: UInt160; readonly script: Buffer; readonly manifest: TContractManifest; } -export class ContractStateModel - implements SerializableWire { +export class ContractStateModel { public readonly id: number; + public readonly updateCounter: number; + public readonly hash: UInt160; public readonly script: Buffer; public readonly manifest: TContractManifest; - public readonly serializeWire: SerializeWire = createSerializeWire(this.serializeWireBase.bind(this)); - public constructor({ script, manifest, id }: ContractStateModelAdd) { + public constructor({ script, hash, manifest, id, updateCounter }: ContractStateModelAdd) { this.id = id; + this.updateCounter = updateCounter; + this.hash = hash; this.script = script; this.manifest = manifest; } - - public serializeWireBase(writer: BinaryWriter): void { - writer.writeUInt32LE(this.id); - writer.writeVarBytesLE(this.script); - this.manifest.serializeWireBase(writer); - } } diff --git a/packages/neo-one-node-core/src/ContractState.ts b/packages/neo-one-node-core/src/ContractState.ts index d01606648e..a630a6c903 100644 --- a/packages/neo-one-node-core/src/ContractState.ts +++ b/packages/neo-one-node-core/src/ContractState.ts @@ -1,19 +1,14 @@ -import { - common, - ContractJSON, - createSerializeWire, - crypto, - IOHelper, - JSONHelper, - UInt160, -} from '@neo-one/client-common'; +import { common, ContractJSON, IOHelper, JSONHelper, UInt160 } from '@neo-one/client-common'; import { ContractStateModel } from '@neo-one/client-full-common'; import { ContractManifest } from './manifest'; -import { DeserializeWireBaseOptions, DeserializeWireOptions } from './Serializable'; -import { BinaryReader, utils } from './utils'; +import { utils } from './utils'; +import { StackItem } from './StackItems'; +import { assertArrayStackItem } from 'dist/cjs'; export interface ContractStateAdd { readonly id: number; + readonly updateCounter: number; + readonly hash: UInt160; readonly script: Buffer; readonly manifest: ContractManifest; } @@ -21,37 +16,27 @@ export interface ContractStateAdd { export type ContractKey = UInt160; export class ContractState extends ContractStateModel { - public static deserializeWireBase(options: DeserializeWireBaseOptions): ContractState { - const { reader } = options; - const id = reader.readInt32LE(); - const script = reader.readVarBytesLE(); - const manifest = ContractManifest.deserializeWireBase(options); + public static fromStackItem(stackItem: StackItem): ContractState { + const { array } = assertArrayStackItem(stackItem); + const id = array[0].getInteger().toNumber(); + const updateCounter = array[1].getInteger().toNumber(); + const hash = common.bufferToUInt160(array[2].getBuffer()); + const script = array[3].getBuffer(); + const manifest = ContractManifest.parseBytes(array[4].getBuffer()); - return new this({ + return new ContractState({ id, + updateCounter, + hash, script, manifest, }); } - public static deserializeWire(options: DeserializeWireOptions): ContractState { - return this.deserializeWireBase({ - context: options.context, - reader: new BinaryReader(options.buffer), - }); - } - - public readonly serializeWire = createSerializeWire(this.serializeWireBase.bind(this)); - - private readonly scriptHashInternal = utils.lazy(() => common.asUInt160(crypto.hash160(this.script))); private readonly sizeInternal = utils.lazy( () => IOHelper.sizeOfUInt32LE + IOHelper.sizeOfVarBytesLE(this.script) + this.manifest.size, ); - public get scriptHash() { - return this.scriptHashInternal(); - } - public get size() { return this.sizeInternal(); } @@ -59,6 +44,8 @@ export class ContractState extends ContractStateModel { public clone() { return new ContractState({ id: this.id, + updateCounter: this.updateCounter, + hash: this.hash, script: this.script, manifest: this.manifest, }); @@ -67,7 +54,8 @@ export class ContractState extends ContractStateModel { public serializeJSON(): ContractJSON { return { id: this.id, - hash: JSONHelper.writeUInt160(this.scriptHash), + updatecounter: this.updateCounter, + hash: JSONHelper.writeUInt160(this.hash), script: JSONHelper.writeBase64Buffer(this.script), manifest: this.manifest.serializeJSON(), }; diff --git a/packages/neo-one-node-core/src/DesignationRole.ts b/packages/neo-one-node-core/src/DesignationRole.ts new file mode 100644 index 0000000000..720e58f1a9 --- /dev/null +++ b/packages/neo-one-node-core/src/DesignationRole.ts @@ -0,0 +1,4 @@ +export enum DesignationRole { + StateValidator = 4, + Oracle = 8, +} diff --git a/packages/neo-one-node-core/src/Native.ts b/packages/neo-one-node-core/src/Native.ts index c63820a9bd..68bc3c2ad3 100644 --- a/packages/neo-one-node-core/src/Native.ts +++ b/packages/neo-one-node-core/src/Native.ts @@ -3,6 +3,11 @@ import { BN } from 'bn.js'; import { ReadFindStorage } from './Storage'; import { StorageItem } from './StorageItem'; import { StorageKey } from './StorageKey'; +import { ContractState } from './ContractState'; +import { OracleRequest } from './OracleRequest'; +import { DesignationRole } from './DesignationRole'; + +export type OracleRequestResults = ReadonlyArray; export interface NativeContractStorageContext { readonly storages: ReadFindStorage; @@ -13,7 +18,7 @@ export interface NativeContract { readonly name: string; } -export interface NEP5NativeContract extends NativeContract { +export interface NEP17NativeContract extends NativeContract { readonly symbol: string; readonly decimals: number; @@ -21,14 +26,16 @@ export interface NEP5NativeContract extends NativeContract { readonly balanceOf: (storage: NativeContractStorageContext, account: UInt160) => Promise; } -export interface GASContract extends NEP5NativeContract {} +export interface GASContract extends NEP17NativeContract {} export interface PolicyContract extends NativeContract { readonly getMaxTransactionsPerBlock: (storage: NativeContractStorageContext) => Promise; readonly getMaxBlockSize: (storage: NativeContractStorageContext) => Promise; readonly getMaxBlockSystemFee: (storage: NativeContractStorageContext) => Promise; readonly getFeePerByte: (storage: NativeContractStorageContext) => Promise; - readonly getBlockedAccounts: (storage: NativeContractStorageContext) => Promise; + readonly getExecFeeFactor: (storage: NativeContractStorageContext) => Promise; + readonly getStoragePrice: (storage: NativeContractStorageContext) => Promise; + readonly isBlocked: (storage: NativeContractStorageContext, account: UInt160) => Promise; } export interface Candidate { @@ -36,21 +43,43 @@ export interface Candidate { readonly votes: BN; } -export interface NEOContract extends NEP5NativeContract { +export interface NEOContract extends NEP17NativeContract { readonly totalAmount: BN; readonly effectiveVoterTurnout: number; readonly totalSupply: () => Promise; readonly getCandidates: (storage: NativeContractStorageContext) => Promise; - readonly getValidators: (storage: NativeContractStorageContext) => Promise; readonly getCommittee: (storage: NativeContractStorageContext) => Promise; readonly getCommitteeAddress: (storage: NativeContractStorageContext) => Promise; readonly unclaimedGas: (storage: NativeContractStorageContext, account: UInt160, end: number) => Promise; readonly getNextBlockValidators: (storage: NativeContractStorageContext) => Promise; } +export interface ManagementContract extends NativeContract { + readonly getContract: (storage: NativeContractStorageContext, hash: UInt160) => Promise; + readonly listContracts: (storage: NativeContractStorageContext) => Promise; +} + +export interface DesignationContract extends NativeContract { + readonly getDesignatedByRole: ( + storage: NativeContractStorageContext, + role: DesignationRole, + height: number, + index: number, + ) => Promise; +} + +export interface OracleContract extends NativeContract { + readonly getRequest: (storage: NativeContractStorageContext, id: BN) => Promise; + readonly getRequests: (storage: NativeContractStorageContext) => Promise; + readonly getRequestsByUrl: (storage: NativeContractStorageContext, url: string) => Promise; +} + export interface NativeContainer { readonly GAS: GASContract; readonly NEO: NEOContract; readonly Policy: PolicyContract; + readonly Management: ManagementContract; + readonly Designation: DesignationContract; + readonly Oracle: OracleContract; } diff --git a/packages/neo-one-node-core/src/OracleRequest.ts b/packages/neo-one-node-core/src/OracleRequest.ts new file mode 100644 index 0000000000..77e0dfd034 --- /dev/null +++ b/packages/neo-one-node-core/src/OracleRequest.ts @@ -0,0 +1,62 @@ +import { UInt256, UInt160, common } from '@neo-one/client-common'; +import { BN } from 'bn.js'; +import { StackItem, assertArrayStackItem } from './StackItems'; + +interface OracleRequestAdd { + readonly originalTxid: UInt256; + readonly gasForResponse: BN; + readonly url: string; + readonly filter: string; + readonly callbackContract: UInt160; + readonly callbackMethod: string; + readonly userData: Buffer; +} + +export class OracleRequest { + public static fromStackItem(stackItem: StackItem): OracleRequest { + const { array } = assertArrayStackItem(stackItem); + const originalTxid = common.bufferToUInt256(array[0].getBuffer()); + const gasForResponse = array[1].getInteger(); + const url = array[2].getString(); + const filter = array[3].getString(); + const callbackContract = common.bufferToUInt160(array[4].getBuffer()); + const callbackMethod = array[5].getString(); + const userData = array[6].getBuffer(); + + return new OracleRequest({ + originalTxid, + gasForResponse, + url, + filter, + callbackContract, + callbackMethod, + userData, + }); + } + + public originalTxid: UInt256; + public gasForResponse: BN; + public url: string; + public filter: string; + public callbackContract: UInt160; + public callbackMethod: string; + public userData: Buffer; + + public constructor({ + originalTxid, + gasForResponse, + url, + filter, + callbackContract, + callbackMethod, + userData, + }: OracleRequestAdd) { + this.originalTxid = originalTxid; + this.gasForResponse = gasForResponse; + this.url = url; + this.filter = filter; + this.callbackContract = callbackContract; + this.callbackMethod = callbackMethod; + this.userData = userData; + } +} diff --git a/packages/neo-one-node-core/src/index.ts b/packages/neo-one-node-core/src/index.ts index d14f6afea3..040a19d6ec 100644 --- a/packages/neo-one-node-core/src/index.ts +++ b/packages/neo-one-node-core/src/index.ts @@ -16,7 +16,9 @@ export * from './HeaderHashList'; export * from './Native'; export * from './network'; export * from './Notification'; +export * from './OracleRequest'; export * from './payload'; +export * from './DesignationRole'; export * from './Serializable'; export * from './Settings'; export * from './Signer'; diff --git a/packages/neo-one-node-core/src/manifest/ContractManifest.ts b/packages/neo-one-node-core/src/manifest/ContractManifest.ts index d9159f8e3f..474a90b3c7 100644 --- a/packages/neo-one-node-core/src/manifest/ContractManifest.ts +++ b/packages/neo-one-node-core/src/manifest/ContractManifest.ts @@ -1,24 +1,14 @@ import { ContractManifestJSON, IOHelper, JSONHelper, UInt160 } from '@neo-one/client-common'; -import { ContractManifestModel, getContractProperties } from '@neo-one/client-full-common'; -import { DeserializeWireBaseOptions, DeserializeWireOptions } from '../Serializable'; +import { ContractManifestModel } from '@neo-one/client-full-common'; import { BinaryReader, utils } from '../utils'; import { ContractABI } from './ContractABI'; import { ContractGroup } from './ContractGroup'; import { ContractPermission } from './ContractPermission'; export class ContractManifest extends ContractManifestModel { - public static deserializeWireBase(options: DeserializeWireBaseOptions): ContractManifest { - const { reader } = options; - const json = JSON.parse(reader.readVarString(this.maxLength)); - - return this.deserializeJSON(json); - } - - public static deserializeWire(options: DeserializeWireOptions): ContractManifest { - return this.deserializeWireBase({ - context: options.context, - reader: new BinaryReader(options.buffer), - }); + public static parseBytes(bytes: Buffer) { + const reader = new BinaryReader(bytes); + return this.deserializeJSON(JSON.parse(reader.readVarString(this.maxLength))); } private static deserializeJSON(json: ContractManifestJSON) { diff --git a/packages/neo-one-node-native/src/CachedCommittee.ts b/packages/neo-one-node-native/src/CachedCommittee.ts new file mode 100644 index 0000000000..1f3c2c2b43 --- /dev/null +++ b/packages/neo-one-node-native/src/CachedCommittee.ts @@ -0,0 +1,31 @@ +import { StackItem, assertArrayStackItem, assertStructStackItem } from '@neo-one/node-core'; +import { ECPoint, common } from '@neo-one/client-common'; +import { BN } from 'bn.js'; + +interface CachedCommitteeElement { + readonly publicKey: ECPoint; + readonly votes: BN; +} + +export class CachedCommittee { + public static fromStackItem(item: StackItem) { + const arrayItem = assertArrayStackItem(item); + + const members = arrayItem.array.map((element) => { + const structItem = assertStructStackItem(element); + + return { + publicKey: common.bufferToECPoint(structItem.array[0].getBuffer()), + votes: structItem.array[1].getInteger(), + }; + }); + + return new CachedCommittee(members); + } + + public readonly members: readonly CachedCommitteeElement[]; + + public constructor(members: readonly CachedCommitteeElement[]) { + this.members = members; + } +} diff --git a/packages/neo-one-node-native/src/DesignationContract.ts b/packages/neo-one-node-native/src/DesignationContract.ts new file mode 100644 index 0000000000..453cef4177 --- /dev/null +++ b/packages/neo-one-node-native/src/DesignationContract.ts @@ -0,0 +1,63 @@ +import { NativeContract } from './NativeContract'; +import { + NativeContractStorageContext, + utils, + StackItem, + assertArrayStackItem, + DesignationRole as Role, +} from '@neo-one/node-core'; +import { map, toArray } from 'rxjs/operators'; +import { ECPoint, common } from '@neo-one/client-common'; + +export class DesignationContract extends NativeContract { + public constructor() { + super({ + id: -5, + name: 'DesignationContract', + }); + } + + public async getDesignatedByRole( + { storages }: NativeContractStorageContext, + role: Role, + height: number, + index: number, + ): Promise { + if (height + 1 < index) { + // TODO: implement makeError + throw new Error(`index: ${index} out of range for getDesignatedByRole.`); + } + + const key = this.createStorageKey(Buffer.from([role])) + .addUInt32BE(index) + .toSearchPrefix(); + const boundary = this.createStorageKey(Buffer.from([role])).toSearchPrefix(); + + const range = await storages + .find$(boundary, key) + .pipe( + map(({ value }) => utils.getInteroperable(value, NodeList.fromStackItem).members), + toArray(), + ) + .toPromise(); + + const publicKeys = range.length === 0 ? undefined : range[range.length - 1]; + + return publicKeys ?? []; + } +} + +class NodeList { + public static fromStackItem(stackItem: StackItem): NodeList { + const arrayItem = assertArrayStackItem(stackItem); + const members = arrayItem.array.map((item) => common.bufferToECPoint(item.getBuffer())); + + return new NodeList(members); + } + + public readonly members: readonly ECPoint[]; + + public constructor(members: readonly ECPoint[]) { + this.members = members; + } +} diff --git a/packages/neo-one-node-native/src/GASToken.ts b/packages/neo-one-node-native/src/GASToken.ts index 64ac350091..b67ec8b229 100644 --- a/packages/neo-one-node-native/src/GASToken.ts +++ b/packages/neo-one-node-native/src/GASToken.ts @@ -1,12 +1,12 @@ -import { NEP5NativeContract } from './Nep5'; +import { NEP17NativeContract } from './Nep17'; -export class GASToken extends NEP5NativeContract { +export class GASToken extends NEP17NativeContract { public static readonly decimals: number = 8; public constructor() { super({ id: -2, - name: 'GAS', - symbol: 'gas', + name: 'GasToken', + symbol: 'GAS', decimals: 8, }); } diff --git a/packages/neo-one-node-native/src/KeyBuilder.ts b/packages/neo-one-node-native/src/KeyBuilder.ts index 03750d6348..c06eb9ebd6 100644 --- a/packages/neo-one-node-native/src/KeyBuilder.ts +++ b/packages/neo-one-node-native/src/KeyBuilder.ts @@ -1,4 +1,5 @@ import { SerializableWire, StorageKey } from '@neo-one/node-core'; +import { BN } from 'bn.js'; export class KeyBuilder { private readonly id: number; @@ -26,6 +27,19 @@ export class KeyBuilder { return this; } + public addUInt32BE(value: number): this { + const buffer = Buffer.alloc(4); + buffer.writeUInt32BE(value); + + return this.addBuffer(buffer); + } + + public addUInt64LE(value: BN): this { + const buffer = value.toArrayLike(Buffer, 'le', 8); + + return this.addBuffer(buffer); + } + public toSearchPrefix(): Buffer { return StorageKey.createSearchPrefix(this.id, this.mutableBuffer); } diff --git a/packages/neo-one-node-native/src/ManagementContract.ts b/packages/neo-one-node-native/src/ManagementContract.ts new file mode 100644 index 0000000000..b6a5a25bce --- /dev/null +++ b/packages/neo-one-node-native/src/ManagementContract.ts @@ -0,0 +1,42 @@ +import { NativeContract } from './NativeContract'; +import { NativeContractStorageContext, utils, ContractState } from '@neo-one/node-core'; +import { UInt160 } from '@neo-one/client-common'; +import { map, toArray } from 'rxjs/operators'; + +export class ManagementContract extends NativeContract { + private readonly prefixes = { + minimumDeploymentFee: Buffer.from([20]), + nextAvailableId: Buffer.from([15]), + contract: Buffer.from([8]), + }; + + public constructor() { + super({ + id: 0, + name: 'ManagementContract', + }); + } + + public async getContract({ storages }: NativeContractStorageContext, hash: UInt160) { + const maybeContract = await storages.tryGet( + this.createStorageKey(this.prefixes.contract).addBuffer(hash).toStorageKey(), + ); + + if (maybeContract === undefined) { + return undefined; + } + + return utils.getInteroperable(maybeContract, ContractState.fromStackItem); + } + + public async listContracts({ storages }: NativeContractStorageContext) { + const searchPrefix = this.createStorageKey(this.prefixes.contract).toSearchPrefix(); + return storages + .find$(searchPrefix) + .pipe( + map(({ value }) => utils.getInteroperable(value, ContractState.fromStackItem)), + toArray(), + ) + .toPromise(); + } +} diff --git a/packages/neo-one-node-native/src/NEOToken.ts b/packages/neo-one-node-native/src/NEOToken.ts index 426b0f1887..3c9b909c3d 100644 --- a/packages/neo-one-node-native/src/NEOToken.ts +++ b/packages/neo-one-node-native/src/NEOToken.ts @@ -4,10 +4,25 @@ import { BN } from 'bn.js'; import _ from 'lodash'; import { filter, map, toArray } from 'rxjs/operators'; import { CandidateState, NEOAccountState } from './AccountStates'; -import { GASToken } from './GASToken'; -import { NEP5NativeContract } from './Nep5'; +import { NEP17NativeContract } from './Nep17'; +import { CachedCommittee } from './CachedCommittee'; -export class NEOToken extends NEP5NativeContract { +type Storages = NativeContractStorageContext['storages']; + +interface CalculateBonusOptions { + readonly storages: Storages; + readonly vote?: ECPoint; + readonly value: BN; + readonly start: number; + readonly end: number; +} + +interface GasRecord { + readonly index: number; + readonly gasPerBlock: BN; +} + +export class NEOToken extends NEP17NativeContract { public readonly totalAmount: BN; // TODO: investigate this usage, its a strange decimal value in C# world. `0.2M`. Something to do with rounding. public readonly effectiveVoterTurnout = 0.2; @@ -16,14 +31,22 @@ export class NEOToken extends NEP5NativeContract { private readonly prefixes = { votersCount: Buffer.from([1]), candidate: Buffer.from([33]), - nextValidators: Buffer.from([14]), + committee: Buffer.from([14]), + gasPerBlock: Buffer.from([29]), + voterRewardPerCommittee: Buffer.from([23]), + }; + + private readonly ratios = { + neoHolderReward: 10, + committeeReward: 10, + voterReward: 10, }; public constructor(settings: BlockchainSettings) { super({ id: -1, - name: 'NEO', - symbol: 'neo', + name: 'NeoToken', + symbol: 'NEO', decimals: 0, }); @@ -46,74 +69,59 @@ export class NEOToken extends NEP5NativeContract { state: utils.getInteroperable(value, CandidateState.fromStackItem), })), filter((value) => value.state.registered), - // tslint:disable-next-line: no-useless-cast map(({ point, state }) => ({ publicKey: point, votes: state.votes })), toArray(), ) .toPromise(); } - public async getValidators(storage: NativeContractStorageContext): Promise { - const members = await this.getCommitteeMembers(storage); - - return members.slice(0, this.settings.validatorsCount).sort(common.ecPointCompare); - } - public async getCommittee(storage: NativeContractStorageContext): Promise { - // tslint:disable-next-line: prefer-immediate-return - const members = await this.getCommitteeMembers(storage); + const cache = await this.getCommitteeFromCache(storage); - return members.slice().sort(common.ecPointCompare); + return cache.members.map(({ publicKey }) => publicKey).sort(common.ecPointCompare); } public async getCommitteeAddress(storage: NativeContractStorageContext): Promise { - const committees = await this.getCommittee(storage); + const committee = await this.getCommittee(storage); return crypto.toScriptHash( - crypto.createMultiSignatureRedeemScript(committees.length - (committees.length - 1) / 2, committees), + crypto.createMultiSignatureRedeemScript(committee.length - (committee.length - 1) / 2, committee), ); } + public async getCommitteeFromCache({ storages }: NativeContractStorageContext): Promise { + const item = await storages.get(this.createStorageKey(this.prefixes.committee).toStorageKey()); + return utils.getInteroperable(item, CachedCommittee.fromStackItem); + } + public async unclaimedGas({ storages }: NativeContractStorageContext, account: UInt160, end: number) { - const storage = await storages.tryGet(this.createStorageKey(this.accountPrefix).addBuffer(account).toStorageKey()); + const storage = await storages.tryGet( + this.createStorageKey(this.basePrefixes.account).addBuffer(account).toStorageKey(), + ); if (storage === undefined) { return new BN(0); } const state = utils.getInteroperable(storage, NEOAccountState.fromStackItem); - return this.calculateBonus(state.balance, state.balanceHeight.toNumber(), end); - } - - public async getNextBlockValidators({ storages }: NativeContractStorageContext): Promise { - const key = this.createStorageKey(this.prefixes.nextValidators).toStorageKey(); - const storage = await storages.tryGet(key); - if (storage === undefined) { - return this.settings.standbyValidators; - } - - return utils.getSerializableArrayFromStorageItem(storage, (reader) => reader.readECPoint()); + return this.calculateBonus({ + storages, + vote: state.voteTo, + value: state.balance, + start: state.balanceHeight.toNumber(), + end, + }); } - private async getCommitteeMembers(storage: NativeContractStorageContext): Promise { - const item = await storage.storages.get(this.createStorageKey(this.prefixes.votersCount).toStorageKey()); - const votersCount = new BN(item.value, 'le').toNumber(); - const voterTurnout = votersCount / this.totalAmount.toNumber(); - if (voterTurnout < this.effectiveVoterTurnout) { - return this.settings.standbyCommittee; - } - - const candidates = await this.getCandidates(storage); - if (candidates.length < this.settings.committeeMembersCount) { - return this.settings.standbyCommittee; - } + public async getNextBlockValidators(storage: NativeContractStorageContext): Promise { + const committeeCache = await this.getCommitteeFromCache(storage); - return _.sortBy(candidates, ['votes', ({ publicKey }) => common.ecPointToHex(publicKey)]) + return _.take(committeeCache.members, this.settings.validatorsCount) .map(({ publicKey }) => publicKey) - .slice(0, this.settings.committeeMembersCount); + .sort(common.ecPointCompare); } - private calculateBonus(value: BN, start: number, end: number) { + private async calculateBonus({ storages, vote, value, start, end }: CalculateBonusOptions) { if (value.isZero() || start >= end) { return new BN(0); } @@ -122,32 +130,55 @@ export class NEOToken extends NEP5NativeContract { throw new Error('negative value not supported'); } - let amount = new BN(0); - let ustart = Math.floor(start / this.settings.decrementInterval); - if (ustart < this.settings.generationAmount.length) { - let istart = start % this.settings.decrementInterval; - let uend = Math.floor(end / this.settings.decrementInterval); - let iend = end % this.settings.decrementInterval; - if (uend >= this.settings.generationAmount.length) { - uend = this.settings.generationAmount.length; - iend = 0; - } - if (iend === 0) { - uend -= 1; - iend = this.settings.decrementInterval; - } - // tslint:disable-next-line: no-loop-statement - while (ustart < uend) { - amount = amount.addn((this.settings.decrementInterval - istart) * this.settings.generationAmount[ustart]); - ustart += 1; - istart = 0; + const neoHolderReward = await this.calculateNeoHolderReward(storages, value, start, end); + if (vote === undefined) { + return neoHolderReward; + } + + const border = this.createStorageKey(this.prefixes.voterRewardPerCommittee).addBuffer(vote).toSearchPrefix(); + const keyStart = this.createStorageKey(this.prefixes.voterRewardPerCommittee) + .addBuffer(vote) + .addUInt32BE(start) + .toSearchPrefix(); + const startRange = await storages.find$(border, keyStart).pipe(toArray()).toPromise(); + const startItem = startRange.length === 0 ? undefined : startRange[startRange.length - 1].value; + const startRewardPerNeo = startItem === undefined ? new BN(0) : new BN(startItem.value, 'le'); + + const keyEnd = this.createStorageKey(this.prefixes.voterRewardPerCommittee) + .addBuffer(vote) + .addUInt32BE(end) + .toSearchPrefix(); + const endRange = await storages.find$(border, keyEnd).pipe(toArray()).toPromise(); + const endItem = endRange.length === 0 ? undefined : endRange[endRange.length - 1].value; + const endRewardPerNeo = endItem === undefined ? new BN(0) : new BN(endItem.value, 'le'); + + return neoHolderReward.add(value.mul(endRewardPerNeo.sub(startRewardPerNeo)).div(this.totalAmount)); + } + + private async calculateNeoHolderReward(storages: Storages, value: BN, start: number, end: number) { + let sum = new BN(0); + const sortedGasRecords = await this.getSortedGasRecords(storages, end); + for (const { index, gasPerBlock } of sortedGasRecords) { + if (index > start) { + sum = sum.add(gasPerBlock.muln(end - index)); + } else { + sum = sum.add(gasPerBlock.muln(end - index)); + break; } - amount = amount.addn((iend - istart) * this.settings.generationAmount[ustart]); } - return common - .fixedFromDecimal(amount.mul(value), GASToken.decimals) - .mul(new BN(10 ** GASToken.decimals)) - .div(this.totalAmount); + return value.mul(sum).muln(this.ratios.neoHolderReward).divn(100).div(this.totalAmount); + } + + private async getSortedGasRecords(storages: Storages, end: number): Promise { + const key = this.createStorageKey(this.prefixes.gasPerBlock).addUInt32BE(end).toSearchPrefix(); + const boundary = this.createStorageKey(this.prefixes.gasPerBlock).toSearchPrefix(); + const range = await storages.find$(key, boundary).pipe(toArray()).toPromise(); + return range + .map(({ key, value }) => ({ + index: key.key.readUInt32BE(4), + gasPerBlock: new BN(value.value, 'le'), + })) + .reverse(); } } diff --git a/packages/neo-one-node-native/src/NativeContainer.ts b/packages/neo-one-node-native/src/NativeContainer.ts index 3f17aa255e..3bc4fc14da 100644 --- a/packages/neo-one-node-native/src/NativeContainer.ts +++ b/packages/neo-one-node-native/src/NativeContainer.ts @@ -2,15 +2,24 @@ import { BlockchainSettings } from '@neo-one/node-core'; import { GASToken } from './GASToken'; import { NEOToken } from './NEOToken'; import { PolicyContract } from './Policy'; +import { ManagementContract } from './ManagementContract'; +import { OracleContract } from './OracleContract'; +import { DesignationContract } from './DesignationContract'; export class NativeContainer { + public readonly Management: ManagementContract; public readonly NEO: NEOToken; public readonly GAS: GASToken; public readonly Policy: PolicyContract; + public readonly Oracle: OracleContract; + public readonly Designation: DesignationContract; public constructor(settings: BlockchainSettings) { + this.Management = new ManagementContract(); this.NEO = new NEOToken(settings); this.GAS = new GASToken(); this.Policy = new PolicyContract(); + this.Oracle = new OracleContract(); + this.Designation = new DesignationContract(); } } diff --git a/packages/neo-one-node-native/src/NativeContract.ts b/packages/neo-one-node-native/src/NativeContract.ts index 363d4ea68d..b0b687ebbd 100644 --- a/packages/neo-one-node-native/src/NativeContract.ts +++ b/packages/neo-one-node-native/src/NativeContract.ts @@ -1,4 +1,4 @@ -import { crypto, ScriptBuilder, UInt160 } from '@neo-one/client-common'; +import { crypto, ScriptBuilder, UInt160, common } from '@neo-one/client-common'; import { KeyBuilder } from './KeyBuilder'; export interface NativeContractAdd { @@ -11,6 +11,8 @@ export abstract class NativeContract { public readonly script: Buffer; public readonly hash: UInt160; public readonly id: number; + // newly added property will see if it is relevant on our end + // public readonly activeBlockIndex: number; public constructor({ name, id }: NativeContractAdd) { this.name = name; @@ -18,10 +20,10 @@ export abstract class NativeContract { const builder = new ScriptBuilder(); builder.emitPushString(this.name); - builder.emitSysCall('Neo.Native.Call'); + builder.emitSysCall('System.Contract.CallNative'); this.script = builder.build(); - this.hash = crypto.toScriptHash(this.script); + this.hash = crypto.getContractHash(common.ZERO_UINT160, this.script); } protected createStorageKey(prefix: Buffer) { diff --git a/packages/neo-one-node-native/src/Nep5.ts b/packages/neo-one-node-native/src/Nep17.ts similarity index 66% rename from packages/neo-one-node-native/src/Nep5.ts rename to packages/neo-one-node-native/src/Nep17.ts index 642c6fbcb8..c653725c41 100644 --- a/packages/neo-one-node-native/src/Nep5.ts +++ b/packages/neo-one-node-native/src/Nep17.ts @@ -3,20 +3,22 @@ import { NativeContractStorageContext } from '@neo-one/node-core'; import { BN } from 'bn.js'; import { NativeContract, NativeContractAdd } from './NativeContract'; -export interface NEP5NativeContractAdd extends NativeContractAdd { +export interface NEP17NativeContractAdd extends NativeContractAdd { readonly symbol: string; readonly decimals: number; } -export abstract class NEP5NativeContract extends NativeContract { +export abstract class NEP17NativeContract extends NativeContract { public readonly symbol: string; public readonly decimals: number; public readonly factor: BN; - protected readonly totalSupplyPrefix = Buffer.from([11]); - protected readonly accountPrefix = Buffer.from([20]); + protected readonly basePrefixes = { + totalSupply: Buffer.from([11]), + account: Buffer.from([20]), + }; - public constructor(options: NEP5NativeContractAdd) { + public constructor(options: NEP17NativeContractAdd) { super(options); this.symbol = options.symbol; this.decimals = options.decimals; @@ -24,7 +26,7 @@ export abstract class NEP5NativeContract extends NativeContract { } public async totalSupply({ storages }: NativeContractStorageContext): Promise { - const storage = await storages.tryGet(this.createStorageKey(this.totalSupplyPrefix).toStorageKey()); + const storage = await storages.tryGet(this.createStorageKey(this.basePrefixes.totalSupply).toStorageKey()); if (storage === undefined) { return new BN(0); } @@ -33,7 +35,9 @@ export abstract class NEP5NativeContract extends NativeContract { } public async balanceOf({ storages }: NativeContractStorageContext, account: UInt160): Promise { - const storage = await storages.tryGet(this.createStorageKey(this.accountPrefix).addBuffer(account).toStorageKey()); + const storage = await storages.tryGet( + this.createStorageKey(this.basePrefixes.totalSupply).addBuffer(account).toStorageKey(), + ); if (storage === undefined) { return new BN(0); } diff --git a/packages/neo-one-node-native/src/OracleContract.ts b/packages/neo-one-node-native/src/OracleContract.ts new file mode 100644 index 0000000000..04d7ff4d9b --- /dev/null +++ b/packages/neo-one-node-native/src/OracleContract.ts @@ -0,0 +1,95 @@ +import { crypto } from '@neo-one/client-common'; +import { NativeContract } from './NativeContract'; +import { + NativeContractStorageContext, + utils, + StackItem, + assertArrayStackItem, + OracleRequestResults, + OracleRequest, +} from '@neo-one/node-core'; +import { BN } from 'bn.js'; +import { map, toArray } from 'rxjs/operators'; + +export class OracleContract extends NativeContract { + private readonly prefixes = { + requestId: Buffer.from([9]), + request: Buffer.from([7]), + idList: Buffer.from([6]), + }; + + // applicationEngine constants that might be used later + // private maxUrlLength = 256 as const; + // private maxFilterLength = 128 as const; + // private maxCallbackLength = 32 as const; + // private maxUserDataLength = 512 as const; + // private oracleRequestPrice = common.fixed8FromDecimal('.5'); + + public constructor() { + super({ + id: -4, + name: 'OracleContract', + }); + } + + public async getRequest({ storages }: NativeContractStorageContext, id: BN) { + const item = await storages.tryGet(this.createStorageKey(this.prefixes.request).addUInt64LE(id).toStorageKey()); + + if (item === undefined) { + return undefined; + } + + return utils.getInteroperable(item, OracleRequest.fromStackItem); + } + + public async getRequests({ storages }: NativeContractStorageContext): Promise { + return storages + .find$(this.createStorageKey(this.prefixes.request).toSearchPrefix()) + .pipe( + map( + ({ key, value }) => + [new BN(key.key.slice(1), 'le'), utils.getInteroperable(value, OracleRequest.fromStackItem)] as const, + ), + toArray(), + ) + .toPromise(); + } + + public async getRequestsByUrl({ storages }: NativeContractStorageContext, url: string) { + const maybeListItem = await storages.tryGet( + this.createStorageKey(this.prefixes.idList).addBuffer(this.getUrlHash(url)).toStorageKey(), + ); + if (maybeListItem === undefined) { + return []; + } + + const { list } = utils.getInteroperable(maybeListItem, IdList.fromStackItem); + + return Promise.all( + list.map(async (id) => { + const request = await storages.get(this.createStorageKey(this.prefixes.request).addUInt64LE(id).toStorageKey()); + + return utils.getInteroperable(request, OracleRequest.fromStackItem); + }), + ); + } + + private getUrlHash(url: string) { + return crypto.hash160(Buffer.from(url, 'utf8')); + } +} + +class IdList { + public static fromStackItem(stackItem: StackItem): IdList { + const { array } = assertArrayStackItem(stackItem); + const list = array.map((item) => item.getInteger()); + + return new IdList(list); + } + + public list: readonly BN[]; + + public constructor(list: readonly BN[]) { + this.list = list; + } +} diff --git a/packages/neo-one-node-native/src/Policy.ts b/packages/neo-one-node-native/src/Policy.ts index 9951682782..6d8b8fa174 100644 --- a/packages/neo-one-node-native/src/Policy.ts +++ b/packages/neo-one-node-native/src/Policy.ts @@ -1,5 +1,5 @@ import { common, UInt160 } from '@neo-one/client-common'; -import { NativeContractStorageContext, utils } from '@neo-one/node-core'; +import { NativeContractStorageContext } from '@neo-one/node-core'; import { BN } from 'bn.js'; import { GASToken } from './GASToken'; import { NativeContract } from './NativeContract'; @@ -12,12 +12,17 @@ export class PolicyContract extends NativeContract { blockedAccounts: Buffer.from([15]), maxBlockSize: Buffer.from([12]), maxBlockSystemFee: Buffer.from([17]), + execFeeFactor: Buffer.from([18]), + storagePrice: Buffer.from([19]), }; + private readonly defaultExecFeeFactor = 30; + private readonly defaultStoragePrice = 100000; + public constructor() { super({ id: -3, - name: 'Policy', + name: 'PolicyContract', }); } @@ -57,12 +62,28 @@ export class PolicyContract extends NativeContract { return new BN(item.value); } - public async getBlockedAccounts({ storages }: NativeContractStorageContext): Promise { - const item = await storages.tryGet(this.createStorageKey(this.prefixes.blockedAccounts).toStorageKey()); - if (item !== undefined) { - return utils.getSerializableArrayFromStorageItem(item, (reader) => reader.readUInt160()); + public async getExecFeeFactor({ storages }: NativeContractStorageContext) { + const item = await storages.tryGet(this.createStorageKey(this.prefixes.execFeeFactor).toStorageKey()); + if (item === undefined) { + return this.defaultExecFeeFactor; } - return []; + return new BN(item.value).toNumber(); + } + + public async getStoragePrice({ storages }: NativeContractStorageContext) { + const item = await storages.tryGet(this.createStorageKey(this.prefixes.storagePrice).toStorageKey()); + if (item === undefined) { + return this.defaultStoragePrice; + } + + return new BN(item.value).toNumber(); + } + + public async isBlocked({ storages }: NativeContractStorageContext, account: UInt160) { + const item = await storages.tryGet( + this.createStorageKey(this.prefixes.blockedAccounts).addBuffer(account).toStorageKey(), + ); + return item !== undefined; } } diff --git a/packages/neo-one-node-native/src/index.ts b/packages/neo-one-node-native/src/index.ts index 5a77ae007d..0c91f79dd7 100644 --- a/packages/neo-one-node-native/src/index.ts +++ b/packages/neo-one-node-native/src/index.ts @@ -4,5 +4,5 @@ export * from './KeyBuilder'; export * from './NativeContainer'; export * from './NativeContract'; export * from './NEOToken'; -export * from './Nep5'; +export * from './Nep17'; export * from './Policy'; diff --git a/packages/neo-one-node-vm/lib/Dispatcher.cs b/packages/neo-one-node-vm/lib/Dispatcher.cs index 99f1b45c46..2e68662c36 100644 --- a/packages/neo-one-node-vm/lib/Dispatcher.cs +++ b/packages/neo-one-node-vm/lib/Dispatcher.cs @@ -124,7 +124,7 @@ private bool _dispose() private dynamic _test() { - return this.snapshot.PersistingBlock.Index.ToString(); + return sizeof(uint); } private NEOONE.ReturnHelpers.ProtocolSettingsReturn _getConfig() diff --git a/packages/neo-one-node-vm/src/__tests__/Dispatcher.test.ts b/packages/neo-one-node-vm/src/__tests__/Dispatcher.test.ts index c9c6c127b4..39398edc01 100644 --- a/packages/neo-one-node-vm/src/__tests__/Dispatcher.test.ts +++ b/packages/neo-one-node-vm/src/__tests__/Dispatcher.test.ts @@ -101,4 +101,8 @@ describe('Dispatcher Tests', () => { test('Dispatcher returns config without initializing config', () => { expect(dispatcher.getConfig()).toBeDefined(); }); + + test.only('test output only', () => { + console.log(dispatcher.test()); + }); }); From e47795b52fd02e343e8af7b21c4a715e1861aa09 Mon Sep 17 00:00:00 2001 From: Daniel Byrne Date: Mon, 11 Jan 2021 13:40:44 -0800 Subject: [PATCH 2/7] feat(node): Continue syncing with preview4 changes --- packages/neo-one-client-common/src/common.ts | 12 +- packages/neo-one-client-common/src/errors.ts | 7 +- .../models/transaction/TransactionModel.ts | 8 + .../transaction/attribute/AttributeModel.ts | 3 +- .../attribute/AttributeTypeModel.ts | 3 +- .../attribute/OracleResponseCode.ts | 26 ++ .../attribute/OracleResponseModel.ts | 37 +++ .../src/models/transaction/attribute/index.ts | 2 + .../neo-one-client-common/src/models/types.ts | 17 +- packages/neo-one-client-common/src/prices.ts | 14 ++ packages/neo-one-client-common/src/types.ts | 20 +- .../src/provider/JSONRPCClient.ts | 4 + .../src/provider/NEOONEDataProvider.ts | 35 ++- .../src/provider/NEOONEProvider.ts | 5 +- .../src/user/LocalUserAccountProvider.ts | 32 ++- .../src/user/UserAccountProviderBase.ts | 3 +- .../src/user/converters/attribute.ts | 19 +- .../neo-one-node-blockchain/src/Blockchain.ts | 47 +--- .../src/PersistingBlockchain.ts | 2 +- packages/neo-one-node-blockchain/src/utils.ts | 23 +- .../neo-one-node-blockchain/src/verify.ts | 233 ++++++++---------- .../neo-one-node-core/src/ContractState.ts | 3 +- packages/neo-one-node-core/src/Native.ts | 12 +- packages/neo-one-node-core/src/Storage.ts | 2 - .../src/TransactionVerificationContext.ts | 28 ++- packages/neo-one-node-core/src/Verifiable.ts | 31 ++- packages/neo-one-node-core/src/errors.ts | 6 + .../src/payload/ConsensusPayload.ts | 18 +- .../src/transaction/Transaction.ts | 99 +++++--- .../src/transaction/attributes/Attribute.ts | 13 +- .../transaction/attributes/AttributeBase.ts | 33 +-- .../attributes/HighPriorityAttribute.ts | 24 +- .../transaction/attributes/OracleResponse.ts | 84 +++++++ packages/neo-one-node-core/src/vm.ts | 14 +- .../src/CachedCommittee.ts | 4 +- .../src/DesignationContract.ts | 6 + .../src/ManagementContract.ts | 5 +- packages/neo-one-node-native/src/NEOToken.ts | 50 +++- .../src/NativeContainer.ts | 20 +- .../neo-one-node-native/src/NativeContract.ts | 2 +- .../neo-one-node-native/src/OracleContract.ts | 13 +- packages/neo-one-node-native/src/Policy.ts | 5 +- packages/neo-one-node-protocol/src/Message.ts | 15 +- packages/neo-one-node-protocol/src/Node.ts | 13 +- .../src/createHandler.ts | 7 +- .../neo-one-node-vm/lib/Dispatcher.Engine.cs | 21 ++ packages/neo-one-node-vm/lib/Dispatcher.cs | 3 +- .../neo-one-node-vm/src/ApplicationEngine.ts | 13 + .../src/Methods/EngineMethods.ts | 3 +- 49 files changed, 749 insertions(+), 350 deletions(-) create mode 100644 packages/neo-one-client-common/src/models/transaction/attribute/OracleResponseCode.ts create mode 100644 packages/neo-one-client-common/src/models/transaction/attribute/OracleResponseModel.ts create mode 100644 packages/neo-one-node-core/src/transaction/attributes/OracleResponse.ts diff --git a/packages/neo-one-client-common/src/common.ts b/packages/neo-one-client-common/src/common.ts index f79cffc05e..9cd482f450 100644 --- a/packages/neo-one-client-common/src/common.ts +++ b/packages/neo-one-client-common/src/common.ts @@ -221,15 +221,21 @@ const TEN_THOUSAND_FIXED8 = fixed8FromDecimal(10000); const ONE_HUNDRED_MILLION_FIXED8 = fixed8FromDecimal(100000000); const nativeScriptHashes = { - GAS: '0x668e0c1f9d7b70a99dd9e06eadd4c784d641afbc', - NEO: '0xde5f57d430d3dece511cf975a8d37848cb9e0525', - Policy: '0xce06595079cd69583126dbfd1d2e25cca74cffe9', + Management: '0xcd97b70d82d69adfcd9165374109419fade8d6ab', + NEO: '0x0a46e2e37c9987f570b4af253fb77e7eef0f72b6', + GAS: '0xa6a6c15dcdc9b997dac448b6926522d22efeedfb', + Policy: '0xdde31084c0fdbebc7f5ed5f53a38905305ccee14', + Oracle: '0xb1c37d5847c2ae36bdde31d0cc833a7ad9667f8f', + Designation: '0xc0073f4c7069bf38995780c9da065f9b3949ea7a', }; const nativeHashes = { + Management: hexToUInt160(nativeScriptHashes.Management), GAS: hexToUInt160(nativeScriptHashes.GAS), NEO: hexToUInt160(nativeScriptHashes.NEO), Policy: hexToUInt160(nativeScriptHashes.Policy), + Oracle: hexToUInt160(nativeScriptHashes.Oracle), + Designation: hexToUInt160(nativeScriptHashes.Designation), }; export const common = { diff --git a/packages/neo-one-client-common/src/errors.ts b/packages/neo-one-client-common/src/errors.ts index 4fcfdbe844..d1e3d26937 100644 --- a/packages/neo-one-client-common/src/errors.ts +++ b/packages/neo-one-client-common/src/errors.ts @@ -95,7 +95,12 @@ export const InvalidAttributeTypeJSONError = makeErrorWithCode( ); export const InvalidAttributeTypeError = makeErrorWithCode( 'INVALID_ATTRIBUTE_TYPE', - (transactionAttributeType: number) => `Expected transaction type, found: ${transactionAttributeType.toString(16)}`, + (transactionAttributeType: number) => + `Expected transaction attribute type, found: ${transactionAttributeType.toString(16)}`, +); +export const InvalidOracleResponseCodeError = makeErrorWithCode( + 'INVALID_ORACLE_RESPONSE_CODE', + (value: number) => `Expected oracle response code, found: ${value.toString()}`, ); export const InvalidAttributeUsageError = makeErrorWithCode( 'INVALID_ATTRIBUTE_USAGE', diff --git a/packages/neo-one-client-common/src/models/transaction/TransactionModel.ts b/packages/neo-one-client-common/src/models/transaction/TransactionModel.ts index 2e60cfa238..7c7f4a1fa8 100644 --- a/packages/neo-one-client-common/src/models/transaction/TransactionModel.ts +++ b/packages/neo-one-client-common/src/models/transaction/TransactionModel.ts @@ -71,6 +71,14 @@ export class TransactionModel< this.networkFee = networkFee; } + public getAttributes(isAttr: (attr: TAttribute) => attr is T): readonly T[] { + return this.attributes.filter(isAttr); + } + + public getAttribute(isAttr: (attr: TAttribute) => attr is T): T | undefined { + return this.getAttributes(isAttr)[0]; + } + public getScriptHashesForVerifying(): readonly UInt160[] { return this.signers.map((signer) => signer.account); } diff --git a/packages/neo-one-client-common/src/models/transaction/attribute/AttributeModel.ts b/packages/neo-one-client-common/src/models/transaction/attribute/AttributeModel.ts index c3e007ac6f..88cb26e419 100644 --- a/packages/neo-one-client-common/src/models/transaction/attribute/AttributeModel.ts +++ b/packages/neo-one-client-common/src/models/transaction/attribute/AttributeModel.ts @@ -1,3 +1,4 @@ import { HighPriorityAttributeModel } from './HighPriorityAttributeModel'; +import { OracleResponseModel } from './OracleResponseModel'; -export type AttributeModel = HighPriorityAttributeModel; +export type AttributeModel = HighPriorityAttributeModel | OracleResponseModel; diff --git a/packages/neo-one-client-common/src/models/transaction/attribute/AttributeTypeModel.ts b/packages/neo-one-client-common/src/models/transaction/attribute/AttributeTypeModel.ts index 2e267729f8..1afe84f14d 100644 --- a/packages/neo-one-client-common/src/models/transaction/attribute/AttributeTypeModel.ts +++ b/packages/neo-one-client-common/src/models/transaction/attribute/AttributeTypeModel.ts @@ -2,7 +2,8 @@ import { InvalidAttributeTypeError, InvalidAttributeTypeJSONError } from '../../ import { AttributeTypeJSON } from '../../types'; export enum AttributeTypeModel { - HighPriority = 1, + HighPriority = 0x01, + OracleResponse = 0x11, } const isAttributeType = (value: number): value is AttributeTypeModel => diff --git a/packages/neo-one-client-common/src/models/transaction/attribute/OracleResponseCode.ts b/packages/neo-one-client-common/src/models/transaction/attribute/OracleResponseCode.ts new file mode 100644 index 0000000000..0d67158b02 --- /dev/null +++ b/packages/neo-one-client-common/src/models/transaction/attribute/OracleResponseCode.ts @@ -0,0 +1,26 @@ +import { InvalidOracleResponseCodeError } from '../../../errors'; + +export enum OracleResponseCode { + Success = 0x00, + + ConsensusUnreachable = 0x10, + NotFound = 0x12, + Timeout = 0x14, + Forbidden = 0x16, + ResponseTooLarge = 0x18, + InsufficientFunds = 0x1a, + + Error = 0xff, +} + +const isOracleResponseCode = (value: number): value is OracleResponseCode => + // tslint:disable-next-line: strict-type-predicates + OracleResponseCode[value] !== undefined; + +export const assertOracleResponseCode = (value: number): OracleResponseCode => { + if (isOracleResponseCode(value)) { + return value; + } + + throw new InvalidOracleResponseCodeError(value); +}; diff --git a/packages/neo-one-client-common/src/models/transaction/attribute/OracleResponseModel.ts b/packages/neo-one-client-common/src/models/transaction/attribute/OracleResponseModel.ts new file mode 100644 index 0000000000..4695399ba3 --- /dev/null +++ b/packages/neo-one-client-common/src/models/transaction/attribute/OracleResponseModel.ts @@ -0,0 +1,37 @@ +import { BN } from 'bn.js'; +import { BinaryWriter } from '../../../BinaryWriter'; +import { IOHelper } from '../../../IOHelper'; +import { AttributeBaseModel } from './AttributeBaseModel'; +import { AttributeTypeModel } from './AttributeTypeModel'; +import { OracleResponseCode } from './OracleResponseCode'; + +export interface OracleResponseModelAdd { + readonly id: BN; + readonly code: OracleResponseCode; + readonly result: Buffer; +} + +export class OracleResponseModel extends AttributeBaseModel { + public readonly type = AttributeTypeModel.OracleResponse; + public readonly allowMultiple = false; + public readonly id: BN; + public readonly code: OracleResponseCode; + public readonly result: Buffer; + + public constructor({ id, code, result }: OracleResponseModelAdd) { + super(); + this.id = id; + this.code = code; + this.result = result; + } + + protected serializeWithoutTypeBase(writer: BinaryWriter) { + writer.writeUInt64LE(this.id); + writer.writeUInt8(this.code); + writer.writeVarBytesLE(this.result); + } + + protected sizeExclusive(): number { + return IOHelper.sizeOfUInt64LE + IOHelper.sizeOfUInt8 + IOHelper.sizeOfVarBytesLE(this.result); + } +} diff --git a/packages/neo-one-client-common/src/models/transaction/attribute/index.ts b/packages/neo-one-client-common/src/models/transaction/attribute/index.ts index 09d44f1986..9e1778f2d4 100644 --- a/packages/neo-one-client-common/src/models/transaction/attribute/index.ts +++ b/packages/neo-one-client-common/src/models/transaction/attribute/index.ts @@ -2,3 +2,5 @@ export * from './AttributeBaseModel'; export * from './AttributeModel'; export * from './AttributeTypeModel'; export * from './HighPriorityAttributeModel'; +export * from './OracleResponseCode'; +export * from './OracleResponseModel'; diff --git a/packages/neo-one-client-common/src/models/types.ts b/packages/neo-one-client-common/src/models/types.ts index 9d6085cf31..146391fda3 100644 --- a/packages/neo-one-client-common/src/models/types.ts +++ b/packages/neo-one-client-common/src/models/types.ts @@ -3,7 +3,7 @@ import { UInt256Hex } from '../common'; import { UserAccount } from '../types'; import { ContractParameterTypeModel } from './ContractParameterTypeModel'; import { StorageFlagsModel } from './StorageFlagsModel'; -import { AttributeTypeModel } from './transaction/attribute/AttributeTypeModel'; +import { AttributeTypeModel } from './transaction'; import { TriggerType, TriggerTypeJSON } from './trigger'; import { VerifyResultModel } from './VerifyResultModel'; import { VMState, VMStateJSON } from './vm'; @@ -196,10 +196,23 @@ export interface SignerJSON { readonly allowedgroups?: readonly string[]; } -export interface AttributeJSON { +export interface AttributeJSONBase { readonly type: AttributeTypeJSON; } +export interface HighPriorityAttributeJSON extends AttributeJSONBase { + readonly type: 'HighPriority'; +} + +export interface OracleResponseJSON extends AttributeJSONBase { + readonly type: 'OracleResponse'; + readonly id: string; + readonly code: number; + readonly result: string; +} + +export type AttributeJSON = HighPriorityAttributeJSON | OracleResponseJSON; + export type AttributeTypeJSON = keyof typeof AttributeTypeModel; export type VerifyResultJSON = keyof typeof VerifyResultModel; diff --git a/packages/neo-one-client-common/src/prices.ts b/packages/neo-one-client-common/src/prices.ts index 4c4c94f3c7..9c3a77afa2 100644 --- a/packages/neo-one-client-common/src/prices.ts +++ b/packages/neo-one-client-common/src/prices.ts @@ -199,3 +199,17 @@ export const getOpCodePrice = (value: Op): BigNumber => { return fee; }; + +export const signatureContractCost = getOpCodePrice(Op.PUSHDATA1) + .multipliedBy(2) + .plus(getOpCodePrice(Op.PUSHNULL)) + .plus(getOpCodePrice(Op.SYSCALL)) + .plus(ECDsaVerifyPrice); + +export const multiSignatureContractCost = (m: number, n: number) => + getOpCodePrice(Op.PUSHDATA1) + .multipliedBy(m + n) + .plus(getOpCodePrice(Op.PUSHINT8).multipliedBy(2)) + .plus(getOpCodePrice(Op.PUSHNULL)) + .plus(getOpCodePrice(Op.SYSCALL)) + .plus(ECDsaVerifyPrice.multipliedBy(n)); diff --git a/packages/neo-one-client-common/src/types.ts b/packages/neo-one-client-common/src/types.ts index 0d5f787018..a7b7eea060 100644 --- a/packages/neo-one-client-common/src/types.ts +++ b/packages/neo-one-client-common/src/types.ts @@ -9,6 +9,7 @@ import { AccountContract, AttributeTypeModel, NotificationJSON, + OracleResponseCode, StackItemJSON, TriggerTypeJSON, VerifyResultModel, @@ -73,21 +74,28 @@ export type NetworkType = 'main' | 'test' | string; * @see Attribute */ export interface AttributeBase { + /** + * `type` specifies the `Attribute` type + */ readonly type: AttributeTypeModel; } /** * `Attribute` whose transaction is "high priority". */ export interface HighPriorityAttribute extends AttributeBase { - /** - * `type` specifies the `Attribute` type - */ readonly type: AttributeTypeModel.HighPriority; } + +export interface OracleResponse extends AttributeBase { + readonly type: AttributeTypeModel.OracleResponse; + readonly id: BigNumber; + readonly code: OracleResponseCode; + readonly result: BufferString; +} /** * `Attribute`s are used to store additional data on `Transaction`s. */ -export type Attribute = HighPriorityAttribute; +export type Attribute = HighPriorityAttribute | OracleResponse; export type WitnessScope = | 'None' @@ -429,6 +437,10 @@ export interface Transfer { * Destination address. */ readonly to: AddressString; + /** + * Additional data to be attached to the transaction. Typed as `any` but should be used cautiously since it will need to be converted. + */ + readonly data?: any; } /** diff --git a/packages/neo-one-client-core/src/provider/JSONRPCClient.ts b/packages/neo-one-client-core/src/provider/JSONRPCClient.ts index c7f9b4f730..746b8bad3c 100644 --- a/packages/neo-one-client-core/src/provider/JSONRPCClient.ts +++ b/packages/neo-one-client-core/src/provider/JSONRPCClient.ts @@ -81,6 +81,10 @@ export class JSONRPCClient { return this.withInstance(async (provider) => provider.request({ method: 'getfeeperbyte' })); } + public async getExecFeeFactor(): Promise { + return this.withInstance(async (provider) => provider.request({ method: 'getexecfeefactor' })); + } + public async getContract(address: AddressString): Promise { return this.withInstance(async (provider) => provider.request({ diff --git a/packages/neo-one-client-core/src/provider/NEOONEDataProvider.ts b/packages/neo-one-client-core/src/provider/NEOONEDataProvider.ts index c0ed5281b4..0f3fb8e128 100644 --- a/packages/neo-one-client-core/src/provider/NEOONEDataProvider.ts +++ b/packages/neo-one-client-core/src/provider/NEOONEDataProvider.ts @@ -5,6 +5,7 @@ import { ApplicationLogJSON, Attribute, AttributeJSON, + AttributeTypeModel, Block, BlockJSON, ConfirmedTransaction, @@ -27,7 +28,6 @@ import { ContractPermission, ContractPermissionJSON, DeveloperProvider, - FeelessTransactionModel, GetOptions, Hash256String, IterOptions, @@ -35,6 +35,7 @@ import { NetworkSettings, NetworkSettingsJSON, NetworkType, + OracleResponseJSON, Peer, PrivateNetworkSettings, RawApplicationLogData, @@ -54,9 +55,9 @@ import { TransactionModel, TransactionReceipt, TransactionReceiptJSON, + UInt160Hex, VerifyResultJSON, VerifyResultModel, - UInt160Hex, } from '@neo-one/client-common'; import { utils as commonUtils } from '@neo-one/utils'; import { AsyncIterableX } from '@reactivex/ix-es2015-cjs/asynciterable/asynciterablex'; @@ -150,6 +151,10 @@ export class NEOONEDataProvider implements DeveloperProvider { return new BigNumber(feePerByte); } + public async getExecFeeFactor(): Promise { + return this.mutableClient.getExecFeeFactor(); + } + public async getVerificationCost( hash: AddressString, transaction: TransactionModel, @@ -356,9 +361,29 @@ export class NEOONEDataProvider implements DeveloperProvider { } private convertAttributes(attributes: readonly AttributeJSON[]): readonly Attribute[] { - return attributes.map((attribute) => ({ - type: toAttributeType(attribute.type), - })); + return attributes.map(this.convertAttribute); + } + + private convertAttribute(attribute: AttributeJSON): Attribute { + const type = toAttributeType(attribute.type); + switch (type) { + case AttributeTypeModel.HighPriority: + return { + type, + }; + case AttributeTypeModel.OracleResponse: + // tslint:disable-next-line: no-any we know this is true but TS is being mean + const oracleJSON = attribute as OracleResponseJSON; + + return { + type, + id: new BigNumber(oracleJSON.id), + code: oracleJSON.code, + result: oracleJSON.result, + }; + default: + throw new Error(); + } } private convertContract(contract: ContractJSON): Contract { diff --git a/packages/neo-one-client-core/src/provider/NEOONEProvider.ts b/packages/neo-one-client-core/src/provider/NEOONEProvider.ts index b2bd704da6..a49661024b 100644 --- a/packages/neo-one-client-core/src/provider/NEOONEProvider.ts +++ b/packages/neo-one-client-core/src/provider/NEOONEProvider.ts @@ -2,7 +2,6 @@ import { Account, AddressString, Block, - FeelessTransactionModel, GetOptions, Hash256String, IterOptions, @@ -85,6 +84,10 @@ export class NEOONEProvider implements Provider { return this.getProvider(network).getFeePerByte(); } + public async getExecFeeFactor(network: NetworkType): Promise { + return this.getProvider(network).getExecFeeFactor(); + } + public async getVerificationCost( network: NetworkType, hash: UInt160Hex, diff --git a/packages/neo-one-client-core/src/user/LocalUserAccountProvider.ts b/packages/neo-one-client-core/src/user/LocalUserAccountProvider.ts index 0ff705f71f..92cebe99b1 100644 --- a/packages/neo-one-client-core/src/user/LocalUserAccountProvider.ts +++ b/packages/neo-one-client-core/src/user/LocalUserAccountProvider.ts @@ -12,7 +12,6 @@ import { NetworkType, Op, Param, - RawAction, RelayTransactionResult, ScriptBuilder, ScriptBuilderParam, @@ -33,7 +32,6 @@ import { WitnessScopeModel, } from '@neo-one/client-common'; import { processActionsAndMessage } from '@neo-one/client-switch'; -import { utils as commonUtils } from '@neo-one/utils'; import BigNumber from 'bignumber.js'; import { Observable } from 'rxjs'; import { InsufficientNetworkFeeError, InvokeError, UnknownAccountError } from '../errors'; @@ -171,6 +169,11 @@ export class LocalUserAccountProvider Promise; readonly getBlockCount: (network: NetworkType) => Promise; readonly getFeePerByte: (network: NetworkType) => Promise; + readonly getExecFeeFactor: (network: NetworkType) => Promise; readonly getTransaction: (network: NetworkType, hash: Hash256String) => Promise; readonly iterBlocks: (network: NetworkType, options?: IterOptions) => AsyncIterable; readonly getAccount: (network: NetworkType, address: AddressString) => Promise; diff --git a/packages/neo-one-client-core/src/user/converters/attribute.ts b/packages/neo-one-client-core/src/user/converters/attribute.ts index 46fceb2ff8..cc66ed3c7e 100644 --- a/packages/neo-one-client-core/src/user/converters/attribute.ts +++ b/packages/neo-one-client-core/src/user/converters/attribute.ts @@ -1,8 +1,23 @@ -import { Attribute, AttributeModel, HighPriorityAttributeModel } from '@neo-one/client-common'; +import { + Attribute, + AttributeModel, + AttributeTypeModel, + HighPriorityAttributeModel, + OracleResponseModel, +} from '@neo-one/client-common'; +import { BN } from 'bn.js'; export const attribute = (attrib: Attribute): AttributeModel => { switch (attrib.type) { - default: + case AttributeTypeModel.HighPriority: return new HighPriorityAttributeModel(); + case AttributeTypeModel.OracleResponse: + return new OracleResponseModel({ + id: new BN(attrib.id.toString()), + code: attrib.code, + result: Buffer.from(attrib.result, 'hex'), + }); + default: + throw new Error('for ts'); } }; diff --git a/packages/neo-one-node-blockchain/src/Blockchain.ts b/packages/neo-one-node-blockchain/src/Blockchain.ts index 8c5e447830..6f429f100a 100644 --- a/packages/neo-one-node-blockchain/src/Blockchain.ts +++ b/packages/neo-one-node-blockchain/src/Blockchain.ts @@ -31,7 +31,6 @@ import { Storage, Transaction, TransactionVerificationContext, - VerifyConsensusPayloadOptions, VerifyOptions, VM, Witness, @@ -51,7 +50,7 @@ import { getNep5UpdateOptions } from './getNep5UpdateOptions'; import { HeaderIndexCache } from './HeaderIndexCache'; import { PersistingBlockchain } from './PersistingBlockchain'; import { utils } from './utils'; -import { verifyWitnesses } from './verify'; +import { verifyWitness, verifyWitnesses } from './verify'; const logger = createChild(nodeLogger, { service: 'blockchain' }); @@ -165,6 +164,7 @@ export class Blockchain { public readonly deserializeWireContext: DeserializeWireContext; + public readonly verifyWitness = verifyWitness; public readonly verifyWitnesses = verifyWitnesses; public readonly settings: BlockchainSettings; public readonly onPersistNativeContractScript: Buffer; @@ -205,7 +205,11 @@ export class Blockchain { }; this.mutableCurrentBlock = options.currentBlock; this.onPersist = - options.onPersist === undefined ? () => Promise.resolve(this.vm.updateSnapshots()) : options.onPersist; + options.onPersist === undefined + ? () => { + this.vm.updateSnapshots(); + } + : options.onPersist; this.start(); } @@ -243,15 +247,7 @@ export class Blockchain { storage: this.storage, native: this.native, verifyWitnesses: this.verifyWitnesses, - }; - } - - public get verifyConsensusPayloadOptions(): VerifyConsensusPayloadOptions { - return { - vm: this.vm, - storage: this.storage, - native: this.native, - verifyWitnesses: this.verifyWitnesses, + verifyWitness: this.verifyWitness, height: this.currentBlockIndex, }; } @@ -280,10 +276,6 @@ export class Blockchain { return this.storage.transactions; } - public get contracts() { - return this.storage.contracts; - } - public get storages() { return this.storage.storages; } @@ -300,10 +292,6 @@ export class Blockchain { return this.storage.headerHashIndex; } - public get contractID() { - return this.storage.contractID; - } - // public get consensusState() { // return this.storage.consensusState; // } @@ -363,20 +351,11 @@ export class Blockchain { return VerifyResultModel.AlreadyExists; } - // TODO: to save some compute time we could keep a local cache of the current blocks return values - // from native contract calls and pass those in, instead of passing the whole native container. - const verifyOptions = { - native: this.native, - vm: this.vm, - storage: this.storage, - verifyWitnesses: this.verifyWitnesses, - }; - - return transaction.verify(verifyOptions, context); + return transaction.verify(this.verifyOptions, context); } public async verifyConsensusPayload(payload: ConsensusPayload) { - const verification = await payload.verify(this.verifyConsensusPayloadOptions); + const verification = await payload.verify(this.verifyOptions); if (!verification) { throw new ConsensusPayloadVerifyError(payload.hashHex); } @@ -447,7 +426,7 @@ export class Blockchain { } public async getValidators(): Promise { - return this.native.NEO.getValidators(this.storage); + return this.native.NEO.computeNextBlockValidators(this.storage); } public async getNextBlockValidators(): Promise { @@ -498,7 +477,7 @@ export class Blockchain { } public async getVerificationCost(contractHash: UInt160, transaction: Transaction) { - const contract = await this.contracts.tryGet(contractHash); + const contract = await this.native.Management.getContract(this.storage, contractHash); if (contract === undefined) { return { fee: utils.ZERO, size: 0 }; } @@ -547,7 +526,7 @@ export class Blockchain { gas, }, (engine) => { - engine.loadScript({ script: script, initialPosition: offset }); + engine.loadScript({ script, initialPosition: offset }); engine.execute(); return utils.getCallReceipt(engine, container); diff --git a/packages/neo-one-node-blockchain/src/PersistingBlockchain.ts b/packages/neo-one-node-blockchain/src/PersistingBlockchain.ts index b46a031b44..a8c345c51f 100644 --- a/packages/neo-one-node-blockchain/src/PersistingBlockchain.ts +++ b/packages/neo-one-node-blockchain/src/PersistingBlockchain.ts @@ -1,5 +1,5 @@ // tslint:disable no-array-mutation no-object-mutation -import { TriggerType, VMState, common } from '@neo-one/client-common'; +import { common, TriggerType, VMState } from '@neo-one/client-common'; import { ApplicationExecuted, Block, SnapshotHandler, Transaction, VM } from '@neo-one/node-core'; import { PersistNativeContractsError, PostPersistError } from './errors'; import { utils } from './utils'; diff --git a/packages/neo-one-node-blockchain/src/utils.ts b/packages/neo-one-node-blockchain/src/utils.ts index 886f2d9daa..bf06e6a596 100644 --- a/packages/neo-one-node-blockchain/src/utils.ts +++ b/packages/neo-one-node-blockchain/src/utils.ts @@ -50,12 +50,6 @@ const getCallReceipt = (engine: ApplicationEngine, container?: Verifiable) => ({ }); const verifyContract = async (contract: ContractState, vm: VM, transaction: Transaction) => { - const verify = contract.manifest.abi.getMethod('verify'); - if (verify === undefined) { - throw new InvalidFormatError(`the smart contract ${contract.scriptHash} does not have a verify method`); - } - - const init = contract.manifest.abi.getMethod('_initialize'); const gas = vm.withApplicationEngine( { trigger: TriggerType.Verification, @@ -64,21 +58,24 @@ const verifyContract = async (contract: ContractState, vm: VM, transaction: Tran gas: common.TWENTY_FIXED8, }, (engine) => { - engine.loadScript({ - script: contract.script, + const loaded = engine.loadContract({ + hash: contract.hash, flags: CallFlags.None, - initialPosition: init ? init.offset : verify.offset, + method: 'verify', + packParameters: true, }); - engine.loadScript({ script: Buffer.from([]), flags: CallFlags.None }); - const result = engine.execute(); + if (!loaded) { + throw new InvalidFormatError(`contract with hash: ${contract.hash} does not have a verify method.`); + } + const result = engine.execute(); if (result === VMState.FAULT) { - throw new ScriptVerifyError(`contract ${contract.scriptHash} returned FAULT state`); + throw new ScriptVerifyError(`contract ${contract.hash} returned FAULT state`); } if (engine.resultStack.length !== 1 || !engine.resultStack[0].getBoolean()) { - throw new ScriptVerifyError(`contract ${contract.scriptHash} returns false`); + throw new ScriptVerifyError(`contract ${contract.hash} returns false`); } return engine.gasConsumed; diff --git a/packages/neo-one-node-blockchain/src/verify.ts b/packages/neo-one-node-blockchain/src/verify.ts index 84005df5cc..d3ab3b7a74 100644 --- a/packages/neo-one-node-blockchain/src/verify.ts +++ b/packages/neo-one-node-blockchain/src/verify.ts @@ -1,123 +1,27 @@ -import { common, TriggerType, UInt160, VMState } from '@neo-one/client-common'; +import { crypto, TriggerType, UInt160, VMState } from '@neo-one/client-common'; import { - BlockchainStorage, CallFlags, - ContractMethodDescriptor, + ContractState, ExecuteScriptResult, - NativeContainer, - SerializableContainer, - Verifiable, - VM, + maxVerificationGas, + VerifyWitnessesOptions, + VerifyWitnessOptions, } from '@neo-one/node-core'; import { BN } from 'bn.js'; -import { ContractMethodError, ContractStateFetchError, WitnessVerifyError } from './errors'; - -const maxVerificationGas = common.fixed8FromDecimal('0.5'); - -interface ApplicationEngineVerifyOptions { - readonly verification: Buffer; - readonly offset: number; - readonly init?: ContractMethodDescriptor; -} - -const getApplicationEngineVerifyOptions = async ( - verification: Buffer, - storage: BlockchainStorage, - hash: UInt160, - scriptHash: UInt160, -): Promise => { - if (verification.length === 0) { - const contractState = await storage.contracts.tryGet(hash); - if (contractState === undefined) { - throw new ContractStateFetchError(common.uInt160ToHex(hash)); - } - const methodDescriptor = contractState.manifest.abi.getMethod('verify'); - if (methodDescriptor === undefined) { - throw new ContractMethodError('verify', common.uInt160ToHex(hash)); - } - - return { - verification: contractState.script, - offset: methodDescriptor.offset, - init: contractState.manifest.abi.getMethod('_initialize'), - }; - } - - // tslint:disable-next-line: possible-timing-attack TODO: look into this `possible-timing-attack` warning - if (!hash.equals(scriptHash)) { - throw new WitnessVerifyError(); - } - - return { - verification, - offset: 0, - }; -}; - -export const verifyWithApplicationEngine = ( - vm: VM, - verifiable: Verifiable & SerializableContainer, - verification: Buffer, - index: number, - gas: BN, - offset: number, - init?: ContractMethodDescriptor, -): ExecuteScriptResult => - vm.withApplicationEngine( - { trigger: TriggerType.Verification, container: verifiable, snapshot: 'clone', gas }, - (engine) => { - engine.loadScript({ script: verification, flags: CallFlags.None, initialPosition: init ? init.offset : offset }); - engine.loadScript({ script: verifiable.witnesses[index].invocation, flags: CallFlags.None }); - - const state = engine.execute(); - if (state === VMState.FAULT) { - return { result: false, gas }; - } - - const stack = engine.resultStack; - if (stack.length !== 1 || !stack[0].getBoolean()) { - return { result: false, gas }; - } - - return { result: true, gas: gas.sub(engine.gasConsumed) }; - }, - ); - -export const tryVerifyHash = async ( - vm: VM, - hash: UInt160, - index: number, - storage: BlockchainStorage, - verifiable: Verifiable & SerializableContainer, - gas: BN, -): Promise => { - const { verification: verificationScript, scriptHash } = verifiable.witnesses[index]; - try { - const { verification, offset, init } = await getApplicationEngineVerifyOptions( - verificationScript, - storage, - hash, - scriptHash, - ); - - return verifyWithApplicationEngine(vm, verifiable, verification, index, gas, offset, init); - } catch { - return { gas, result: false }; - } -}; -export const verifyWitnesses = async ( - vm: VM, - verifiable: Verifiable & SerializableContainer, - storage: BlockchainStorage, - native: NativeContainer, - gasIn: BN, -): Promise => { +export const verifyWitnesses = async ({ + vm, + verifiable, + storage, + native, + gas: gasIn, + snapshot, +}: VerifyWitnessesOptions): Promise => { if (gasIn.ltn(0)) { return false; } - const gas = gasIn.gt(maxVerificationGas) ? maxVerificationGas : gasIn; + let gas = gasIn.gt(maxVerificationGas) ? maxVerificationGas : gasIn; let hashes: readonly UInt160[]; try { @@ -130,28 +34,97 @@ export const verifyWitnesses = async ( return false; } - const { next, previous } = await hashes - .slice(1) - .reduce; readonly previous: boolean }>>( - async (acc, hash, index) => { - const { next: accNext, previous: accPrevious } = await acc; - const { result, gas: newGas } = await accNext; - if (!result) { - return { - next: Promise.resolve({ result: false, gas: newGas }), - previous: false, - }; + // tslint:disable-next-line: no-loop-statement + for (let i = 0; i < hashes.length; i += 1) { + const { result, gas: gasCost } = await verifyWitness({ + vm, + verifiable, + storage, + native, + hash: hashes[i], + snapshot, + witness: verifiable.witnesses[i], + gas, + }); + + if (!result) { + return false; + } + + gas = gas.sub(gasCost); + } + + return true; +}; + +export const verifyWitness = async ({ + vm, + verifiable, + snapshot: snapshotIn, + storage, + native, + hash, + witness, + gas, +}: VerifyWitnessOptions): Promise => { + const initFee = new BN(0); + const { verification, invocation } = witness; + const callFlags = !crypto.isStandardContract(verification) ? CallFlags.ReadStates : CallFlags.None; + + let contract: ContractState | undefined; + if (verification.length === 0) { + contract = await native.Management.getContract(storage, hash); + if (contract === undefined) { + return { result: false, gas: initFee }; + } + } + + const snapshot = snapshotIn ?? 'clone'; + vm.withSnapshots(({ main }) => { + if (snapshotIn === 'clone') { + main.clone(); + } + }); + + return vm.withApplicationEngine( + { + trigger: TriggerType.Verification, + container: verifiable, + snapshot, + gas, + }, + async (engine) => { + if (contract !== undefined) { + const loadContractResult = engine.loadContract({ + hash, + method: 'verify', + flags: callFlags, + packParameters: true, + }); + if (!loadContractResult) { + return { result: false, gas: initFee }; + } + } else { + // tslint:disable-next-line: possible-timing-attack + if (native.isNative(hash) || hash !== witness.scriptHash) { + return { result: false, gas: initFee }; } - return { - next: tryVerifyHash(vm, hash, index, storage, verifiable, newGas), - previous: accPrevious && result, - }; - }, - Promise.resolve({ next: tryVerifyHash(vm, hashes[0], 0, storage, verifiable, gas), previous: true }), - ); + engine.loadScript({ script: verification, flags: callFlags, scriptHash: hash, initialPosition: 0 }); + } - const { result: finalResult } = await next; + engine.loadScript({ script: invocation, flags: CallFlags.None }); + const result = engine.execute(); - return finalResult && previous; + if (result === VMState.FAULT) { + return { result: false, gas: initFee }; + } + + if (engine.resultStack.length !== 1 || !engine.resultStack[0].getBoolean()) { + return { result: false, gas: initFee }; + } + + return { result: true, gas: engine.gasConsumed }; + }, + ); }; diff --git a/packages/neo-one-node-core/src/ContractState.ts b/packages/neo-one-node-core/src/ContractState.ts index a630a6c903..00b4b868c8 100644 --- a/packages/neo-one-node-core/src/ContractState.ts +++ b/packages/neo-one-node-core/src/ContractState.ts @@ -2,8 +2,7 @@ import { common, ContractJSON, IOHelper, JSONHelper, UInt160 } from '@neo-one/cl import { ContractStateModel } from '@neo-one/client-full-common'; import { ContractManifest } from './manifest'; import { utils } from './utils'; -import { StackItem } from './StackItems'; -import { assertArrayStackItem } from 'dist/cjs'; +import { StackItem, assertArrayStackItem } from './StackItems'; export interface ContractStateAdd { readonly id: number; diff --git a/packages/neo-one-node-core/src/Native.ts b/packages/neo-one-node-core/src/Native.ts index 68bc3c2ad3..ed2e92fab7 100644 --- a/packages/neo-one-node-core/src/Native.ts +++ b/packages/neo-one-node-core/src/Native.ts @@ -1,11 +1,11 @@ import { ECPoint, UInt160 } from '@neo-one/client-common'; import { BN } from 'bn.js'; +import { ContractState } from './ContractState'; +import { DesignationRole } from './DesignationRole'; +import { OracleRequest } from './OracleRequest'; import { ReadFindStorage } from './Storage'; import { StorageItem } from './StorageItem'; import { StorageKey } from './StorageKey'; -import { ContractState } from './ContractState'; -import { OracleRequest } from './OracleRequest'; -import { DesignationRole } from './DesignationRole'; export type OracleRequestResults = ReadonlyArray; @@ -53,10 +53,11 @@ export interface NEOContract extends NEP17NativeContract { readonly getCommitteeAddress: (storage: NativeContractStorageContext) => Promise; readonly unclaimedGas: (storage: NativeContractStorageContext, account: UInt160, end: number) => Promise; readonly getNextBlockValidators: (storage: NativeContractStorageContext) => Promise; + readonly computeNextBlockValidators: (storage: NativeContractStorageContext) => Promise; } export interface ManagementContract extends NativeContract { - readonly getContract: (storage: NativeContractStorageContext, hash: UInt160) => Promise; + readonly getContract: (storage: NativeContractStorageContext, hash: UInt160) => Promise; readonly listContracts: (storage: NativeContractStorageContext) => Promise; } @@ -70,7 +71,7 @@ export interface DesignationContract extends NativeContract { } export interface OracleContract extends NativeContract { - readonly getRequest: (storage: NativeContractStorageContext, id: BN) => Promise; + readonly getRequest: (storage: NativeContractStorageContext, id: BN) => Promise; readonly getRequests: (storage: NativeContractStorageContext) => Promise; readonly getRequestsByUrl: (storage: NativeContractStorageContext, url: string) => Promise; } @@ -82,4 +83,5 @@ export interface NativeContainer { readonly Management: ManagementContract; readonly Designation: DesignationContract; readonly Oracle: OracleContract; + readonly isNative: (hash: UInt160) => boolean; } diff --git a/packages/neo-one-node-core/src/Storage.ts b/packages/neo-one-node-core/src/Storage.ts index 2cefae8ca9..8f55036282 100644 --- a/packages/neo-one-node-core/src/Storage.ts +++ b/packages/neo-one-node-core/src/Storage.ts @@ -134,12 +134,10 @@ export interface BlockchainStorage { readonly applicationLogs: ReadStorage; // readonly consensusState: ReadMetadataStorage; readonly transactions: ReadStorage; - readonly contracts: ReadStorage; readonly storages: ReadFindStorage; readonly headerHashList: ReadStorage; readonly blockHashIndex: ReadMetadataStorage; readonly headerHashIndex: ReadMetadataStorage; - readonly contractID: ReadMetadataStorage; } export interface Storage extends BlockchainStorage { diff --git a/packages/neo-one-node-core/src/TransactionVerificationContext.ts b/packages/neo-one-node-core/src/TransactionVerificationContext.ts index b913ec208f..1cdbc9fc1a 100644 --- a/packages/neo-one-node-core/src/TransactionVerificationContext.ts +++ b/packages/neo-one-node-core/src/TransactionVerificationContext.ts @@ -1,7 +1,7 @@ -import { common, UInt160, UInt160Hex } from '@neo-one/client-common'; +import { common, UInt160, UInt160Hex, UInt256Hex } from '@neo-one/client-common'; import { BN } from 'bn.js'; import { NativeContractStorageContext } from './Native'; -import { Transaction } from './transaction'; +import { isOracleResponse, Transaction } from './transaction'; const assertSender = (sender: UInt160 | undefined) => { if (sender === undefined) { @@ -19,13 +19,20 @@ export interface TransactionVerificationContextAdd { export class TransactionVerificationContext { private readonly getGasBalance: (storage: NativeContractStorageContext, sender: UInt160) => Promise; private readonly mutableSenderFee: Record; + private readonly mutableOracleResponses: Record; public constructor({ getGasBalance }: TransactionVerificationContextAdd) { this.getGasBalance = getGasBalance; this.mutableSenderFee = {}; + this.mutableOracleResponses = {}; } public addTransaction(tx: Transaction) { + const oracle = tx.getAttribute(isOracleResponse); + if (oracle !== undefined) { + this.mutableOracleResponses[oracle.id.toString()] = tx.hashHex; + } + const key = common.uInt160ToHex(assertSender(tx.sender)); const maybeFee = this.mutableSenderFee[key] ?? new BN(0); this.mutableSenderFee[key] = maybeFee.add(tx.systemFee).add(tx.networkFee); @@ -37,7 +44,16 @@ export class TransactionVerificationContext { const maybeFee = this.mutableSenderFee[common.uInt160ToHex(sender)] ?? new BN(0); const totalFee = maybeFee.add(tx.systemFee).add(tx.networkFee); - return balance.gte(totalFee); + if (balance.lt(totalFee)) { + return false; + } + + const oracle = tx.getAttribute(isOracleResponse); + if (oracle !== undefined && this.mutableOracleResponses[oracle.id.toString()] !== undefined) { + return false; + } + + return true; } public removeTransaction(tx: Transaction) { @@ -56,5 +72,11 @@ export class TransactionVerificationContext { } else { this.mutableSenderFee[key] = newFee; } + + const oracle = tx.getAttribute(isOracleResponse); + if (oracle !== undefined) { + // tslint:disable-next-line: no-dynamic-delete + delete this.mutableOracleResponses[oracle.id.toString()]; + } } } diff --git a/packages/neo-one-node-core/src/Verifiable.ts b/packages/neo-one-node-core/src/Verifiable.ts index cf06cbba51..a4e49a50ee 100644 --- a/packages/neo-one-node-core/src/Verifiable.ts +++ b/packages/neo-one-node-core/src/Verifiable.ts @@ -1,11 +1,12 @@ -import { UInt160 } from '@neo-one/client-common'; +import { common, UInt160 } from '@neo-one/client-common'; import { BN } from 'bn.js'; import { NativeContainer } from './Native'; import { SerializableContainer } from './Serializable'; import { BlockchainStorage } from './Storage'; -import { VM } from './vm'; +import { SnapshotName, VM } from './vm'; import { Witness } from './Witness'; +export const maxVerificationGas = common.fixed8FromDecimal('0.5'); export interface Verifiable { readonly getScriptHashesForVerifying: (context: { readonly storage: BlockchainStorage; @@ -19,19 +20,31 @@ export interface ExecuteScriptResult { readonly result: boolean; } -export type VerifyWitnesses = ( - vm: VM, - verifiable: SerializableContainer, - storage: BlockchainStorage, - native: NativeContainer, - gasIn: BN, -) => Promise; +export interface VerifyWitnessesOptions { + readonly vm: VM; + readonly verifiable: SerializableContainer; + readonly storage: BlockchainStorage; + readonly native: NativeContainer; + readonly gas: BN; + readonly snapshot?: SnapshotName; +} + +export type VerifyWitnesses = (options: VerifyWitnessesOptions) => Promise; + +export interface VerifyWitnessOptions extends VerifyWitnessesOptions { + readonly hash: UInt160; + readonly witness: Witness; +} + +export type VerifyWitness = (options: VerifyWitnessOptions) => Promise; export interface VerifyOptions { + readonly height: number; readonly vm: VM; readonly storage: BlockchainStorage; readonly native: NativeContainer; readonly verifyWitnesses: VerifyWitnesses; + readonly verifyWitness: VerifyWitness; } /* I think all of this might be a useless abstraction of blockchain properties. */ diff --git a/packages/neo-one-node-core/src/errors.ts b/packages/neo-one-node-core/src/errors.ts index 621129b3ac..a86fdb8107 100644 --- a/packages/neo-one-node-core/src/errors.ts +++ b/packages/neo-one-node-core/src/errors.ts @@ -1,3 +1,4 @@ +import { OracleResponseCode } from '@neo-one/client-common'; import { makeErrorWithCode } from '@neo-one/utils'; // tslint:disable-next-line export-name @@ -74,3 +75,8 @@ export const InvalidOpCodeError = makeErrorWithCode( 'INVALID_OP_CODE_ERROR', (value: number) => `Cannot find fee for OpCode ${value}.`, ); +export const InvalidOracleResultError = makeErrorWithCode( + 'INVALID_ORACLE_RESULT_ERROR', + (code: OracleResponseCode, resultLength: number) => + `Expected result.length to be 0 with response code ${OracleResponseCode[code]}, found: ${resultLength}`, +); diff --git a/packages/neo-one-node-core/src/payload/ConsensusPayload.ts b/packages/neo-one-node-core/src/payload/ConsensusPayload.ts index 9cf52cce44..2ed061ac3b 100644 --- a/packages/neo-one-node-core/src/payload/ConsensusPayload.ts +++ b/packages/neo-one-node-core/src/payload/ConsensusPayload.ts @@ -1,6 +1,7 @@ import { AccountContract, BinaryWriter, + common, createSerializeWire, crypto, ECPoint, @@ -9,16 +10,14 @@ import { PrivateKey, } from '@neo-one/client-common'; import { ContractParametersContext } from '../ContractParametersContext'; -import { NativeContainer } from '../Native'; import { DeserializeWireBaseOptions, DeserializeWireOptions, SerializableContainer, SerializableContainerType, } from '../Serializable'; -import { BlockchainStorage } from '../Storage'; -import { BinaryReader, utils } from '../utils'; -import { Verifiable, VerifyOptions } from '../Verifiable'; +import { BinaryReader } from '../utils'; +import { VerifyOptions } from '../Verifiable'; import { Witness } from '../Witness'; import { ConsensusMessage } from './message'; import { UnsignedConsensusPayload, UnsignedConsensusPayloadAdd } from './UnsignedConsensusPayload'; @@ -26,12 +25,7 @@ import { UnsignedConsensusPayload, UnsignedConsensusPayloadAdd } from './Unsigne export interface ConsensusPayloadAdd extends UnsignedConsensusPayloadAdd { readonly witness: Witness; } - -export interface VerifyConsensusPayloadOptions extends VerifyOptions { - readonly height: number; -} - -export class ConsensusPayload extends UnsignedConsensusPayload { +export class ConsensusPayload extends UnsignedConsensusPayload implements SerializableContainer { public static sign( payload: UnsignedConsensusPayload, privateKey: PrivateKey, @@ -117,11 +111,11 @@ export class ConsensusPayload extends UnsignedConsensusPayload { return this.consensusMessage as T; } - public async verify(options: VerifyConsensusPayloadOptions) { + public async verify(options: VerifyOptions) { if (this.blockIndex <= options.height) { return false; } - return options.verifyWitnesses(options.vm, this, options.storage, options.native, 0.02); + return options.verifyWitnesses(options.vm, this, options.storage, options.native, common.fixed8FromDecimal('0.02')); } } diff --git a/packages/neo-one-node-core/src/transaction/Transaction.ts b/packages/neo-one-node-core/src/transaction/Transaction.ts index cb46f4499e..9b3d4916c5 100644 --- a/packages/neo-one-node-core/src/transaction/Transaction.ts +++ b/packages/neo-one-node-core/src/transaction/Transaction.ts @@ -1,12 +1,15 @@ import { AttributeTypeModel, common, + crypto, InvalidFormatError, IOHelper, JSONHelper, MAX_TRANSACTION_SIZE, MAX_VALID_UNTIL_BLOCK_INCREMENT, + multiSignatureContractCost, scriptHashToAddress, + signatureContractCost, TransactionJSON, TransactionModel, TransactionModelAdd, @@ -26,7 +29,7 @@ import { import { Signer } from '../Signer'; import { TransactionVerificationContext } from '../TransactionVerificationContext'; import { BinaryReader, utils } from '../utils'; -import { Verifiable, VerifyOptions } from '../Verifiable'; +import { maxVerificationGas, Verifiable, VerifyOptions } from '../Verifiable'; import { Witness } from '../Witness'; import { Attribute, deserializeAttribute } from './attributes'; @@ -174,20 +177,19 @@ export class Transaction IOHelper.sizeOfArray(this.witnesses, (witness) => witness.size), ); - public async verifyForEachBlock( + public async verifyStateDependent( verifyOptions: VerifyOptions, transactionContext?: TransactionVerificationContext, ): Promise { - const { storage, native } = verifyOptions; + const { storage, native, verifyWitness, vm } = verifyOptions; const { index } = await storage.blockHashIndex.get(); - if (this.validUntilBlock < index || this.validUntilBlock > index + MAX_VALID_UNTIL_BLOCK_INCREMENT) { + if (this.validUntilBlock <= index || this.validUntilBlock > index + MAX_VALID_UNTIL_BLOCK_INCREMENT) { return VerifyResultModel.Expired; } const hashes = this.getScriptHashesForVerifying(); - const setHashes = new Set(hashes); - const blockedAccounts = await native.Policy.getBlockedAccounts(storage); - if (blockedAccounts.some((account) => setHashes.has(account))) { + const blocked = await Promise.all(hashes.map(async (hash) => native.Policy.isBlocked(storage, hash))); + if (blocked.some((bool) => bool)) { return VerifyResultModel.PolicyFail; } @@ -212,21 +214,64 @@ export class Transaction return VerifyResultModel.Invalid; } - const verifyHashes = await Promise.all( - hashes.map(async (hash, idx) => { - if (this.witnesses[idx].verification.length > 0) { - return true; + const [feePerByte, execFeeFactor] = await Promise.all([ + native.Policy.getFeePerByte(storage), + native.Policy.getExecFeeFactor(storage), + ]); + + let netFee = this.networkFee.sub(feePerByte.muln(this.size)); + // tslint:disable-next-line: no-loop-statement + for (let i = 0; i < hashes.length; i += 1) { + const witness = this.witnesses[i]; + const multiSigResult = crypto.isMultiSigContractWithResult(witness.verification); + if (multiSigResult.result) { + const { m, n } = multiSigResult; + netFee = netFee.sub(new BN(multiSignatureContractCost(m, n).toString(), 10).muln(execFeeFactor)); + } else if (crypto.isSignatureContract(witness.verification)) { + netFee = netFee.sub(new BN(signatureContractCost.toString(), 10).muln(execFeeFactor)); + } else { + const { result, gas } = await verifyWitness(vm, this, storage, native, hashes[i], witness, netFee); + if (!result) { + return VerifyResultModel.InsufficientFunds; } - const state = await storage.contracts.tryGet(hash); + netFee = netFee.sub(gas); + } + if (netFee.ltn(0)) { + return VerifyResultModel.InsufficientFunds; + } + } - return state !== undefined; - }), - ); + return VerifyResultModel.Succeed; + } - if (verifyHashes.some((value) => !value)) { + public async verifyStateIndependent(verifyOptions: VerifyOptions) { + const { storage, native, verifyWitness, vm } = verifyOptions; + if (this.size > MAX_TRANSACTION_SIZE) { + return VerifyResultModel.Invalid; + } + const hashes = this.getScriptHashesForVerifying(); + if (hashes.length !== this.witnesses.length) { return VerifyResultModel.Invalid; } + // tslint:disable-next-line: no-loop-statement + for (let i = 0; i < hashes.length; i += 1) { + if (crypto.isStandardContract(this.witnesses[i].verification)) { + const { result } = await verifyWitness( + vm, + this, + storage, + native, + hashes[i], + this.witnesses[i], + maxVerificationGas, + ); + if (!result) { + return VerifyResultModel.Invalid; + } + } + } + return VerifyResultModel.Succeed; } @@ -234,26 +279,12 @@ export class Transaction verifyOptions: VerifyOptions, verifyContext?: TransactionVerificationContext, ): Promise { - const { native, storage, verifyWitnesses, vm } = verifyOptions; - const result = await this.verifyForEachBlock(verifyOptions, verifyContext); - if (result !== VerifyResultModel.Succeed) { - return result; - } - if (this.size > MAX_TRANSACTION_SIZE) { - return VerifyResultModel.Invalid; - } - const feePerByte = await native.Policy.getFeePerByte(storage); - const netFee = this.networkFee.sub(feePerByte.muln(this.size)); - if (netFee.ltn(0)) { - return VerifyResultModel.InsufficientFunds; + const independentResult = await this.verifyStateIndependent(verifyOptions); + if (independentResult !== VerifyResultModel.Succeed) { + return independentResult; } - const witnessVerify = await verifyWitnesses(vm, this, storage, native, netFee); - if (!witnessVerify) { - return VerifyResultModel.Invalid; - } - - return VerifyResultModel.Succeed; + return this.verifyStateDependent(verifyOptions, verifyContext); } public serializeJSON(): TransactionJSON { diff --git a/packages/neo-one-node-core/src/transaction/attributes/Attribute.ts b/packages/neo-one-node-core/src/transaction/attributes/Attribute.ts index 2b041f0ea3..dc06e15031 100644 --- a/packages/neo-one-node-core/src/transaction/attributes/Attribute.ts +++ b/packages/neo-one-node-core/src/transaction/attributes/Attribute.ts @@ -1,8 +1,9 @@ import { assertAttributeType, AttributeTypeModel, InvalidFormatError } from '@neo-one/client-common'; import { DeserializeWireBaseOptions } from '../../Serializable'; import { HighPriorityAttribute } from './HighPriorityAttribute'; +import { OracleResponse } from './OracleResponse'; -export type Attribute = HighPriorityAttribute; +export type Attribute = HighPriorityAttribute | OracleResponse; export const deserializeAttribute = (options: DeserializeWireBaseOptions): Attribute => { const { reader } = options; @@ -11,8 +12,16 @@ export const deserializeAttribute = (options: DeserializeWireBaseOptions): Attri switch (type) { case AttributeTypeModel.HighPriority: - return new HighPriorityAttribute(); + return HighPriorityAttribute.deserializeWithoutType(reader); + case AttributeTypeModel.OracleResponse: + return OracleResponse.deserializeWithoutType(reader); default: throw new InvalidFormatError(`Attribute type ${type} not yet implemented`); } }; + +export const getIsAttribute = (type: AttributeTypeModel) => (attr: Attribute): attr is T => + attr.type === type; + +export const isHighPriorityAttribute = getIsAttribute(AttributeTypeModel.HighPriority); +export const isOracleResponse = getIsAttribute(AttributeTypeModel.OracleResponse); diff --git a/packages/neo-one-node-core/src/transaction/attributes/AttributeBase.ts b/packages/neo-one-node-core/src/transaction/attributes/AttributeBase.ts index cc5ccddb5d..9816f814ee 100644 --- a/packages/neo-one-node-core/src/transaction/attributes/AttributeBase.ts +++ b/packages/neo-one-node-core/src/transaction/attributes/AttributeBase.ts @@ -1,34 +1,7 @@ -import { - AttributeBaseModel, - AttributeJSON, - AttributeTypeModel, - InvalidFormatError, - IOHelper, - toJSONAttributeType, -} from '@neo-one/client-common'; -import { DeserializeWireBaseOptions, SerializableJSON } from '../../Serializable'; +import { AttributeJSON, SerializableJSON } from '@neo-one/client-common'; import { VerifyOptions } from '../../Verifiable'; import { Transaction } from '../Transaction'; -export const createDeserializeAttributeType = (type: AttributeTypeModel) => (options: DeserializeWireBaseOptions) => { - const { reader } = options; - const byte = reader.readUInt8(); - if (byte !== type) { - throw new InvalidFormatError(`Expected attribute type: ${type}, found: ${byte}`); - } - - return type; -}; - -export abstract class AttributeBase extends AttributeBaseModel implements SerializableJSON { - public serializeJSON(): AttributeJSON { - return { - type: toJSONAttributeType(this.type), - }; - } - - // Must not be implemented in C# land yet? - public async verify(_verifyOptions: VerifyOptions, _tx: Transaction) { - return Promise.resolve(true); - } +export interface AttributeBase extends SerializableJSON { + readonly verify: (verifyOptions: VerifyOptions, tx: Transaction) => Promise; } diff --git a/packages/neo-one-node-core/src/transaction/attributes/HighPriorityAttribute.ts b/packages/neo-one-node-core/src/transaction/attributes/HighPriorityAttribute.ts index 42bc09f28f..e1cd54a250 100644 --- a/packages/neo-one-node-core/src/transaction/attributes/HighPriorityAttribute.ts +++ b/packages/neo-one-node-core/src/transaction/attributes/HighPriorityAttribute.ts @@ -1,7 +1,23 @@ -import { AttributeTypeModel } from '@neo-one/client-common'; +import { HighPriorityAttributeJSON, HighPriorityAttributeModel } from '@neo-one/client-common'; +import { BinaryReader } from '../../utils'; +import { VerifyOptions } from '../../Verifiable'; +import { Transaction } from '../Transaction'; import { AttributeBase } from './AttributeBase'; -export class HighPriorityAttribute extends AttributeBase { - public readonly type = AttributeTypeModel.HighPriority; - public readonly allowMultiple = false; +export class HighPriorityAttribute + extends HighPriorityAttributeModel + implements AttributeBase { + public static deserializeWithoutType(_reader: BinaryReader) { + return new HighPriorityAttribute(); + } + + public serializeJSON(): HighPriorityAttributeJSON { + return { + type: 'HighPriority', + }; + } + + public async verify(_verifyOptions: VerifyOptions, _tx: Transaction) { + return Promise.resolve(true); + } } diff --git a/packages/neo-one-node-core/src/transaction/attributes/OracleResponse.ts b/packages/neo-one-node-core/src/transaction/attributes/OracleResponse.ts new file mode 100644 index 0000000000..7d4bb36115 --- /dev/null +++ b/packages/neo-one-node-core/src/transaction/attributes/OracleResponse.ts @@ -0,0 +1,84 @@ +import { + assertOracleResponseCode, + common, + crypto, + JSONHelper, + OracleResponseCode, + OracleResponseJSON, + OracleResponseModel, + ScriptBuilder, + utils, + WitnessScopeModel, +} from '@neo-one/client-common'; +import { DesignationRole } from '../../DesignationRole'; +import { InvalidOracleResultError } from '../../errors'; +import { BinaryReader } from '../../utils'; +import { VerifyOptions } from '../../Verifiable'; +import { Transaction } from '../Transaction'; +import { AttributeBase } from './AttributeBase'; + +const maxResultSize = 65535; + +const getFixedScript = utils.lazy(() => { + const builder = new ScriptBuilder(); + builder.emitAppCall(common.nativeHashes.Oracle, 'finish'); + + return builder.build(); +}); + +export class OracleResponse extends OracleResponseModel implements AttributeBase { + public static readonly fixedScript = getFixedScript(); + public static deserializeWithoutType(reader: BinaryReader): OracleResponse { + const id = reader.readUInt64LE(); + const code = assertOracleResponseCode(reader.readUInt8()); + const result = reader.readVarBytesLE(maxResultSize); + + if (code !== OracleResponseCode.Success && result.length > 0) { + throw new InvalidOracleResultError(code, result.length); + } + + return new OracleResponse({ + id, + code, + result, + }); + } + + public serializeJSON(): OracleResponseJSON { + return { + type: 'OracleResponse', + id: this.id.toString(), + code: this.code, + result: JSONHelper.writeBase64Buffer(this.result), + }; + } + + public async verify({ native, storage, height }: VerifyOptions, tx: Transaction) { + if (tx.signers.some((signer) => signer.scopes !== WitnessScopeModel.None)) { + return false; + } + + if (!tx.script.equals(OracleResponse.fixedScript)) { + return false; + } + + const request = await native.Oracle.getRequest(storage, this.id); + if (request === undefined) { + return false; + } + + if (!tx.networkFee.add(tx.systemFee).eq(request.gasForResponse)) { + return false; + } + + const designated = await native.Designation.getDesignatedByRole( + storage, + DesignationRole.Oracle, + height, + height + 1, + ); + const oracleAccount = crypto.getConsensusAddress(designated); + + return tx.signers.some((signer) => signer.account.equals(oracleAccount)); + } +} diff --git a/packages/neo-one-node-core/src/vm.ts b/packages/neo-one-node-core/src/vm.ts index 01755a30a8..853f04d171 100644 --- a/packages/neo-one-node-core/src/vm.ts +++ b/packages/neo-one-node-core/src/vm.ts @@ -1,4 +1,4 @@ -import { TriggerType, UInt256, VMState, Log, UInt160 } from '@neo-one/client-common'; +import { Log, TriggerType, UInt160, UInt256, VMState } from '@neo-one/client-common'; import { BN } from 'bn.js'; import { Block } from './Block'; import { CallFlags } from './CallFlags'; @@ -47,6 +47,13 @@ export interface LoadScriptOptions { readonly initialPosition?: number; } +export interface LoadContractOptions { + readonly hash: UInt160; + readonly flags: CallFlags; + readonly method: string; + readonly packParameters?: boolean; +} + export interface ApplicationEngine { readonly trigger: TriggerType; readonly gasConsumed: BN; @@ -55,6 +62,7 @@ export interface ApplicationEngine { readonly notifications: readonly StackItem[]; readonly logs: readonly VMLog[]; readonly loadScript: (options: LoadScriptOptions) => boolean; + readonly loadContract: (options: LoadContractOptions) => boolean; readonly execute: () => VMState; } @@ -71,6 +79,7 @@ export interface SnapshotHandler { readonly setPersistingBlock: (block: Block) => boolean; readonly hasPersistingBlock: () => boolean; // TODO: type the returning changeSet + // tslint:disable-next-line: no-any readonly getChangeSet: () => any; readonly clone: () => void; } @@ -95,6 +104,7 @@ export interface VM { readonly withSnapshots: ( func: (snapshots: { readonly main: SnapshotHandler; readonly clone: Omit }) => T, ) => T; - readonly updateStore: (storage: ReadonlyArray<{ key: Buffer; value: Buffer }>) => void; + readonly updateStore: (storage: ReadonlyArray<{ readonly key: Buffer; readonly value: Buffer }>) => void; + // tslint:disable-next-line: no-any readonly test: () => any; } diff --git a/packages/neo-one-node-native/src/CachedCommittee.ts b/packages/neo-one-node-native/src/CachedCommittee.ts index 1f3c2c2b43..7aaa73d78a 100644 --- a/packages/neo-one-node-native/src/CachedCommittee.ts +++ b/packages/neo-one-node-native/src/CachedCommittee.ts @@ -1,5 +1,5 @@ -import { StackItem, assertArrayStackItem, assertStructStackItem } from '@neo-one/node-core'; -import { ECPoint, common } from '@neo-one/client-common'; +import { common, ECPoint } from '@neo-one/client-common'; +import { assertArrayStackItem, assertStructStackItem, StackItem } from '@neo-one/node-core'; import { BN } from 'bn.js'; interface CachedCommitteeElement { diff --git a/packages/neo-one-node-native/src/DesignationContract.ts b/packages/neo-one-node-native/src/DesignationContract.ts index 453cef4177..7d4c9add5b 100644 --- a/packages/neo-one-node-native/src/DesignationContract.ts +++ b/packages/neo-one-node-native/src/DesignationContract.ts @@ -17,6 +17,12 @@ export class DesignationContract extends NativeContract { }); } + /** + * passing in height and index is a pretty HMMM way to do this but in the vein of being + * consistent with C# code as much as possible we will do it like this. The reasoning + * being that our snapshot equivalent 'storage' doesn't have knowledge of the current height, + * that is a blockchain abstraction. In almost no situation should this first error actually throw. + */ public async getDesignatedByRole( { storages }: NativeContractStorageContext, role: Role, diff --git a/packages/neo-one-node-native/src/ManagementContract.ts b/packages/neo-one-node-native/src/ManagementContract.ts index b6a5a25bce..b7aaa0d742 100644 --- a/packages/neo-one-node-native/src/ManagementContract.ts +++ b/packages/neo-one-node-native/src/ManagementContract.ts @@ -1,7 +1,7 @@ -import { NativeContract } from './NativeContract'; -import { NativeContractStorageContext, utils, ContractState } from '@neo-one/node-core'; import { UInt160 } from '@neo-one/client-common'; +import { ContractState, NativeContractStorageContext, utils } from '@neo-one/node-core'; import { map, toArray } from 'rxjs/operators'; +import { NativeContract } from './NativeContract'; export class ManagementContract extends NativeContract { private readonly prefixes = { @@ -31,6 +31,7 @@ export class ManagementContract extends NativeContract { public async listContracts({ storages }: NativeContractStorageContext) { const searchPrefix = this.createStorageKey(this.prefixes.contract).toSearchPrefix(); + return storages .find$(searchPrefix) .pipe( diff --git a/packages/neo-one-node-native/src/NEOToken.ts b/packages/neo-one-node-native/src/NEOToken.ts index 3c9b909c3d..0d11c4e309 100644 --- a/packages/neo-one-node-native/src/NEOToken.ts +++ b/packages/neo-one-node-native/src/NEOToken.ts @@ -1,11 +1,11 @@ -import { common, crypto, ECPoint, UInt160 } from '@neo-one/client-common'; +import { common, crypto, ECPoint, InvalidFormatError, UInt160 } from '@neo-one/client-common'; import { BlockchainSettings, Candidate, NativeContractStorageContext, utils } from '@neo-one/node-core'; import { BN } from 'bn.js'; import _ from 'lodash'; import { filter, map, toArray } from 'rxjs/operators'; import { CandidateState, NEOAccountState } from './AccountStates'; -import { NEP17NativeContract } from './Nep17'; import { CachedCommittee } from './CachedCommittee'; +import { NEP17NativeContract } from './Nep17'; type Storages = NativeContractStorageContext['storages']; @@ -22,6 +22,15 @@ interface GasRecord { readonly gasPerBlock: BN; } +const candidateSort = (a: Candidate, b: Candidate) => { + const voteComp = a.votes.cmp(b.votes); + if (voteComp !== 0) { + return voteComp; + } + + return a.publicKey.compare(b.publicKey); +}; + export class NEOToken extends NEP17NativeContract { public readonly totalAmount: BN; // TODO: investigate this usage, its a strange decimal value in C# world. `0.2M`. Something to do with rounding. @@ -91,9 +100,21 @@ export class NEOToken extends NEP17NativeContract { public async getCommitteeFromCache({ storages }: NativeContractStorageContext): Promise { const item = await storages.get(this.createStorageKey(this.prefixes.committee).toStorageKey()); + return utils.getInteroperable(item, CachedCommittee.fromStackItem); } + public async computeNextBlockValidators(storage: NativeContractStorageContext): Promise { + const committeeMembers = await this.computeCommitteeMembers(storage); + + return _.take( + committeeMembers.map(({ publicKey }) => publicKey), + this.settings.validatorsCount, + ) + .slice() + .sort(common.ecPointCompare); + } + public async unclaimedGas({ storages }: NativeContractStorageContext, account: UInt160, end: number) { const storage = await storages.tryGet( this.createStorageKey(this.basePrefixes.account).addBuffer(account).toStorageKey(), @@ -126,8 +147,7 @@ export class NEOToken extends NEP17NativeContract { return new BN(0); } if (value.ltn(0)) { - // TODO: create a real error for here - throw new Error('negative value not supported'); + throw new InvalidFormatError('negative value not supported'); } const neoHolderReward = await this.calculateNeoHolderReward(storages, value, start, end); @@ -158,6 +178,7 @@ export class NEOToken extends NEP17NativeContract { private async calculateNeoHolderReward(storages: Storages, value: BN, start: number, end: number) { let sum = new BN(0); const sortedGasRecords = await this.getSortedGasRecords(storages, end); + // tslint:disable-next-line: no-loop-statement for (const { index, gasPerBlock } of sortedGasRecords) { if (index > start) { sum = sum.add(gasPerBlock.muln(end - index)); @@ -171,9 +192,10 @@ export class NEOToken extends NEP17NativeContract { } private async getSortedGasRecords(storages: Storages, end: number): Promise { - const key = this.createStorageKey(this.prefixes.gasPerBlock).addUInt32BE(end).toSearchPrefix(); + const prefix = this.createStorageKey(this.prefixes.gasPerBlock).addUInt32BE(end).toSearchPrefix(); const boundary = this.createStorageKey(this.prefixes.gasPerBlock).toSearchPrefix(); - const range = await storages.find$(key, boundary).pipe(toArray()).toPromise(); + const range = await storages.find$(prefix, boundary).pipe(toArray()).toPromise(); + return range .map(({ key, value }) => ({ index: key.key.readUInt32BE(4), @@ -181,4 +203,20 @@ export class NEOToken extends NEP17NativeContract { })) .reverse(); } + + private async computeCommitteeMembers({ storages }: NativeContractStorageContext): Promise { + const item = await storages.get(this.createStorageKey(this.prefixes.votersCount).toStorageKey()); + const votersCount = new BN(item.value).toNumber(); + const voterTurnout = votersCount / this.totalAmount.toNumber(); + const candidates = await this.getCandidates({ storages }); + + if (voterTurnout < this.effectiveVoterTurnout || candidates.length < this.settings.committeeMembersCount) { + return this.settings.standbyCommittee.map((member) => ({ + publicKey: member, + votes: candidates.find((candidate) => candidate.publicKey.equals(member))?.votes ?? new BN(0), + })); + } + + return _.take(candidates.slice().sort(candidateSort), this.settings.committeeMembersCount); + } } diff --git a/packages/neo-one-node-native/src/NativeContainer.ts b/packages/neo-one-node-native/src/NativeContainer.ts index 3bc4fc14da..144de0a2cd 100644 --- a/packages/neo-one-node-native/src/NativeContainer.ts +++ b/packages/neo-one-node-native/src/NativeContainer.ts @@ -1,10 +1,11 @@ +import { UInt160 } from '@neo-one/client-common'; import { BlockchainSettings } from '@neo-one/node-core'; +import { DesignationContract } from './DesignationContract'; import { GASToken } from './GASToken'; -import { NEOToken } from './NEOToken'; -import { PolicyContract } from './Policy'; import { ManagementContract } from './ManagementContract'; +import { NEOToken } from './NEOToken'; import { OracleContract } from './OracleContract'; -import { DesignationContract } from './DesignationContract'; +import { PolicyContract } from './Policy'; export class NativeContainer { public readonly Management: ManagementContract; @@ -13,6 +14,7 @@ export class NativeContainer { public readonly Policy: PolicyContract; public readonly Oracle: OracleContract; public readonly Designation: DesignationContract; + public readonly nativeHashes: readonly UInt160[]; public constructor(settings: BlockchainSettings) { this.Management = new ManagementContract(); @@ -21,5 +23,17 @@ export class NativeContainer { this.Policy = new PolicyContract(); this.Oracle = new OracleContract(); this.Designation = new DesignationContract(); + this.nativeHashes = [ + this.Management.hash, + this.NEO.hash, + this.GAS.hash, + this.Policy.hash, + this.Oracle.hash, + this.Designation.hash, + ]; + } + + public isNative(hash: UInt160) { + return this.nativeHashes.some((nativeHash) => hash.equals(nativeHash)); } } diff --git a/packages/neo-one-node-native/src/NativeContract.ts b/packages/neo-one-node-native/src/NativeContract.ts index b0b687ebbd..8b46fc560c 100644 --- a/packages/neo-one-node-native/src/NativeContract.ts +++ b/packages/neo-one-node-native/src/NativeContract.ts @@ -1,4 +1,4 @@ -import { crypto, ScriptBuilder, UInt160, common } from '@neo-one/client-common'; +import { common, crypto, ScriptBuilder, UInt160 } from '@neo-one/client-common'; import { KeyBuilder } from './KeyBuilder'; export interface NativeContractAdd { diff --git a/packages/neo-one-node-native/src/OracleContract.ts b/packages/neo-one-node-native/src/OracleContract.ts index 04d7ff4d9b..0f42a77488 100644 --- a/packages/neo-one-node-native/src/OracleContract.ts +++ b/packages/neo-one-node-native/src/OracleContract.ts @@ -1,15 +1,15 @@ import { crypto } from '@neo-one/client-common'; -import { NativeContract } from './NativeContract'; import { - NativeContractStorageContext, - utils, - StackItem, assertArrayStackItem, - OracleRequestResults, + NativeContractStorageContext, OracleRequest, + OracleRequestResults, + StackItem, + utils, } from '@neo-one/node-core'; import { BN } from 'bn.js'; import { map, toArray } from 'rxjs/operators'; +import { NativeContract } from './NativeContract'; export class OracleContract extends NativeContract { private readonly prefixes = { @@ -48,6 +48,7 @@ export class OracleContract extends NativeContract { .pipe( map( ({ key, value }) => + // tslint:disable-next-line: no-useless-cast [new BN(key.key.slice(1), 'le'), utils.getInteroperable(value, OracleRequest.fromStackItem)] as const, ), toArray(), @@ -87,7 +88,7 @@ class IdList { return new IdList(list); } - public list: readonly BN[]; + public readonly list: readonly BN[]; public constructor(list: readonly BN[]) { this.list = list; diff --git a/packages/neo-one-node-native/src/Policy.ts b/packages/neo-one-node-native/src/Policy.ts index 6d8b8fa174..1fcd3fc696 100644 --- a/packages/neo-one-node-native/src/Policy.ts +++ b/packages/neo-one-node-native/src/Policy.ts @@ -9,7 +9,7 @@ export class PolicyContract extends NativeContract { private readonly prefixes = { maxTransactionsPerBlock: Buffer.from([23]), feePerByte: Buffer.from([10]), - blockedAccounts: Buffer.from([15]), + blockedAccount: Buffer.from([15]), maxBlockSize: Buffer.from([12]), maxBlockSystemFee: Buffer.from([17]), execFeeFactor: Buffer.from([18]), @@ -82,8 +82,9 @@ export class PolicyContract extends NativeContract { public async isBlocked({ storages }: NativeContractStorageContext, account: UInt160) { const item = await storages.tryGet( - this.createStorageKey(this.prefixes.blockedAccounts).addBuffer(account).toStorageKey(), + this.createStorageKey(this.prefixes.blockedAccount).addBuffer(account).toStorageKey(), ); + return item !== undefined; } } diff --git a/packages/neo-one-node-protocol/src/Message.ts b/packages/neo-one-node-protocol/src/Message.ts index 735106bd7e..17da7813d8 100644 --- a/packages/neo-one-node-protocol/src/Message.ts +++ b/packages/neo-one-node-protocol/src/Message.ts @@ -32,6 +32,19 @@ import { VersionPayload, } from './payload'; +const tryCompression = ({ command }: MessageValue) => { + return ( + command === Command.Block || + command === Command.Consensus || + command === Command.Transaction || + command === Command.Headers || + command === Command.Addr || + command === Command.MerkleBlock || + command === Command.FilterLoad || + command === Command.FilterAdd + ); +}; + export type MessageValue = | { readonly command: Command.Addr; readonly payload: AddrPayload } | { readonly command: Command.Block; readonly payload: Block } @@ -188,7 +201,7 @@ export class Message implements SerializableWire { public static create(value: MessageValue): Message { // tslint:disable-next-line: no-any const payloadBuffer = (value as any)?.payload?.serializeWire() ?? Buffer.alloc(0); - if (payloadBuffer.length > compressionMinSize) { + if (tryCompression(value) && payloadBuffer.length > compressionMinSize) { const compressed = lz4Helper.compress(payloadBuffer); if (compressed.length < payloadBuffer.length - compressionThreshold) { return new Message({ diff --git a/packages/neo-one-node-protocol/src/Node.ts b/packages/neo-one-node-protocol/src/Node.ts index 43d5f16961..326ecab1e8 100644 --- a/packages/neo-one-node-protocol/src/Node.ts +++ b/packages/neo-one-node-protocol/src/Node.ts @@ -135,11 +135,6 @@ const compareTransactionAndFees = (val1: TransactionAndFee, val2: TransactionAnd return val1.transaction.hash.compare(val2.transaction.hash); }; -// TODO: We should note what some of these settings used to be, I've made them more aggressive -// while we are testing syncing; and then testnet can be a bit slow. -// const GET_BLOCKS_THROTTLE_MS = 1000; -// const GET_BLOCKS_TIME_MS = 5000; - const MEM_POOL_SIZE = 5000; const GET_BLOCKS_COUNT = 500; // Assume that we get 500 back, but if not, at least request every 10 seconds @@ -162,6 +157,8 @@ export class Node implements INode { public readonly getNewVerificationContext: () => TransactionVerificationContext; // tslint:disable-next-line readonly-keyword private mutableMemPool: { [hash: string]: Transaction }; + // tslint:disable-next-line: readonly-keyword + private readonly mutableSentCommands: { [k: number]: boolean } = {}; private readonly transactionVerificationContext: TransactionVerificationContext; private readonly network: Network; private readonly options: Options; @@ -498,6 +495,7 @@ export class Node implements INode { private sendMessage(peer: Peer | ConnectedPeer, message: Message): void { peer.write(message.serializeWire()); + this.mutableSentCommands[message.value.command] = true; } private readonly negotiate = async (peer: Peer): Promise> => { this.sendMessage( @@ -847,6 +845,11 @@ export class Node implements INode { } private onAddrMessageReceived(addr: AddrPayload): void { + if (!this.mutableSentCommands[Command.GetAddr]) { + return; + } + this.mutableSentCommands[Command.GetAddr] = false; + addr.addressList .filter((address) => !LOCAL_HOST_ADDRESSES.has(address.address)) .filter((address) => address.port > 0) diff --git a/packages/neo-one-node-rpc-handler/src/createHandler.ts b/packages/neo-one-node-rpc-handler/src/createHandler.ts index 35324bebd5..f30b0d13e8 100644 --- a/packages/neo-one-node-rpc-handler/src/createHandler.ts +++ b/packages/neo-one-node-rpc-handler/src/createHandler.ts @@ -9,7 +9,6 @@ import { toVMStateJSON, TransactionJSON, TransactionReceiptJSON, - utils as commonUtils, VerboseTransactionJSON, VerifyResultModel, } from '@neo-one/client-common'; @@ -23,7 +22,6 @@ import { Nep5Transfer, Nep5TransferKey, Node, - Signer, Signers, StackItem, stackItemToJSON, @@ -125,6 +123,7 @@ const RPC_METHODS: { readonly [key: string]: string } = { // NEO•ONE getfeeperbyte: 'getfeeperbyte', + getexecfeefactor: 'getexecfeefactor', getverificationcost: 'getverificationcost', relaytransaction: 'relaytransaction', getallstorage: 'getallstorage', @@ -306,6 +305,7 @@ export const createHandler = ({ try { const stack = stackIn.map((item: StackItem) => stackItemToJSON(item, undefined)); + return { script: script.toString('hex'), state: toVMStateJSON(state), @@ -481,7 +481,7 @@ export const createHandler = ({ }, [RPC_METHODS.getvalidators]: async () => { const [validators, candidates] = await Promise.all([ - native.NEO.getValidators({ storages: blockchain.storages }), + native.NEO.computeNextBlockValidators({ storages: blockchain.storages }), native.NEO.getCandidates({ storages: blockchain.storages }), ]); @@ -886,6 +886,7 @@ export const createHandler = ({ return feePerByte.toString(); }, + [RPC_METHODS.getexecfeefactor]: async () => native.Policy.getExecFeeFactor({ storages: blockchain.storages }), [RPC_METHODS.getverificationcost]: async (args) => { const hash = JSONHelper.readUInt160(args[0]); const transaction = Transaction.deserializeWire({ diff --git a/packages/neo-one-node-vm/lib/Dispatcher.Engine.cs b/packages/neo-one-node-vm/lib/Dispatcher.Engine.cs index cae8b20e56..682f00b790 100644 --- a/packages/neo-one-node-vm/lib/Dispatcher.Engine.cs +++ b/packages/neo-one-node-vm/lib/Dispatcher.Engine.cs @@ -6,6 +6,7 @@ using Neo.Network.P2P.Payloads; using Neo.Persistence; using Neo.SmartContract; +using Neo.SmartContract.Native; using Neo.VM; using Neo.VM.Types; @@ -66,6 +67,7 @@ private enum EngineMethod create, execute, loadscript, + loadcontract, setinstructionpointer, getvmstate, getresultstack, @@ -111,6 +113,14 @@ private dynamic dispatchEngineMethod(EngineMethod method, dynamic args) return this._loadScript(script, flags, scriptHash, initialPosition); + case EngineMethod.loadcontract: + UInt160 contractHash = new UInt160((byte[])args.hash); + string contractMethod = (string)args.method; + CallFlags contractFlags = (CallFlags)((byte)args.flags); + bool packParameters = (bool)args.packParameters; + + return this._loadContract(contractHash, contractMethod, contractFlags, packParameters); + case EngineMethod.getvmstate: return this._getVMState(); @@ -169,6 +179,17 @@ private bool _loadScript(Script script, CallFlags flags, UInt160 hash = null, in return true; } + private bool _loadContract(UInt160 hash, string method, CallFlags flags, bool packParameters) + { + this.isEngineInitialized(); + ContractState cs = NativeContract.Management.GetContract(this.snapshot, hash); + if (cs is null) return false; + + this.engine.LoadContract(cs, method, flags, packParameters); + + return true; + } + private VMState _getVMState() { return this.engine != null ? this.engine.State : VMState.BREAK; diff --git a/packages/neo-one-node-vm/lib/Dispatcher.cs b/packages/neo-one-node-vm/lib/Dispatcher.cs index 2e68662c36..7c327baa8e 100644 --- a/packages/neo-one-node-vm/lib/Dispatcher.cs +++ b/packages/neo-one-node-vm/lib/Dispatcher.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using Neo.Persistence; using Microsoft.Extensions.Configuration; +using Neo.SmartContract.Native; namespace NEOONE { @@ -124,7 +125,7 @@ private bool _dispose() private dynamic _test() { - return sizeof(uint); + return NativeContract.NEO.Name; } private NEOONE.ReturnHelpers.ProtocolSettingsReturn _getConfig() diff --git a/packages/neo-one-node-vm/src/ApplicationEngine.ts b/packages/neo-one-node-vm/src/ApplicationEngine.ts index 532079db48..839e6aff19 100644 --- a/packages/neo-one-node-vm/src/ApplicationEngine.ts +++ b/packages/neo-one-node-vm/src/ApplicationEngine.ts @@ -5,6 +5,7 @@ import { serializeScriptContainer, SnapshotName, LoadScriptOptions, + LoadContractOptions, } from '@neo-one/node-core'; import { BN } from 'bn.js'; import _ from 'lodash'; @@ -114,6 +115,18 @@ export class ApplicationEngine { }); } + public loadContract({ hash, method, flags, packParameters = false }: LoadContractOptions) { + return this.dispatch({ + method: 'loadcontract', + args: { + hash, + method, + flags, + packParameters, + }, + }); + } + public checkScript() { return this.dispatch({ method: 'checkscript', diff --git a/packages/neo-one-node-vm/src/Methods/EngineMethods.ts b/packages/neo-one-node-vm/src/Methods/EngineMethods.ts index af2edfc2f9..f75a4aadbc 100644 --- a/packages/neo-one-node-vm/src/Methods/EngineMethods.ts +++ b/packages/neo-one-node-vm/src/Methods/EngineMethods.ts @@ -1,5 +1,5 @@ import { TriggerType, VMState, UInt160Hex } from '@neo-one/client-common'; -import { CallFlags, SerializedScriptContainer, SnapshotName, LoadScriptOptions } from '@neo-one/node-core'; +import { CallFlags, SerializedScriptContainer, SnapshotName, LoadContractOptions } from '@neo-one/node-core'; import { StackItemReturn, LogReturn } from '../converters'; import { DefaultMethods, DispatchMethod } from '../types'; @@ -30,4 +30,5 @@ export interface EngineMethods extends DefaultMethods { // methods readonly execute: DispatchMethod; readonly loadscript: DispatchMethod; + readonly loadcontract: DispatchMethod; } From 2a10d72cfecf86bd27744c56de9ad86cbfa6b5f5 Mon Sep 17 00:00:00 2001 From: Daniel Byrne Date: Tue, 12 Jan 2021 14:19:00 -0800 Subject: [PATCH 3/7] feat(misc): final changes to bring us in line with preview4 --- .../src/ScriptBuilder.ts | 8 +- .../src/__data__/models.ts | 5 +- .../src/__data__/configs/consensus.ts | 2 +- .../neo-one-node-blockchain/src/Blockchain.ts | 4 + .../src/StorageCache.ts | 6 +- .../neo-one-node-consensus/src/Consensus.ts | 2 - .../consensus/handleConsensusPayload.test.ts | 39 +---- .../src/context/common.ts | 119 ++++++++------ packages/neo-one-node-core/src/BlockBase.ts | 35 ++--- packages/neo-one-node-core/src/Blockchain.ts | 1 + .../neo-one-node-core/src/ContractState.ts | 2 +- packages/neo-one-node-core/src/Verifiable.ts | 13 +- .../src/consensus/ConsensusContext.ts | 54 +++---- packages/neo-one-node-core/src/errors.ts | 11 +- .../manifest/ContractPermissionDescriptor.ts | 1 - .../src/payload/ConsensusPayload.ts | 10 +- .../src/payload/UnsignedConsensusPayload.ts | 17 +- packages/neo-one-node-core/src/utils/utils.ts | 3 +- packages/neo-one-node-core/src/vm.ts | 10 +- .../src/DesignationContract.ts | 11 +- .../neo-one-node-neo-settings/src/common.ts | 146 +----------------- .../src/createHandler.ts | 11 +- .../src/__tests__/rocksDBStorage.test.ts | 4 +- .../neo-one-node-storage-levelup/src/read.ts | 83 +++------- .../neo-one-node-vm/lib/Dispatcher.csproj | 6 +- .../neo-one-node-vm/src/ApplicationEngine.ts | 8 +- packages/neo-one-node-vm/src/utils.ts | 2 + packages/neo-one-node/src/__data__/data.ts | 2 + .../src/__tests__/blockchain.test.ts | 29 +--- .../src/__tests__/consensus.test.ts | 20 --- .../src/__tests__/createNode.test.ts | 10 +- 31 files changed, 236 insertions(+), 438 deletions(-) diff --git a/packages/neo-one-client-common/src/ScriptBuilder.ts b/packages/neo-one-client-common/src/ScriptBuilder.ts index 8c197bd497..faf8958fec 100644 --- a/packages/neo-one-client-common/src/ScriptBuilder.ts +++ b/packages/neo-one-client-common/src/ScriptBuilder.ts @@ -11,7 +11,7 @@ export class ScriptBuilder extends BaseScriptBuilder { super(); this.pushParamCallbacks = { - undefined: () => this.emitPush(Buffer.alloc(0, 0)), + undefined: () => this.emitOp('PUSHNULL'), array: (param) => this.emitPushArray(param), map: (param) => this.emitPushMap(param), uInt160: (param) => this.emitPushUInt160(common.asUInt160(param)), @@ -49,10 +49,14 @@ export class ScriptBuilder extends BaseScriptBuilder { } public emitPushArray(params: readonly ScriptBuilderParam[]): this { + if (params.length === 0) { + return this.emitOp('NEWARRAY0'); + } + this.emitPushParams(...params); this.emitPushParam(params.length); - return params.length !== 0 ? this.emitOp('PACK') : this.emitOp('NEWARRAY'); + return this.emitOp('PACK'); } // tslint:disable-next-line readonly-array diff --git a/packages/neo-one-client-full-common/src/__data__/models.ts b/packages/neo-one-client-full-common/src/__data__/models.ts index dc049cc054..8fffd94f32 100644 --- a/packages/neo-one-client-full-common/src/__data__/models.ts +++ b/packages/neo-one-client-full-common/src/__data__/models.ts @@ -1,4 +1,4 @@ -import { common, ContractParameterTypeModel, ECPoint, SignatureString, UInt160 } from '@neo-one/client-common'; +import { common, ContractParameterTypeModel, ECPoint, UInt160 } from '@neo-one/client-common'; import { constants } from '@neo-one/utils'; import { ContractABIModel, @@ -72,7 +72,7 @@ export const contractMethodDescriptorModel = ( returnType: ContractParameterTypeModel = ContractParameterTypeModel.Void, name = 'function', offset = 0, -) => new ContractMethodDescriptorModel({ name, parameters, returnType, offset }); +) => new ContractMethodDescriptorModel({ name, parameters, returnType, offset, safe: true }); export const contractEventDescriptorModel = ( parameters: readonly ContractParameterDefinitionModel[] = [contractParamDefinitionModel.boolean], @@ -117,6 +117,7 @@ export const contractManifestModel = ( supportedStandards: readonly string[] = [], ) => new ContractManifestModel({ groups, supportedStandards, abi, permissions, trusts }); +// TODO: fixup export const contractModel = ( id = 1, script: Buffer = Buffer.alloc(25), diff --git a/packages/neo-one-node-bin/src/__data__/configs/consensus.ts b/packages/neo-one-node-bin/src/__data__/configs/consensus.ts index 1a694f2ef6..dfba130d35 100644 --- a/packages/neo-one-node-bin/src/__data__/configs/consensus.ts +++ b/packages/neo-one-node-bin/src/__data__/configs/consensus.ts @@ -1,7 +1,7 @@ import { createMain, serializeSettings } from '@neo-one/node-neo-settings'; import { getTestKeys } from '../getTestKeys'; -const { standbyValidator, address, privateKeyString } = getTestKeys(); +const { standbyValidator, privateKeyString } = getTestKeys(); export const consensus = (rpcPort: number, path: string) => ({ path, diff --git a/packages/neo-one-node-blockchain/src/Blockchain.ts b/packages/neo-one-node-blockchain/src/Blockchain.ts index 6f429f100a..9bc80a6a70 100644 --- a/packages/neo-one-node-blockchain/src/Blockchain.ts +++ b/packages/neo-one-node-blockchain/src/Blockchain.ts @@ -449,6 +449,10 @@ export class Blockchain { return this.native.Policy.getFeePerByte(this.storage); } + public shouldRefreshCommittee(offset = 0): boolean { + return (this.currentBlockIndex + offset) % this.settings.committeeMembersCount === 0; + } + public async persistBlock({ block, verify = false, diff --git a/packages/neo-one-node-blockchain/src/StorageCache.ts b/packages/neo-one-node-blockchain/src/StorageCache.ts index 5bbb482069..893cc8e818 100644 --- a/packages/neo-one-node-blockchain/src/StorageCache.ts +++ b/packages/neo-one-node-blockchain/src/StorageCache.ts @@ -1,4 +1,4 @@ -import { AddChange, Change, ChangeSet, DeleteChange, ReadMetadataStorage, ReadStorage } from '@neo-one/node-core'; +import { AddChange, Change, ChangeSet, DeleteChange, ReadStorage } from '@neo-one/node-core'; interface DeleteMetadataTrackedChanged { readonly type: 'delete'; @@ -16,10 +16,6 @@ interface AddTrackedChange extends AddMetadataTrackedChange { readonly key: Key; } -type TrackedMetadataChange = Value extends undefined - ? DeleteMetadataTrackedChanged - : AddMetadataTrackedChange; - type TrackedChange = DeleteTrackedChange | AddTrackedChange; const isDeleteTrackedChange = (value: TrackedChange): value is DeleteTrackedChange => diff --git a/packages/neo-one-node-consensus/src/Consensus.ts b/packages/neo-one-node-consensus/src/Consensus.ts index 894cb88321..2b73bba8b8 100644 --- a/packages/neo-one-node-consensus/src/Consensus.ts +++ b/packages/neo-one-node-consensus/src/Consensus.ts @@ -27,8 +27,6 @@ export interface InternalOptions { readonly privateNet: boolean; } -const MS_IN_SECOND = 1000; - export class Consensus { private mutableQueue: ConsensusQueue; private mutableTimer: number | undefined; diff --git a/packages/neo-one-node-consensus/src/__tests__/consensus/handleConsensusPayload.test.ts b/packages/neo-one-node-consensus/src/__tests__/consensus/handleConsensusPayload.test.ts index 815c289ff1..64fbfc58b5 100644 --- a/packages/neo-one-node-consensus/src/__tests__/consensus/handleConsensusPayload.test.ts +++ b/packages/neo-one-node-consensus/src/__tests__/consensus/handleConsensusPayload.test.ts @@ -1,12 +1,11 @@ // wallaby.skip -import { common, crypto, Op, PrivateKey, ScriptBuilder, UInt256Hex, WitnessScopeModel } from '@neo-one/client-common'; +import { common, crypto, Op, ScriptBuilder, UInt256Hex, WitnessScopeModel } from '@neo-one/client-common'; import { Block, ChangeViewConsensusMessage, ChangeViewReason, ConsensusContext, ConsensusData, - Contract, Signer, Transaction, TransactionVerificationContext, @@ -45,6 +44,7 @@ describe('handleConsensusPayload', () => { knownHashes = new Set(); }); + // TODO: fixup test('updates the expected view on new view number', async () => { const payload = await makeSignedPayload({ node, @@ -77,17 +77,13 @@ describe('handleConsensusPayload', () => { timerContext, }); - - console.log(result); }); + // TODO: fixup test.only('settings help', () => { const privateKeyString = 'e35fa5d1652c4c65e296c86e63a3da6939bc471b741845be636e2daa320dc770'; const privateKey = common.stringToPrivateKey(privateKeyString); const publicKey = crypto.privateKeyToPublicKey(privateKey); - const publicKeyString = common.ecPointToHex(publicKey); - - // console.log({ privateKey: privateKeyString, publicKey: publicKeyString }); const standbyValidators = [publicKey]; @@ -98,27 +94,6 @@ describe('handleConsensusPayload', () => { verification: Buffer.from([Op.PUSH1]), }); - const scriptBuilder = new ScriptBuilder(); - scriptBuilder.emitSysCall('Neo.Native.Deploy'); - const script = scriptBuilder.build(); - - const deployTransaction = new Transaction({ - version: 0, - script, - systemFee: new BN(0), - networkFee: new BN(0), - signers: [ - new Signer({ - account: crypto.hash160(Buffer.from([Op.PUSH1])), - scopes: WitnessScopeModel.None, - }), - ], - attributes: [], - witnesses: [deployWitness], - validUntilBlock: 0, - messageMagic: 7630401, - }); - const consensusData = new ConsensusData({ primaryIndex: 0, nonce: new BN(2083236893), @@ -131,14 +106,8 @@ describe('handleConsensusPayload', () => { nextConsensus: consensusAddress, witness: deployWitness, consensusData, - transactions: [deployTransaction], + transactions: [], messageMagic: 7630401, }); - - console.log(deployTransaction.hash); - console.log(consensusData); - - const serializedBlock = genesisBlock.serializeWire(); - console.log(serializedBlock.toString('hex')); }); }); diff --git a/packages/neo-one-node-consensus/src/context/common.ts b/packages/neo-one-node-consensus/src/context/common.ts index 195722e46c..72727e6015 100644 --- a/packages/neo-one-node-consensus/src/context/common.ts +++ b/packages/neo-one-node-consensus/src/context/common.ts @@ -197,6 +197,21 @@ export const ensureMaxBlockLimitation = async ( }; }; +const validatorsChanged = (blockchain: Blockchain) => { + if (blockchain.currentBlockIndex === 0) { + return false; + } + + const currentBlock = blockchain.currentBlock; + const prevBlock = blockchain.previousBlock; + + if (prevBlock === undefined) { + throw new Error('expected previous block'); + } + + return !currentBlock.nextConsensus.equals(prevBlock.nextConsensus); +}; + export const reset = async ({ blockchain, privateKey, @@ -217,7 +232,7 @@ export const reset = async ({ const initialBlockOptions = { previousHash: blockchain.currentBlock.hash, index: blockchain.currentBlockIndex + 1, - nextConsensus: crypto.getConsensusAddress(validators), + nextConsensus: crypto.getConsensusAddress(blockchain.shouldRefreshCommittee(1) ? validators : nextValidators), merkleRoot: undefined, messageMagic: blockchain.settings.messageMagic, }; @@ -239,9 +254,24 @@ export const reset = async ({ const changeViewPayloads = _.range(nextValidators.length).map(() => undefined); const lastChangeViewPayloads = _.range(nextValidators.length).map(() => undefined); const commitPayloads = _.range(nextValidators.length).map(() => undefined); - let lastSeenMessage = context.lastSeenMessage; - if (context.lastSeenMessage.length === 0) { - lastSeenMessage = _.range(nextValidators.length).map(() => -1); + const prevLastSeenMessage = context.lastSeenMessage; + let lastSeenMessage = prevLastSeenMessage; + if (validatorsChanged(blockchain) || Object.values(context.lastSeenMessage).length === 0) { + lastSeenMessage = nextValidators.reduce<{ readonly [k: string]: number | undefined }>((acc, validator) => { + const validatorHex = common.ecPointToHex(validator); + const prevIndex = prevLastSeenMessage[validatorHex]; + if (prevIndex !== undefined) { + return { + ...acc, + validatorHex: prevIndex, + }; + } + + return { + ...acc, + validatorHex: blockchain.currentBlockIndex, + }; + }, {}); } const publicKey = crypto.privateKeyToPublicKey(privateKey); @@ -260,55 +290,52 @@ export const reset = async ({ }), }; } - { - const mutableLastChangeViewPayloads = [...context.lastChangeViewPayloads]; - _.range(mutableLastChangeViewPayloads.length).forEach((i) => { - // tslint:disable-next-line: prefer-conditional-expression - if ( - (context.changeViewPayloads[i]?.getDeserializedMessage().newViewNumber ?? -1) >= - viewNumber - ) { - mutableLastChangeViewPayloads[i] = context.changeViewPayloads[i]; - } else { - mutableLastChangeViewPayloads[i] = undefined; - } - }); - - const primaryIndex = getPrimaryIndex({ context, viewNumber }); - const newBlockOptions = { - consensusData: { - primaryIndex, - }, - merkleRoot: undefined, - timestamp: new BN(0), - transactions: undefined, - }; + const mutableLastChangeViewPayloads = [...context.lastChangeViewPayloads]; + _.range(mutableLastChangeViewPayloads.length).forEach((i) => { + // tslint:disable-next-line: prefer-conditional-expression + if ( + (context.changeViewPayloads[i]?.getDeserializedMessage().newViewNumber ?? -1) >= + viewNumber + ) { + mutableLastChangeViewPayloads[i] = context.changeViewPayloads[i]; + } else { + mutableLastChangeViewPayloads[i] = undefined; + } + }); - const preparationPayloads = _.range(context.validators.length).map(() => undefined); + const primaryIndex = getPrimaryIndex({ context, viewNumber }); + const newBlockOptions = { + consensusData: { + primaryIndex, + }, + merkleRoot: undefined, + timestamp: new BN(0), + transactions: undefined, + }; - const mutableLastSeenMessage = [...context.lastSeenMessage]; - if (context.myIndex >= 0) { - mutableLastSeenMessage[context.myIndex] = utils.nullthrows(context.blockBuilder?.index); - } + const preparationPayloads = _.range(context.validators.length).map(() => undefined); - return { - context: context.clone({ - viewNumber, - lastChangeViewPayloads: mutableLastChangeViewPayloads, - blockOptions: newBlockOptions, - transactionHashes: undefined, - preparationPayloads, - lastSeenMessage: mutableLastSeenMessage, - }), - }; + const mutableLastSeenMessage = { ...context.lastSeenMessage }; + if (context.myIndex >= 0) { + mutableLastSeenMessage[context.myIndex] = utils.nullthrows(context.blockBuilder?.index); } + + return { + context: context.clone({ + viewNumber, + lastChangeViewPayloads: mutableLastChangeViewPayloads, + blockOptions: newBlockOptions, + transactionHashes: undefined, + preparationPayloads, + lastSeenMessage: mutableLastSeenMessage, + }), + }; }; -// TODO: not convinced we need to reload this that often -export const saveContext = async (context: ConsensusContext) => {}; +export const saveContext = async (_context: ConsensusContext) => { + throw new Error('not implemented'); +}; -// TODO: pickup here, everything SHOULD be set up correctly, now we just need to -// sort out how it all goes together and then starts export const getInitialContext = ({ blockchain, publicKey, diff --git a/packages/neo-one-node-core/src/BlockBase.ts b/packages/neo-one-node-core/src/BlockBase.ts index 94a1ab7f97..96ce026760 100644 --- a/packages/neo-one-node-core/src/BlockBase.ts +++ b/packages/neo-one-node-core/src/BlockBase.ts @@ -13,7 +13,7 @@ import { } from '@neo-one/client-common'; import { BN } from 'bn.js'; import { Equals, EquatableKey } from './Equatable'; -import { UnsignedBlockError } from './errors'; +import { InvalidPreviousHeaderError, UnsignedBlockError } from './errors'; import { createSerializeWire, DeserializeWireBaseOptions, @@ -47,14 +47,18 @@ export const getBlockScriptHashesForVerifying = async ( storage: BlockchainStorage, ) => { if (block.previousHash === common.ZERO_UINT256) { - return [block.witness?.scriptHash]; + const witnessHash = block.witness?.scriptHash; + if (witnessHash === undefined) { + throw new InvalidFormatError('Always expect a witness on the genesis block'); + } + + return [witnessHash]; } const prevBlock = await storage.blocks.tryGet({ hashOrIndex: block.previousHash }); const prevHeader = prevBlock?.header; if (prevHeader === undefined) { - // TODO: implement this as a makeError InvalidStorageHeaderFetch - throw new Error(`previous header hash ${block.previousHash} did not return a valid Header from storage`); + throw new InvalidPreviousHeaderError(common.uInt256ToHex(block.previousHash)); } return [prevHeader.nextConsensus]; @@ -113,20 +117,7 @@ export abstract class BlockBase implements EquatableKey, SerializableContainer, public readonly nextConsensus: UInt160; public readonly messageMagic: number; public readonly getScriptHashesForVerifying = utils.lazyAsync( - async (context: { readonly storage: BlockchainStorage }) => { - if (this.previousHash === common.ZERO_UINT256) { - return [this.witness.scriptHash]; - } - - const prevBlock = await context.storage.blocks.tryGet({ hashOrIndex: this.previousHash }); - const prevHeader = prevBlock?.header; - if (prevHeader === undefined) { - // TODO: implement this as a makeError InvalidStorageHeaderFetch - throw new Error(`previous header hash ${this.previousHash} did not return a valid Header from storage`); - } - - return [prevHeader.nextConsensus]; - }, + async (context: { readonly storage: BlockchainStorage }) => getBlockScriptHashesForVerifying(this, context.storage), ); // tslint:disable-next-line no-any public readonly equals: Equals = utils.equals(this.constructor as any, this, (other: any) => @@ -261,7 +252,13 @@ export abstract class BlockBase implements EquatableKey, SerializableContainer, return false; } - return verifyWitnesses(vm, this, storage, native, utils.ONE); + return verifyWitnesses({ + vm, + verifiable: this, + storage, + native, + gas: utils.ONE, + }); } protected readonly sizeExclusive: () => number = () => 0; diff --git a/packages/neo-one-node-core/src/Blockchain.ts b/packages/neo-one-node-core/src/Blockchain.ts index cc3ff5fefb..38e8f5e4f4 100644 --- a/packages/neo-one-node-core/src/Blockchain.ts +++ b/packages/neo-one-node-core/src/Blockchain.ts @@ -53,6 +53,7 @@ export interface Blockchain extends BlockchainStorage { readonly getMaxBlockSystemFee: () => Promise; readonly getMaxTransactionsPerBlock: () => Promise; readonly getFeePerByte: () => Promise; + readonly shouldRefreshCommittee: (offset?: number) => boolean; readonly invokeScript: (script: Buffer, signers?: Signers) => CallReceipt; readonly testTransaction: (transaction: Transaction) => CallReceipt; diff --git a/packages/neo-one-node-core/src/ContractState.ts b/packages/neo-one-node-core/src/ContractState.ts index 00b4b868c8..4b2b1e82f9 100644 --- a/packages/neo-one-node-core/src/ContractState.ts +++ b/packages/neo-one-node-core/src/ContractState.ts @@ -1,8 +1,8 @@ import { common, ContractJSON, IOHelper, JSONHelper, UInt160 } from '@neo-one/client-common'; import { ContractStateModel } from '@neo-one/client-full-common'; import { ContractManifest } from './manifest'; +import { assertArrayStackItem, StackItem } from './StackItems'; import { utils } from './utils'; -import { StackItem, assertArrayStackItem } from './StackItems'; export interface ContractStateAdd { readonly id: number; diff --git a/packages/neo-one-node-core/src/Verifiable.ts b/packages/neo-one-node-core/src/Verifiable.ts index a4e49a50ee..c9a587ddee 100644 --- a/packages/neo-one-node-core/src/Verifiable.ts +++ b/packages/neo-one-node-core/src/Verifiable.ts @@ -7,11 +7,16 @@ import { SnapshotName, VM } from './vm'; import { Witness } from './Witness'; export const maxVerificationGas = common.fixed8FromDecimal('0.5'); + +export interface GetScriptHashesContext { + readonly storage: BlockchainStorage; + readonly native: NativeContainer; +} + export interface Verifiable { - readonly getScriptHashesForVerifying: (context: { - readonly storage: BlockchainStorage; - readonly native: NativeContainer; - }) => Promise | readonly UInt160[]; + readonly getScriptHashesForVerifying: ( + context: GetScriptHashesContext, + ) => Promise | readonly UInt160[]; readonly witnesses: readonly Witness[]; } diff --git a/packages/neo-one-node-core/src/consensus/ConsensusContext.ts b/packages/neo-one-node-core/src/consensus/ConsensusContext.ts index cc805e1aa8..ad60ea89b4 100644 --- a/packages/neo-one-node-core/src/consensus/ConsensusContext.ts +++ b/packages/neo-one-node-core/src/consensus/ConsensusContext.ts @@ -1,8 +1,4 @@ import { common, ECPoint, UInt256, UInt256Hex } from '@neo-one/client-common'; -import { BN } from 'bn.js'; -import _ from 'lodash'; -import { Block } from '../Block'; -import { ConsensusData } from '../ConsensusData'; import { ChangeViewConsensusMessage, ConsensusPayload } from '../payload'; import { DeserializeWireBaseOptions } from '../Serializable'; import { Transaction } from '../transaction'; @@ -23,7 +19,7 @@ export interface ConsensusContextAdd { readonly commitPayloads?: ReadonlyArray; readonly changeViewPayloads?: ReadonlyArray; readonly lastChangeViewPayloads?: ReadonlyArray; - readonly lastSeenMessage?: readonly number[]; + readonly lastSeenMessage?: { readonly [key: string]: number | undefined }; readonly transactions?: { readonly [hash: string]: Transaction | undefined }; readonly transactionHashes?: readonly UInt256[]; readonly witnessSize?: number; @@ -31,24 +27,8 @@ export interface ConsensusContextAdd { // tslint:disable-next-line no-any export class ConsensusContext { - public static deserializeWireBase(options: DeserializeWireBaseOptions) { - const { reader } = options; - const version = reader.readUInt32LE(); - const index = reader.readUInt32LE(); - const timestamp = reader.readUInt64LE(); - - const nextConsensusIn = reader.readUInt160(); - const nextConsensus = nextConsensusIn.equals(common.ZERO_UINT160) ? undefined : nextConsensusIn; - - const consensusData = ConsensusData.deserializeWireBase(options); - const viewNumber = reader.readInt8(); - const transactionHashes = reader.readArray(() => reader.readUInt256()); - const transactions = reader.readArray( - () => Transaction.deserializeWireBase(options), - Block.MaxTransactionsPerBlock, - ); - - // TODO: before we implement the rest of this see if reloading and saving is even necessary + public static deserializeWireBase(_options: DeserializeWireBaseOptions) { + throw new Error('not yet implemented'); } public readonly viewNumber: number; public readonly myIndex: number; @@ -59,7 +39,7 @@ export class ConsensusContext { public readonly commitPayloads: ReadonlyArray; public readonly changeViewPayloads: ReadonlyArray; public readonly lastChangeViewPayloads: ReadonlyArray; - public readonly lastSeenMessage: readonly number[]; + public readonly lastSeenMessage: { readonly [key: string]: number | undefined }; public readonly transactions: { readonly [hash: string]: Transaction | undefined }; public readonly transactionHashes?: readonly UInt256[]; public readonly transactionHashesSet: Set; @@ -77,7 +57,7 @@ export class ConsensusContext { commitPayloads = [], changeViewPayloads = [], lastChangeViewPayloads = [], - lastSeenMessage = [], + lastSeenMessage = {}, transactions = {}, transactionHashes, witnessSize = 0, @@ -124,7 +104,18 @@ export class ConsensusContext { } public get countFailed(): number { - return this.lastSeenMessage.reduce((acc, val) => acc + (val < (this.blockBuilder.index ?? 0) - 1 ? 1 : 0), 0); + if (Object.values(this.lastSeenMessage).length === 0) { + return 0; + } + + return this.validators.reduce((acc, validator) => { + const count = this.lastSeenMessage[common.ecPointToHex(validator)]; + if (count === undefined) { + return acc + 1; + } + + return acc + (count < (this.blockBuilder.index ?? 0) - 1 ? 1 : 0); + }, 0); } public get moreThanFNodesCommittedOrLost(): boolean { @@ -197,19 +188,12 @@ export class ConsensusContext { lastChangeViewPayloads: this.lastChangeViewPayloads, transactions: this.transactions, transactionHashes: this.transactionHashes, + lastSeenMessage: this.lastSeenMessage, ...rest, }); } public toJSON(): object { - return { - block: this.blockBuilder.toJSON(), - viewNumber: this.viewNumber, - myIndex: this.myIndex, - expectedView: [...this.expectedView], - validators: this.validators.map((validator) => common.ecPointToString(validator)), - blockReceivedTimeMS: this.blockReceivedTimeMS, - transactions: _.fromPairs(Object.entries(this.transactions).map(([hash, tx]) => [hash, tx?.serializeJSON()])), - }; + throw new Error('not implemented'); } } diff --git a/packages/neo-one-node-core/src/errors.ts b/packages/neo-one-node-core/src/errors.ts index a86fdb8107..41fd200a43 100644 --- a/packages/neo-one-node-core/src/errors.ts +++ b/packages/neo-one-node-core/src/errors.ts @@ -1,4 +1,4 @@ -import { OracleResponseCode } from '@neo-one/client-common'; +import { OracleResponseCode, UInt256Hex } from '@neo-one/client-common'; import { makeErrorWithCode } from '@neo-one/utils'; // tslint:disable-next-line export-name @@ -80,3 +80,12 @@ export const InvalidOracleResultError = makeErrorWithCode( (code: OracleResponseCode, resultLength: number) => `Expected result.length to be 0 with response code ${OracleResponseCode[code]}, found: ${resultLength}`, ); +export const InvalidValidatorsError = makeErrorWithCode( + 'INVALID_VALIDATORS_ERROR', + (length: number, index: number) => + `Validator index out of range when getting scriptHashes, found length ${length} but need index: ${index}.`, +); +export const InvalidPreviousHeaderError = makeErrorWithCode( + 'INVALID_PREVIOUS_HEADER_ERROR', + (hash: UInt256Hex) => `previous header hash ${hash} did not return a valid Header from storage`, +); diff --git a/packages/neo-one-node-core/src/manifest/ContractPermissionDescriptor.ts b/packages/neo-one-node-core/src/manifest/ContractPermissionDescriptor.ts index 3ae724009b..75adb708c9 100644 --- a/packages/neo-one-node-core/src/manifest/ContractPermissionDescriptor.ts +++ b/packages/neo-one-node-core/src/manifest/ContractPermissionDescriptor.ts @@ -3,7 +3,6 @@ import { ContractPermissionDescriptorModel } from '@neo-one/client-full-common'; export class ContractPermissionDescriptor extends ContractPermissionDescriptorModel { public static deserializeJSON(json: ContractPermissionDescriptorJSON): ContractPermissionDescriptor { - // TODO: Verify this is even close to being the same const jsonString = JSON.stringify(json); if (jsonString.length === 42) { return new ContractPermissionDescriptor({ hashOrGroup: JSONHelper.readUInt160(jsonString) }); diff --git a/packages/neo-one-node-core/src/payload/ConsensusPayload.ts b/packages/neo-one-node-core/src/payload/ConsensusPayload.ts index 2ed061ac3b..dd200a3f9c 100644 --- a/packages/neo-one-node-core/src/payload/ConsensusPayload.ts +++ b/packages/neo-one-node-core/src/payload/ConsensusPayload.ts @@ -32,7 +32,7 @@ export class ConsensusPayload extends UnsignedConsensusPayload implements Serial validators: readonly ECPoint[], messageMagic: number, ): ConsensusPayload { - const context = new ContractParametersContext(payload.getScriptHashesForVerifying(validators)); + const context = new ContractParametersContext(payload.getScriptHashesForVerifyingFromValidators(validators)); const hashData = getHashData(payload.serializeWire(), messageMagic); const publicKey = crypto.privateKeyToPublicKey(privateKey); const signatureContract = AccountContract.createSignatureContract(publicKey); @@ -116,6 +116,12 @@ export class ConsensusPayload extends UnsignedConsensusPayload implements Serial return false; } - return options.verifyWitnesses(options.vm, this, options.storage, options.native, common.fixed8FromDecimal('0.02')); + return options.verifyWitnesses({ + vm: options.vm, + verifiable: this, + storage: options.storage, + native: options.native, + gas: common.fixed8FromDecimal('0.02'), + }); } } diff --git a/packages/neo-one-node-core/src/payload/UnsignedConsensusPayload.ts b/packages/neo-one-node-core/src/payload/UnsignedConsensusPayload.ts index 656f11e693..ddc60b90bb 100644 --- a/packages/neo-one-node-core/src/payload/UnsignedConsensusPayload.ts +++ b/packages/neo-one-node-core/src/payload/UnsignedConsensusPayload.ts @@ -5,10 +5,13 @@ import { crypto, ECPoint, getHashData, + InvalidFormatError, UInt256, } from '@neo-one/client-common'; +import { InvalidValidatorsError } from '../errors'; import { DeserializeWireBaseOptions, DeserializeWireOptions, SerializableWire } from '../Serializable'; import { BinaryReader, utils } from '../utils'; +import { GetScriptHashesContext } from '../Verifiable'; import { ConsensusMessage, deserializeConsensusMessageWire } from './message/ConsensusMessage'; export interface UnsignedConsensusPayloadAdd { @@ -94,8 +97,7 @@ export class UnsignedConsensusPayload implements SerializableWire { public get consensusMessage() { if (this.consensusMessageInternal === undefined) { - // TODO: Implement an error here - throw new Error('Need a way to get consensusMessage'); + throw new InvalidFormatError('Expected to receive a ConsensusMessage but could not find one.'); } return this.consensusMessageInternal(); @@ -117,10 +119,15 @@ export class UnsignedConsensusPayload implements SerializableWire { return common.uInt256ToHex(this.hash); } - public getScriptHashesForVerifying(validators: readonly ECPoint[]) { + public async getScriptHashesForVerifying({ native, storage }: GetScriptHashesContext) { + const validators = await native.NEO.getNextBlockValidators(storage); + + return this.getScriptHashesForVerifyingFromValidators(validators); + } + + public getScriptHashesForVerifyingFromValidators(validators: readonly ECPoint[]) { if (validators.length <= this.validatorIndex) { - // TODO - throw new Error(); + throw new InvalidValidatorsError(validators.length, this.validatorIndex); } return [crypto.toScriptHash(crypto.createSignatureRedeemScript(validators[this.validatorIndex]))]; diff --git a/packages/neo-one-node-core/src/utils/utils.ts b/packages/neo-one-node-core/src/utils/utils.ts index 5324c96e7a..c174b23086 100644 --- a/packages/neo-one-node-core/src/utils/utils.ts +++ b/packages/neo-one-node-core/src/utils/utils.ts @@ -5,6 +5,7 @@ import { randomBytes } from 'crypto'; import _ from 'lodash'; import { StackItem } from '../StackItems'; import { StorageItem } from '../StorageItem'; +import { executionLimits } from '../vm'; import { BinaryReader } from './BinaryReader'; import { deserializeStackItem } from './deserializeStackItem'; @@ -205,7 +206,7 @@ const wildCardFromJSON = (json: WildcardContainerJSON, selector: (input: stri const getInteroperable = (item: StorageItem, fromStackItem: (item: StackItem) => T): T => { const buffer = item.value; const reader = new BinaryReader(buffer); - const deserializedStackItem = deserializeStackItem(reader, 16, 34); + const deserializedStackItem = deserializeStackItem(reader, executionLimits.maxStackSize, executionLimits.maxItemSize); return fromStackItem(deserializedStackItem); }; diff --git a/packages/neo-one-node-core/src/vm.ts b/packages/neo-one-node-core/src/vm.ts index 853f04d171..83b4fd0174 100644 --- a/packages/neo-one-node-core/src/vm.ts +++ b/packages/neo-one-node-core/src/vm.ts @@ -1,4 +1,4 @@ -import { Log, TriggerType, UInt160, UInt256, VMState } from '@neo-one/client-common'; +import { TriggerType, UInt160, UInt256, VMState } from '@neo-one/client-common'; import { BN } from 'bn.js'; import { Block } from './Block'; import { CallFlags } from './CallFlags'; @@ -7,6 +7,14 @@ import { SerializableContainer } from './Serializable'; import { StackItem } from './StackItems'; import { Transaction } from './transaction'; +export const executionLimits = { + maxShift: 256, + maxStackSize: 2 * 1024, + maxItemSize: 1024 * 1024, + maxInvocationStackSize: 1024, + maxTryNestingDepth: 16, +}; + export interface VMLog { readonly containerHash?: UInt256; readonly callingScriptHash: UInt160; diff --git a/packages/neo-one-node-native/src/DesignationContract.ts b/packages/neo-one-node-native/src/DesignationContract.ts index 7d4c9add5b..9381150802 100644 --- a/packages/neo-one-node-native/src/DesignationContract.ts +++ b/packages/neo-one-node-native/src/DesignationContract.ts @@ -1,13 +1,13 @@ -import { NativeContract } from './NativeContract'; +import { common, ECPoint } from '@neo-one/client-common'; import { - NativeContractStorageContext, - utils, - StackItem, assertArrayStackItem, DesignationRole as Role, + NativeContractStorageContext, + StackItem, + utils, } from '@neo-one/node-core'; import { map, toArray } from 'rxjs/operators'; -import { ECPoint, common } from '@neo-one/client-common'; +import { NativeContract } from './NativeContract'; export class DesignationContract extends NativeContract { public constructor() { @@ -30,7 +30,6 @@ export class DesignationContract extends NativeContract { index: number, ): Promise { if (height + 1 < index) { - // TODO: implement makeError throw new Error(`index: ${index} out of range for getDesignatedByRole.`); } diff --git a/packages/neo-one-node-neo-settings/src/common.ts b/packages/neo-one-node-neo-settings/src/common.ts index 8f2df9e0ef..e08ecdb87e 100644 --- a/packages/neo-one-node-neo-settings/src/common.ts +++ b/packages/neo-one-node-neo-settings/src/common.ts @@ -1,5 +1,5 @@ -import { common as clientCommon, crypto, Op, ScriptBuilder, UInt160, WitnessScopeModel } from '@neo-one/client-common'; -import { Block, ConsensusData, Signer, Transaction, Witness } from '@neo-one/node-core'; +import { common as clientCommon, Op, UInt160 } from '@neo-one/client-common'; +import { Block, ConsensusData, Witness } from '@neo-one/node-core'; import { BN } from 'bn.js'; export const GENERATION_AMOUNT: readonly number[] = [6, 5, 4, 3, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]; @@ -16,79 +16,11 @@ interface Options { readonly messageMagic: number; } -// const ONE_HUNDRED_MILLION = clientCommon.fixed8FromDecimal(100000000); - -// const getGoverningToken = () => { -// const scriptBuilder = new ScriptBuilder(); -// scriptBuilder.emitOp('PUSH1'); -// const admin = crypto.toScriptHash(scriptBuilder.build()); - -// return new RegisterTransaction({ -// asset: { -// type: AssetType.GoverningToken, -// name: '[{"lang":"zh-CN","name":"小蚁股"},{"lang":"en","name":"AntShare"}]', -// amount: ONE_HUNDRED_MILLION, -// precision: 0, -// owner: clientCommon.ECPOINT_INFINITY, -// admin, -// }, -// }); -// }; - -// const getUtilityToken = () => { -// const scriptBuilder = new ScriptBuilder(); -// scriptBuilder.emitOp('PUSH0'); -// const admin = crypto.toScriptHash(scriptBuilder.build()); - -// return new RegisterTransaction({ -// asset: { -// type: AssetType.UtilityToken, -// name: '[{"lang":"zh-CN","name":"小蚁币"},{"lang":"en","name":"AntCoin"}]', -// amount: ONE_HUNDRED_MILLION, -// precision: 8, -// owner: clientCommon.ECPOINT_INFINITY, -// admin, -// }, -// }); -// }; - -// interface GensisBlockOptions { -// readonly privateNet?: boolean; -// readonly governingToken: RegisterTransaction; -// readonly utilityToken: RegisterTransaction; -// readonly address: UInt160; -// readonly consensusAddress: UInt160; -// } - const getDeployWitness = () => new Witness({ invocation: Buffer.from([]), verification: Buffer.from([Op.PUSH1]), }); - -const getDeployNativeContracts = (messageMagic: number) => { - const scriptBuilder = new ScriptBuilder(); - scriptBuilder.emitSysCall('Neo.Native.Deploy'); - const script = scriptBuilder.build(); - - return new Transaction({ - version: 0, - script, - systemFee: new BN(0), - networkFee: new BN(0), - signers: [ - new Signer({ - account: crypto.hash160(Buffer.from([Op.PUSH1])), - scopes: WitnessScopeModel.None, - }), - ], - attributes: [], - witnesses: [getDeployWitness()], - validUntilBlock: 0, - messageMagic, - }); -}; - interface GetGenesisBlockOptions { readonly consensusAddress: UInt160; readonly messageMagic: number; @@ -122,77 +54,3 @@ export const common = ({ privateNet, consensusAddress, messageMagic }: Options) maxTransactionsPerBlock: MAX_TRANSACTION_PER_BLOCK, memoryPoolMaxTransactions: 50000, }); - -// const getGenesisBlock = ({ privateNet, governingToken, utilityToken, address, consensusAddress }: GensisBlockOptions) => -// new Block({ -// previousHash: clientCommon.ZERO_UINT256, -// timestamp: 1468595301, -// index: 0, -// consensusData: new BN(2083236893), -// nextConsensus: consensusAddress, -// script: new Witness({ -// invocation: Buffer.from([]), -// verification: Buffer.from([Op.PUSH1]), -// }), -// transactions: [ -// new MinerTransaction({ nonce: 2083236893 }), -// governingToken, -// utilityToken, -// new IssueTransaction({ -// version: 0, -// outputs: [ -// new Output({ -// asset: governingToken.hash, -// value: governingToken.asset.amount, -// address, -// }), -// ], -// scripts: [ -// new Witness({ -// invocation: Buffer.from([]), -// verification: Buffer.from([Op.PUSH1]), -// }), -// ], -// }), -// privateNet -// ? new IssueTransaction({ -// outputs: [ -// new Output({ -// asset: utilityToken.hash, -// value: ISSUE_AMOUNT_PRIVATE, -// address, -// }), -// ], - -// scripts: [ -// new Witness({ -// invocation: Buffer.from([]), -// verification: Buffer.from([Op.PUSH0]), -// }), -// ], -// }) -// : undefined, -// ].filter(utils.notNull), -// }); - -// export const common = ({ privateNet, address, consensusAddress }: Options) => { -// const utilityToken = getUtilityToken(); -// const governingToken = getGoverningToken(); - -// return { -// genesisBlock: getGenesisBlock({ -// privateNet, -// governingToken, -// utilityToken, -// address, -// consensusAddress, -// }), -// governingToken, -// utilityToken, -// decrementInterval: DECREMENT_INTERVAL, -// generationAmount: privateNet ? GENERATION_AMOUNT_PRIVATE : GENERATION_AMOUNT, -// secondsPerBlock: SECONDS_PER_BLOCK, -// maxTransactionsPerBlock: MAX_TRANSACTION_PER_BLOCK, -// memPoolSize: 50000, -// }; -// }; diff --git a/packages/neo-one-node-rpc-handler/src/createHandler.ts b/packages/neo-one-node-rpc-handler/src/createHandler.ts index f30b0d13e8..3c07c426cb 100644 --- a/packages/neo-one-node-rpc-handler/src/createHandler.ts +++ b/packages/neo-one-node-rpc-handler/src/createHandler.ts @@ -415,7 +415,7 @@ export const createHandler = ({ }, [RPC_METHODS.getcontractstate]: async (args) => { const hash = JSONHelper.readUInt160(args[0]); - const contract = await blockchain.contracts.tryGet(hash); + const contract = await native.Management.getContract({ storages: blockchain.storages }, hash); if (contract === undefined) { throw new JSONRPCError(-100, 'Unknown contract'); } @@ -463,7 +463,7 @@ export const createHandler = ({ }, [RPC_METHODS.getstorage]: async (args) => { const hash = JSONHelper.readUInt160(args[0]); - const state = await blockchain.contracts.tryGet(hash); + const state = await native.Management.getContract({ storages: blockchain.storages }, hash); if (state === undefined) { return undefined; } @@ -701,7 +701,10 @@ export const createHandler = ({ const storedBalances = await blockchain.nep5Balances.find$(scriptHash).pipe(toArray()).toPromise(); const validBalances = await Promise.all( storedBalances.map(async ({ key, value }) => { - const assetStillExists = await blockchain.contracts.tryGet(key.assetScriptHash); + const assetStillExists = await native.Management.getContract( + { storages: blockchain.storages }, + key.assetScriptHash, + ); if (!assetStillExists) { return undefined; } @@ -779,7 +782,7 @@ export const createHandler = ({ if (hash.equals(NEO) || hash.equals(GAS) || hash.equals(Policy)) { throw new Error("Can't get all storage for native contracts."); } - const contract = await blockchain.contracts.tryGet(hash); + const contract = await native.Management.getContract({ storages: blockchain.storages }, hash); if (contract === undefined) { return []; } diff --git a/packages/neo-one-node-storage-levelup/src/__tests__/rocksDBStorage.test.ts b/packages/neo-one-node-storage-levelup/src/__tests__/rocksDBStorage.test.ts index 0e4192a7f5..5bccba3b13 100644 --- a/packages/neo-one-node-storage-levelup/src/__tests__/rocksDBStorage.test.ts +++ b/packages/neo-one-node-storage-levelup/src/__tests__/rocksDBStorage.test.ts @@ -8,7 +8,7 @@ describe('levelUpStorage', () => { let storage: Storage; beforeEach(async () => { const rocks = new RocksDB('/Users/danielbyrne/Desktop/test-location'); - storage = levelUpStorage({ db: LevelUp(rocks), context: { messageMagic: 1953787457 } }); + storage = levelUpStorage({ db: LevelUp(rocks), context: { messageMagic: 1953787457, validatorsCount: 7 } }); }); test('deleted items are undefined', async () => { const hash = common.bufferToUInt160(Buffer.from('3775292229eccdf904f16fff8e83e7cffdc0f0ce', 'hex')); @@ -16,7 +16,6 @@ describe('levelUpStorage', () => { const value = Buffer.from('5f8d70', 'hex'); const firstGet = await storage.storages.tryGet(key); - console.log(firstGet); expect(firstGet).toEqual(undefined); const storageItem = new StorageItem({ @@ -31,7 +30,6 @@ describe('levelUpStorage', () => { await storage.commit([{ type: 'add', change: addChange, subType: 'add' }]); const secondGet = await storage.storages.tryGet(key); - console.log(secondGet); expect(JSON.stringify(secondGet)).toEqual(JSON.stringify(storageItem)); const deleteChange: DeleteChange = { diff --git a/packages/neo-one-node-storage-levelup/src/read.ts b/packages/neo-one-node-storage-levelup/src/read.ts index a99fe265bb..df5afd964a 100644 --- a/packages/neo-one-node-storage-levelup/src/read.ts +++ b/packages/neo-one-node-storage-levelup/src/read.ts @@ -35,32 +35,32 @@ export function createTryGet({ }; } -// TODO: we haven't implemented any `tryGetLatest` functions, should we reimplement for something? -// export function createTryGetLatest({ -// db, -// latestKey, -// deserializeResult, -// get, -// }: { -// readonly db: LevelUp; -// readonly latestKey: string; -// readonly deserializeResult: (latestResult: Buffer) => Key; -// readonly get: (key: Key) => Promise; -// }): () => Promise { -// return async (): Promise => { -// try { -// const result = await db.get(latestKey); -// const value = await get(deserializeResult(result as Buffer)); +// Keeping this around if we find a use for it +export function createTryGetLatest({ + db, + latestKey, + deserializeResult, + get, +}: { + readonly db: LevelUp; + readonly latestKey: string; + readonly deserializeResult: (latestResult: Buffer) => Key; + readonly get: (key: Key) => Promise; +}): () => Promise { + return async (): Promise => { + try { + const result = await db.get(latestKey); + const value = await get(deserializeResult(result as Buffer)); -// return value; -// } catch (error) { -// if (error.notFound || error.code === 'KEY_NOT_FOUND') { -// return undefined; -// } -// throw error; -// } -// }; -// } + return value; + } catch (error) { + if (error.notFound || error.code === 'KEY_NOT_FOUND') { + return undefined; + } + throw error; + } + }; +} export function createReadStorage({ db, @@ -209,39 +209,6 @@ export function createReadAllFindStorage({ }; } -// TODO: do we need to reimplement this for something? -// export function createReadGetAllStorage({ -// db, -// serializeKey, -// getMinKey, -// getMaxKey, -// deserializeValue, -// }: { -// readonly db: LevelUp; -// readonly serializeKey: SerializeKey; -// readonly getMinKey: (keys: Keys) => string; -// readonly getMaxKey: (keys: Keys) => string; -// readonly deserializeValue: (value: Buffer) => Value; -// }): ReadGetAllStorage { -// const readStorage = createReadStorage({ -// db, -// serializeKey, -// deserializeValue, -// }); - -// return { -// get: readStorage.get, -// tryGet: readStorage.tryGet, -// getAll$: (keys: Keys) => -// createAll$({ -// db, -// minKey: getMinKey(keys), -// maxKey: getMaxKey(keys), -// deserializeValue, -// }), -// }; -// } - export function createTryGetMetadata({ get, }: { diff --git a/packages/neo-one-node-vm/lib/Dispatcher.csproj b/packages/neo-one-node-vm/lib/Dispatcher.csproj index c93ca3843e..04a1502e7b 100644 --- a/packages/neo-one-node-vm/lib/Dispatcher.csproj +++ b/packages/neo-one-node-vm/lib/Dispatcher.csproj @@ -15,11 +15,7 @@ - - - - - + diff --git a/packages/neo-one-node-vm/src/ApplicationEngine.ts b/packages/neo-one-node-vm/src/ApplicationEngine.ts index 839e6aff19..44b400e9a4 100644 --- a/packages/neo-one-node-vm/src/ApplicationEngine.ts +++ b/packages/neo-one-node-vm/src/ApplicationEngine.ts @@ -1,15 +1,15 @@ -import { TriggerType, VMState, common } from '@neo-one/client-common'; +import { common, TriggerType, VMState } from '@neo-one/client-common'; import { CallFlags, + LoadContractOptions, + LoadScriptOptions, SerializableContainer, serializeScriptContainer, SnapshotName, - LoadScriptOptions, - LoadContractOptions, } from '@neo-one/node-core'; import { BN } from 'bn.js'; import _ from 'lodash'; -import { parseStackItems, convertLog } from './converters'; +import { convertLog, parseStackItems } from './converters'; import { EngineMethods } from './Methods'; import { DispatcherFunc } from './types'; diff --git a/packages/neo-one-node-vm/src/utils.ts b/packages/neo-one-node-vm/src/utils.ts index 3521cd36cf..87e0c268be 100644 --- a/packages/neo-one-node-vm/src/utils.ts +++ b/packages/neo-one-node-vm/src/utils.ts @@ -22,10 +22,12 @@ export const createCSharpDispatchInvoke = ( options: EdgeOptions, ): DispatcherFunc => { if (process.env.EDGE_APP_ROOT === undefined) { + // tslint:disable-next-line: no-object-mutation process.env.EDGE_APP_ROOT = CSHARP_APP_ROOT; } if (process.env.EDGE_USE_CORECLR === undefined) { + // tslint:disable-next-line: no-object-mutation process.env.EDGE_USE_CORECLR = '1'; } diff --git a/packages/neo-one-node/src/__data__/data.ts b/packages/neo-one-node/src/__data__/data.ts index 6ab55b78de..2a676f1ac4 100644 --- a/packages/neo-one-node/src/__data__/data.ts +++ b/packages/neo-one-node/src/__data__/data.ts @@ -40,6 +40,7 @@ const convertBlock = (json: BlockJSON, messageMagic: number) => (signer) => new Signer({ account: JSONHelper.readUInt160(signer.account), + // tslint:disable-next-line: no-any scopes: (signer.scopes as any) === 'FeeOnly' ? WitnessScopeModel.None : toWitnessScope(signer.scopes), }), ), @@ -55,6 +56,7 @@ const convertBlock = (json: BlockJSON, messageMagic: number) => messageMagic, }); +// tslint:disable no-any export-name export const getData = (messageMagic: number) => ({ genesisBlock: convertBlock(genesisJSON as any, messageMagic), secondBlock: convertBlock(secondBlockJSON as any, messageMagic), diff --git a/packages/neo-one-node/src/__tests__/blockchain.test.ts b/packages/neo-one-node/src/__tests__/blockchain.test.ts index 1600ba30a5..6e2f995042 100644 --- a/packages/neo-one-node/src/__tests__/blockchain.test.ts +++ b/packages/neo-one-node/src/__tests__/blockchain.test.ts @@ -1,36 +1,13 @@ -import { common, ScriptBuilder } from '@neo-one/client-common'; import { Blockchain } from '@neo-one/node-blockchain'; -import { ContractState, StorageItem } from '@neo-one/node-core'; import { NativeContainer } from '@neo-one/node-native'; import { test as createTest } from '@neo-one/node-neo-settings'; import { storage as levelupStorage } from '@neo-one/node-storage-levelup'; import { blockchainSettingsToProtocolSettings, Dispatcher } from '@neo-one/node-vm'; import LevelUp from 'levelup'; -import RocksDB from 'rocksdb'; +// tslint:disable-next-line: match-default-export-name import Memdown from 'memdown'; +import RocksDB from 'rocksdb'; import { getData } from '../__data__'; -import { BN } from 'bn.js'; - -const rawReadStreamPromise = async (db: any, options: { readonly gte: Buffer; readonly lte: Buffer }) => - new Promise((resolve, reject) => { - db.createReadStream(options) - .on('data', (data: any) => { - console.log(common.uInt160ToString(data.key.slice(1))); - console.log( - JSON.stringify( - ContractState.deserializeWire({ - context: { messageMagic: 1951352142, validatorsCount: 1 }, - buffer: data.value, - }).serializeJSON(), - undefined, - 2, - ), - ); - }) - .on('error', reject) - .on('close', resolve) - .on('end', resolve); - }); describe('Blockchain invocation / storage tests', () => { test('Can persist the first 3 blocks with disk storage', async () => { @@ -86,7 +63,7 @@ describe('VM memory store for testing', () => { }) .on('close', () => resolve(changesInternal)) .on('end', () => resolve(changesInternal)) - .on('error', (reason) => reject(reason)); + .on('error', reject); }); const onPersist = async () => { diff --git a/packages/neo-one-node/src/__tests__/consensus.test.ts b/packages/neo-one-node/src/__tests__/consensus.test.ts index 3b45b2a4b0..ed262552bd 100644 --- a/packages/neo-one-node/src/__tests__/consensus.test.ts +++ b/packages/neo-one-node/src/__tests__/consensus.test.ts @@ -1,10 +1,6 @@ import { common } from '@neo-one/client-common'; import { Block } from '@neo-one/node-core'; -import { storage as levelupStorage } from '@neo-one/node-storage-levelup'; -import { blockchainSettingsToProtocolSettings, Dispatcher } from '@neo-one/node-vm'; import fs from 'fs-extra'; -import LevelUp from 'levelup'; -import RocksDB from 'rocksdb'; import { FullNode } from '../FullNode'; const timeout = 30000000; @@ -71,20 +67,4 @@ describe('Consensus Testing', () => { await Promise.all([fullNode.start(), new Promise((resolve) => setTimeout(resolve, timeout))]); }); - - test('', async () => { - const db = LevelUp(RocksDB(config.path)); - - const storage = levelupStorage({ - db, - context: { messageMagic: config.blockchain.messageMagic }, - }); - - const dispatcher = new Dispatcher({ - levelDBPath: config.path, - protocolSettings: blockchainSettingsToProtocolSettings(config.blockchain), - }); - - console.log(JSON.stringify(dispatcher.getConfig(), undefined, 2)); - }); }); diff --git a/packages/neo-one-smart-contract-test/src/__tests__/createNode.test.ts b/packages/neo-one-smart-contract-test/src/__tests__/createNode.test.ts index 515e62d7a8..47c4453f40 100644 --- a/packages/neo-one-smart-contract-test/src/__tests__/createNode.test.ts +++ b/packages/neo-one-smart-contract-test/src/__tests__/createNode.test.ts @@ -1,14 +1,14 @@ /// -import { createNode } from '../createNode'; +import { common } from '@neo-one/client-common'; import { - NEOONEDataProvider, - NEOONEProvider, - LocalMemoryStore, LocalKeyStore, + LocalMemoryStore, LocalUserAccountProvider, + NEOONEDataProvider, + NEOONEProvider, } from '@neo-one/client-core'; -import { common } from '@neo-one/client-common'; import BigNumber from 'bignumber.js'; +import { createNode } from '../createNode'; const secondaryKeyString = '04c1784140445016cf0f8cc86dd10ad8764e1a89c563c500e21ac19a5d905ab3'; From 422eb99c97c786853e58fc0e1aae35c18769af75 Mon Sep 17 00:00:00 2001 From: Daniel Byrne Date: Thu, 14 Jan 2021 11:24:42 -0800 Subject: [PATCH 4/7] fix(misc): update nep5 naming to nep17 --- .../projects/exchange/codegen/Exchange/abi.ts | 4 +- .../exchange/codegen/Exchange/types.ts | 8 +-- .../exchange/neo-one/contracts/Exchange.ts | 16 ++--- .../src/__e2e__/cmd/buildExchange.test.ts | 18 +++--- .../neo-one-client-common/src/models/index.ts | 2 +- .../Nep17BalanceKeyModel.ts} | 6 +- .../Nep17BalanceModel.ts} | 6 +- .../Nep17TransferKeyModel.ts} | 6 +- .../Nep17TransferModel.ts} | 6 +- .../src/models/nep17/index.ts | 4 ++ .../src/models/nep5/index.ts | 4 -- .../neo-one-client-common/src/models/types.ts | 14 ++--- packages/neo-one-client-common/src/types.ts | 2 +- .../src/__data__/factory.ts | 4 +- .../__tests__/__snapshots__/nep5.test.ts.snap | 2 +- .../__tests__/{nep5.test.ts => nep17.test.ts} | 12 ++-- .../src/__tests__/provider/temp.test.ts | 4 +- packages/neo-one-client-core/src/index.ts | 4 +- .../src/{nep5.ts => nep17.ts} | 22 ++++--- .../src/provider/JSONRPCClient.ts | 14 ++--- .../src/provider/NEOONEDataProvider.ts | 2 +- .../src/__data__/factory.ts | 4 +- .../src/__tests__/args.test.ts | 8 +-- packages/neo-one-client-full/src/index.ts | 2 +- packages/neo-one-client/src/index.ts | 2 +- .../src/AddToken.tsx | 6 +- .../src/BalanceSelector.tsx | 4 +- .../src/WalletSelectorBase.tsx | 4 +- .../src/WalletTransfer.tsx | 4 +- .../neo-one-node-blockchain/src/Blockchain.ts | 44 +++++++------- ...ateOptions.ts => getNep17UpdateOptions.ts} | 60 +++++++++---------- .../src/{Nep5Balance.ts => Nep17Balance.ts} | 12 ++-- .../{Nep5BalanceKey.ts => Nep17BalanceKey.ts} | 12 ++-- .../src/{Nep5Transfer.ts => Nep17Transfer.ts} | 12 ++-- ...Nep5TransferKey.ts => Nep17TransferKey.ts} | 12 ++-- packages/neo-one-node-core/src/Storage.ts | 23 ++++--- packages/neo-one-node-core/src/index.ts | 8 +-- .../src/createHandler.ts | 24 ++++---- .../neo-one-node-storage-common/src/keys.ts | 46 +++++++------- .../src/__tests__/levelUpStorage.test.ts | 18 +++--- .../src/convertChange.ts | 16 ++--- .../src/levelUpStorage.ts | 40 ++++++------- .../src/__data__/index.ts | 2 +- .../src/__data__/{nep5.ts => nep17.ts} | 2 +- .../src/__tests__/abi/genABI.test.ts | 6 +- .../src/__tests__/genFiles.test.ts | 4 +- .../types/genSmartContractTypes.test.ts | 6 +- .../src/{NEP5Token.ts => NEP17Token.ts} | 6 +- .../neo-one-smart-contract-lib/src/index.ts | 2 +- .../neo-one-smart-contract-lib/tsconfig.json | 2 +- .../src/__data__/contracts/SimpleToken.ts | 4 +- .../src/__data__/contracts/TestICO.ts | 4 +- .../src/__data__/contracts/TestToken.ts | 4 +- .../4-contributing/1-codebase-overview.md | 2 +- 54 files changed, 285 insertions(+), 280 deletions(-) rename packages/neo-one-client-common/src/models/{nep5/Nep5BalanceKeyModel.ts => nep17/Nep17BalanceKeyModel.ts} (78%) rename packages/neo-one-client-common/src/models/{nep5/Nep5BalanceModel.ts => nep17/Nep17BalanceModel.ts} (78%) rename packages/neo-one-client-common/src/models/{nep5/Nep5TransferKeyModel.ts => nep17/Nep17TransferKeyModel.ts} (89%) rename packages/neo-one-client-common/src/models/{nep5/Nep5TransferModel.ts => nep17/Nep17TransferModel.ts} (88%) create mode 100644 packages/neo-one-client-common/src/models/nep17/index.ts delete mode 100644 packages/neo-one-client-common/src/models/nep5/index.ts rename packages/neo-one-client-core/src/__tests__/{nep5.test.ts => nep17.test.ts} (64%) rename packages/neo-one-client-core/src/{nep5.ts => nep17.ts} (86%) rename packages/neo-one-node-blockchain/src/{getNep5UpdateOptions.ts => getNep17UpdateOptions.ts} (70%) rename packages/neo-one-node-core/src/{Nep5Balance.ts => Nep17Balance.ts} (82%) rename packages/neo-one-node-core/src/{Nep5BalanceKey.ts => Nep17BalanceKey.ts} (78%) rename packages/neo-one-node-core/src/{Nep5Transfer.ts => Nep17Transfer.ts} (84%) rename packages/neo-one-node-core/src/{Nep5TransferKey.ts => Nep17TransferKey.ts} (83%) rename packages/neo-one-smart-contract-codegen/src/__data__/{nep5.ts => nep17.ts} (99%) rename packages/neo-one-smart-contract-lib/src/{NEP5Token.ts => NEP17Token.ts} (96%) diff --git a/packages/neo-one-cli/src/__data__/projects/exchange/codegen/Exchange/abi.ts b/packages/neo-one-cli/src/__data__/projects/exchange/codegen/Exchange/abi.ts index 03a0e1bd4a..821fb242b4 100644 --- a/packages/neo-one-cli/src/__data__/projects/exchange/codegen/Exchange/abi.ts +++ b/packages/neo-one-cli/src/__data__/projects/exchange/codegen/Exchange/abi.ts @@ -297,7 +297,7 @@ export const exchangeABI: ABI = { { claim: false, constant: false, - name: 'depositNEP5', + name: 'depositNEP17', parameters: [ { forwardedValue: false, @@ -330,7 +330,7 @@ export const exchangeABI: ABI = { { claim: false, constant: false, - name: 'withdrawNEP5', + name: 'withdrawNEP17', parameters: [ { forwardedValue: false, diff --git a/packages/neo-one-cli/src/__data__/projects/exchange/codegen/Exchange/types.ts b/packages/neo-one-cli/src/__data__/projects/exchange/codegen/Exchange/types.ts index 3739e8ced7..7c480b4295 100644 --- a/packages/neo-one-cli/src/__data__/projects/exchange/codegen/Exchange/types.ts +++ b/packages/neo-one-cli/src/__data__/projects/exchange/codegen/Exchange/types.ts @@ -86,7 +86,7 @@ export interface ExchangeSmartContract extends options?: TransactionOptions & GetOptions, ) => Promise & { readonly transaction: InvocationTransaction }>; }; - readonly depositNEP5: { + readonly depositNEP17: { (from: AddressString, assetID: AddressString, amount: BigNumber, options?: TransactionOptions): Promise< TransactionResult, InvocationTransaction> >; @@ -171,7 +171,7 @@ export interface ExchangeSmartContract extends options?: TransactionOptions & GetOptions, ) => Promise & { readonly transaction: InvocationTransaction }>; }; - readonly withdrawNEP5: { + readonly withdrawNEP17: { (from: AddressString, assetID: AddressString, amount: BigNumber, options?: TransactionOptions): Promise< TransactionResult, InvocationTransaction> >; @@ -198,7 +198,7 @@ export interface ExchangeMigrationSmartContract { owner?: AddressString | Promise, options?: TransactionOptions & GetOptions, ) => Promise & { readonly transaction: InvocationTransaction }>; - readonly depositNEP5: ( + readonly depositNEP17: ( from: AddressString | Promise, assetID: AddressString | Promise, amount: BigNumber | Promise, @@ -247,7 +247,7 @@ export interface ExchangeMigrationSmartContract { feeAddress: AddressString | Promise, options?: TransactionOptions & GetOptions, ) => Promise & { readonly transaction: InvocationTransaction }>; - readonly withdrawNEP5: ( + readonly withdrawNEP17: ( from: AddressString | Promise, assetID: AddressString | Promise, amount: BigNumber | Promise, diff --git a/packages/neo-one-cli/src/__data__/projects/exchange/neo-one/contracts/Exchange.ts b/packages/neo-one-cli/src/__data__/projects/exchange/neo-one/contracts/Exchange.ts index ec1b4c8e27..1969f7392c 100644 --- a/packages/neo-one-cli/src/__data__/projects/exchange/neo-one/contracts/Exchange.ts +++ b/packages/neo-one-cli/src/__data__/projects/exchange/neo-one/contracts/Exchange.ts @@ -40,7 +40,7 @@ const notifyFilled = createEventNotifier boolean; } @@ -81,22 +81,22 @@ export class Exchange extends SmartContract { return this.offers.get(offerHash); } - public depositNEP5(from: Address, assetID: Address, amount: Fixed8): void { + public depositNEP17(from: Address, assetID: Address, amount: Fixed8): void { if (!Address.isCaller(from)) throw new Error('Caller was not the sender!'); if (amount < 1) throw new Error('Amount must be greater than 0!'); - this.transferNEP5(from, this.address, assetID, amount); + this.transferNEP17(from, this.address, assetID, amount); this.balances.set([from, assetID], this.balanceOf(from, assetID) + amount); notifyDeposited(from, assetID, amount); } - public withdrawNEP5(from: Address, assetID: Address, amount: Fixed8): void { + public withdrawNEP17(from: Address, assetID: Address, amount: Fixed8): void { if (amount < 0) throw new Error(`Amount must be greater than 0: ${amount}`); const balance = this.balanceOf(from, assetID); if (balance < amount) throw new Error(`Not enough Balance to withdraw ${amount}!`); if (!Address.isCaller(from)) throw new Error('Caller is not authorized to withdraw funds!'); - this.transferNEP5(this.address, from, assetID, amount); + this.transferNEP17(this.address, from, assetID, amount); this.balances.set([from, assetID], this.balanceOf(from, assetID) - amount); notifyWithdrawn(from, assetID, amount); } @@ -309,9 +309,9 @@ export class Exchange extends SmartContract { return crypto.hash256(offerBuffer); } - private transferNEP5(from: Address, to: Address, assetID: Address, amount: Fixed8): void { - const nep5Asset = SmartContract.for(assetID); - if (!nep5Asset.transfer(from, to, amount)) { + private transferNEP17(from: Address, to: Address, assetID: Address, amount: Fixed8): void { + const nep17Asset = SmartContract.for(assetID); + if (!nep17Asset.transfer(from, to, amount)) { throw new Error('Failed to transfer NEP-5 tokens!'); } } diff --git a/packages/neo-one-cli/src/__e2e__/cmd/buildExchange.test.ts b/packages/neo-one-cli/src/__e2e__/cmd/buildExchange.test.ts index 1ca00c6c2f..7ade48d848 100644 --- a/packages/neo-one-cli/src/__e2e__/cmd/buildExchange.test.ts +++ b/packages/neo-one-cli/src/__e2e__/cmd/buildExchange.test.ts @@ -69,7 +69,7 @@ const checkBalances = async ({ expect(tokensDeposited.toString()).toEqual(expected.tokensOnExchange); }; -const depositNEP5 = async ({ +const depositNEP17 = async ({ token, tokenAssetID, exchange, @@ -97,7 +97,7 @@ const depositNEP5 = async ({ expect(approveDepositReceipt.result.value).toEqual(true); const [exchangeDepositReceipt] = await Promise.all([ - exchange.depositNEP5.confirmed(from.address, tokenAssetID, amount, { from }), + exchange.depositNEP17.confirmed(from.address, tokenAssetID, amount, { from }), developerClient.runConsensusNow(), ]); expect(exchangeDepositReceipt.result.state).toEqual('HALT'); @@ -107,7 +107,7 @@ const depositNEP5 = async ({ await checkBalances({ token, tokenAssetID, from, exchange, exchangeAddress, expected }); }; -const withdrawNEP5 = async ({ +const withdrawNEP17 = async ({ token, tokenAssetID, exchange, @@ -127,7 +127,7 @@ const withdrawNEP5 = async ({ readonly developerClient: DeveloperClient; }) => { const [exchangeWithdrawalReceipt] = await Promise.all([ - exchange.withdrawNEP5.confirmed(from.address, tokenAssetID, amount, { from }), + exchange.withdrawNEP17.confirmed(from.address, tokenAssetID, amount, { from }), developerClient.runConsensusNow(), ]); expect(exchangeWithdrawalReceipt.result.state).toEqual('HALT'); @@ -137,7 +137,7 @@ const withdrawNEP5 = async ({ await checkBalances({ token, tokenAssetID, from, exchange, exchangeAddress, expected }); }; -const verifyNEP5NEP5Exchange = async ({ +const verifyNEP17NEP17Exchange = async ({ token, tokenAssetID, coin, @@ -158,7 +158,7 @@ const verifyNEP5NEP5Exchange = async ({ readonly toAccountID: UserAccountID; readonly developerClient: DeveloperClient; }) => { - await depositNEP5({ + await depositNEP17({ token, tokenAssetID, exchange, @@ -169,7 +169,7 @@ const verifyNEP5NEP5Exchange = async ({ developerClient, }); - await withdrawNEP5({ + await withdrawNEP17({ token, tokenAssetID, exchange, @@ -187,7 +187,7 @@ const verifyNEP5NEP5Exchange = async ({ ); expect(coinTransferReceipt.result.value).toEqual(true); - await depositNEP5({ + await depositNEP17({ token: coin, tokenAssetID: coinAssetID, exchange, @@ -300,7 +300,7 @@ const verifyExchangeContractTesting = async (codegenPath: string) => { const coinAssetID = coin.definition.networks[masterAccountID.network].address; const exchangeAddress = exchange.definition.networks[masterAccountID.network].address; - await verifyNEP5NEP5Exchange({ + await verifyNEP17NEP17Exchange({ token, tokenAssetID, coin, diff --git a/packages/neo-one-client-common/src/models/index.ts b/packages/neo-one-client-common/src/models/index.ts index 50c880cde2..aa8f4878e4 100644 --- a/packages/neo-one-client-common/src/models/index.ts +++ b/packages/neo-one-client-common/src/models/index.ts @@ -7,7 +7,7 @@ export * from './StorageFlagsModel'; export * from './WitnessModel'; export * from './WitnessScopeModel'; export * from './transaction'; -export * from './nep5'; +export * from './nep17'; export * from './types'; export * from './vm'; export * from './trigger'; diff --git a/packages/neo-one-client-common/src/models/nep5/Nep5BalanceKeyModel.ts b/packages/neo-one-client-common/src/models/nep17/Nep17BalanceKeyModel.ts similarity index 78% rename from packages/neo-one-client-common/src/models/nep5/Nep5BalanceKeyModel.ts rename to packages/neo-one-client-common/src/models/nep17/Nep17BalanceKeyModel.ts index 5d22e82247..7855614ede 100644 --- a/packages/neo-one-client-common/src/models/nep5/Nep5BalanceKeyModel.ts +++ b/packages/neo-one-client-common/src/models/nep17/Nep17BalanceKeyModel.ts @@ -2,17 +2,17 @@ import { BinaryWriter } from '../../BinaryWriter'; import { UInt160 } from '../../common'; import { createSerializeWire, SerializableWire, SerializeWire } from '../Serializable'; -export interface Nep5BalanceKeyModelAdd { +export interface Nep17BalanceKeyModelAdd { readonly userScriptHash: UInt160; readonly assetScriptHash: UInt160; } -export class Nep5BalanceKeyModel implements SerializableWire { +export class Nep17BalanceKeyModel implements SerializableWire { public readonly userScriptHash: UInt160; public readonly assetScriptHash: UInt160; public readonly serializeWire: SerializeWire = createSerializeWire(this.serializeWireBase.bind(this)); - public constructor({ userScriptHash, assetScriptHash }: Nep5BalanceKeyModelAdd) { + public constructor({ userScriptHash, assetScriptHash }: Nep17BalanceKeyModelAdd) { this.userScriptHash = userScriptHash; this.assetScriptHash = assetScriptHash; } diff --git a/packages/neo-one-client-common/src/models/nep5/Nep5BalanceModel.ts b/packages/neo-one-client-common/src/models/nep17/Nep17BalanceModel.ts similarity index 78% rename from packages/neo-one-client-common/src/models/nep5/Nep5BalanceModel.ts rename to packages/neo-one-client-common/src/models/nep17/Nep17BalanceModel.ts index c177181682..c70bfeb61f 100644 --- a/packages/neo-one-client-common/src/models/nep5/Nep5BalanceModel.ts +++ b/packages/neo-one-client-common/src/models/nep17/Nep17BalanceModel.ts @@ -1,17 +1,17 @@ import { BinaryWriter } from '../../BinaryWriter'; import { createSerializeWire, SerializableWire, SerializeWire } from '../Serializable'; -export interface Nep5BalanceModelAdd { +export interface Nep17BalanceModelAdd { readonly balanceBuffer: Buffer; readonly lastUpdatedBlock: number; } -export class Nep5BalanceModel implements SerializableWire { +export class Nep17BalanceModel implements SerializableWire { public readonly balanceInternal: Buffer; public readonly lastUpdatedBlock: number; public readonly serializeWire: SerializeWire = createSerializeWire(this.serializeWireBase.bind(this)); - public constructor({ balanceBuffer, lastUpdatedBlock }: Nep5BalanceModelAdd) { + public constructor({ balanceBuffer, lastUpdatedBlock }: Nep17BalanceModelAdd) { this.balanceInternal = balanceBuffer; this.lastUpdatedBlock = lastUpdatedBlock; } diff --git a/packages/neo-one-client-common/src/models/nep5/Nep5TransferKeyModel.ts b/packages/neo-one-client-common/src/models/nep17/Nep17TransferKeyModel.ts similarity index 89% rename from packages/neo-one-client-common/src/models/nep5/Nep5TransferKeyModel.ts rename to packages/neo-one-client-common/src/models/nep17/Nep17TransferKeyModel.ts index fadd3d4bd1..0ff8dc1957 100644 --- a/packages/neo-one-client-common/src/models/nep5/Nep5TransferKeyModel.ts +++ b/packages/neo-one-client-common/src/models/nep17/Nep17TransferKeyModel.ts @@ -3,14 +3,14 @@ import { BinaryWriter } from '../../BinaryWriter'; import { UInt160 } from '../../common'; import { createSerializeWire, SerializableWire, SerializeWire } from '../Serializable'; -export interface Nep5TransferKeyModelAdd { +export interface Nep17TransferKeyModelAdd { readonly userScriptHash: UInt160; readonly timestampMS: BN; readonly assetScriptHash: UInt160; readonly blockTransferNotificationIndex: number; } -export class Nep5TransferKeyModel implements SerializableWire { +export class Nep17TransferKeyModel implements SerializableWire { public readonly userScriptHash: UInt160; public readonly timestampMS: BN; public readonly assetScriptHash: UInt160; @@ -22,7 +22,7 @@ export class Nep5TransferKeyModel implements SerializableWire { timestampMS, assetScriptHash, blockTransferNotificationIndex, - }: Nep5TransferKeyModelAdd) { + }: Nep17TransferKeyModelAdd) { this.userScriptHash = userScriptHash; this.timestampMS = timestampMS; this.assetScriptHash = assetScriptHash; diff --git a/packages/neo-one-client-common/src/models/nep5/Nep5TransferModel.ts b/packages/neo-one-client-common/src/models/nep17/Nep17TransferModel.ts similarity index 88% rename from packages/neo-one-client-common/src/models/nep5/Nep5TransferModel.ts rename to packages/neo-one-client-common/src/models/nep17/Nep17TransferModel.ts index 8ba02bad5c..a88e6bfaa2 100644 --- a/packages/neo-one-client-common/src/models/nep5/Nep5TransferModel.ts +++ b/packages/neo-one-client-common/src/models/nep17/Nep17TransferModel.ts @@ -2,21 +2,21 @@ import { BinaryWriter } from '../../BinaryWriter'; import { UInt160, UInt256 } from '../../common'; import { createSerializeWire, SerializableWire, SerializeWire } from '../Serializable'; -export interface Nep5TransferModelAdd { +export interface Nep17TransferModelAdd { readonly userScriptHash: UInt160; readonly blockIndex: number; readonly txHash: UInt256; readonly amountBuffer: Buffer; } -export class Nep5TransferModel implements SerializableWire { +export class Nep17TransferModel implements SerializableWire { public readonly userScriptHash: UInt160; public readonly blockIndex: number; public readonly txHash: UInt256; public readonly amountInternal: Buffer; public readonly serializeWire: SerializeWire = createSerializeWire(this.serializeWireBase.bind(this)); - public constructor({ userScriptHash, blockIndex, txHash, amountBuffer }: Nep5TransferModelAdd) { + public constructor({ userScriptHash, blockIndex, txHash, amountBuffer }: Nep17TransferModelAdd) { this.userScriptHash = userScriptHash; this.blockIndex = blockIndex; this.txHash = txHash; diff --git a/packages/neo-one-client-common/src/models/nep17/index.ts b/packages/neo-one-client-common/src/models/nep17/index.ts new file mode 100644 index 0000000000..21d52dfbff --- /dev/null +++ b/packages/neo-one-client-common/src/models/nep17/index.ts @@ -0,0 +1,4 @@ +export * from './Nep17BalanceModel'; +export * from './Nep17TransferModel'; +export * from './Nep17TransferKeyModel'; +export * from './Nep17BalanceKeyModel'; diff --git a/packages/neo-one-client-common/src/models/nep5/index.ts b/packages/neo-one-client-common/src/models/nep5/index.ts deleted file mode 100644 index e011fa908e..0000000000 --- a/packages/neo-one-client-common/src/models/nep5/index.ts +++ /dev/null @@ -1,4 +0,0 @@ -export * from './Nep5BalanceModel'; -export * from './Nep5TransferModel'; -export * from './Nep5TransferKeyModel'; -export * from './Nep5BalanceKeyModel'; diff --git a/packages/neo-one-client-common/src/models/types.ts b/packages/neo-one-client-common/src/models/types.ts index 146391fda3..e57892139a 100644 --- a/packages/neo-one-client-common/src/models/types.ts +++ b/packages/neo-one-client-common/src/models/types.ts @@ -408,24 +408,24 @@ export interface ContractJSON { readonly manifest: ContractManifestJSON; } -export interface Nep5TransfersJSON { +export interface Nep17TransfersJSON { readonly address: string; - readonly received: readonly Nep5TransferJSON[]; - readonly sent: readonly Nep5TransferJSON[]; + readonly received: readonly Nep17TransferJSON[]; + readonly sent: readonly Nep17TransferJSON[]; } -export interface Nep5BalancesJSON { +export interface Nep17BalancesJSON { readonly address: string; - readonly balance: readonly Nep5BalanceJSON[]; + readonly balance: readonly Nep17BalanceJSON[]; } -export interface Nep5BalanceJSON { +export interface Nep17BalanceJSON { readonly assethash: string; readonly amount: string; readonly lastupdatedblock: number; } -export interface Nep5TransferJSON { +export interface Nep17TransferJSON { readonly timestamp: number; readonly assethash: string; readonly transferaddress: string; diff --git a/packages/neo-one-client-common/src/types.ts b/packages/neo-one-client-common/src/types.ts index a7b7eea060..081dcba952 100644 --- a/packages/neo-one-client-common/src/types.ts +++ b/packages/neo-one-client-common/src/types.ts @@ -694,7 +694,7 @@ export interface DeveloperProvider { } /** - * An `Account` represents the balances of NEO, GAS an other NEP5 assets at a given `Address`. + * An `Account` represents the balances of NEO, GAS an other NEP17 assets at a given `Address`. */ export interface Account { /** diff --git a/packages/neo-one-client-core/src/__data__/factory.ts b/packages/neo-one-client-core/src/__data__/factory.ts index c4c77fdf70..9acf972495 100644 --- a/packages/neo-one-client-core/src/__data__/factory.ts +++ b/packages/neo-one-client-core/src/__data__/factory.ts @@ -78,7 +78,7 @@ import BigNumber from 'bignumber.js'; import { BN } from 'bn.js'; import { ContractEventDescriptor, ContractMethodDescriptor } from '../../../neo-one-node-core/src/manifest'; import { Hash160 } from '../Hash160'; -import * as nep5 from '../nep5'; +import * as nep17 from '../nep17'; import { LockedWallet, UnlockedWallet } from '../user'; import { data } from './data'; import { keys } from './keys'; @@ -724,7 +724,7 @@ const createStringABIParameter = (options: Partial = {}): St }); const createABI = (options: Partial = {}): ContractABI => ({ - ...nep5.abi(8), + ...nep17.abi(8), ...options, }); diff --git a/packages/neo-one-client-core/src/__tests__/__snapshots__/nep5.test.ts.snap b/packages/neo-one-client-core/src/__tests__/__snapshots__/nep5.test.ts.snap index eb39263e1a..58fdc25058 100644 --- a/packages/neo-one-client-core/src/__tests__/__snapshots__/nep5.test.ts.snap +++ b/packages/neo-one-client-core/src/__tests__/__snapshots__/nep5.test.ts.snap @@ -98,7 +98,7 @@ Object { } `; -exports[`nep5 createNEP5SmartContract 1`] = ` +exports[`nep5 createNEP17SmartContract 1`] = ` Array [ Array [ Object { diff --git a/packages/neo-one-client-core/src/__tests__/nep5.test.ts b/packages/neo-one-client-core/src/__tests__/nep17.test.ts similarity index 64% rename from packages/neo-one-client-core/src/__tests__/nep5.test.ts rename to packages/neo-one-client-core/src/__tests__/nep17.test.ts index c8016a34b0..513dbdd0f3 100644 --- a/packages/neo-one-client-core/src/__tests__/nep5.test.ts +++ b/packages/neo-one-client-core/src/__tests__/nep17.test.ts @@ -2,11 +2,11 @@ import BigNumber from 'bignumber.js'; import { data, factory } from '../__data__'; import { Client } from '../Client'; -import * as nep5 from '../nep5'; +import * as nep17 from '../nep17'; -describe('nep5', () => { +describe('nep17', () => { test('abi', () => { - expect(nep5.abi(4)).toMatchSnapshot(); + expect(nep17.abi(4)).toMatchSnapshot(); }); const smartContract: { decimals?: () => BigNumber } = {}; @@ -18,13 +18,13 @@ describe('nep5', () => { test('getDecimals', async () => { smartContract.decimals = jest.fn(() => data.bigNumbers.a); - const result = await nep5.getDecimals(client, factory.createSmartContractDefinition().networks, 'main'); + const result = await nep17.getDecimals(client, factory.createSmartContractDefinition().networks, 'main'); expect(result).toEqual(data.bigNumbers.a.toNumber()); }); - test('createNEP5SmartContract', () => { - const contract = nep5.createNEP5SmartContract(client, factory.createSmartContractDefinition().networks, 8); + test('createNEP17SmartContract', () => { + const contract = nep17.createNEP17SmartContract(client, factory.createSmartContractDefinition().networks, 8); expect(contract).toEqual(smartContract); expect(clientSmartContract.mock.calls).toMatchSnapshot(); diff --git a/packages/neo-one-client-core/src/__tests__/provider/temp.test.ts b/packages/neo-one-client-core/src/__tests__/provider/temp.test.ts index a20c2d6a29..45099661d8 100644 --- a/packages/neo-one-client-core/src/__tests__/provider/temp.test.ts +++ b/packages/neo-one-client-core/src/__tests__/provider/temp.test.ts @@ -28,8 +28,8 @@ describe('JSONRPCClient Tests', async () => { ['getStorage', getStorageArgs(common.nativeHashes.GAS, 11)], ['getApplicationLog', [transactionHash]], ['getBlock', [1]], - ['getNep5Balances', [address]], - ['getNep5Transfers', [addressWithTransfers, 1468595301000, 1603753592250]], + ['getNep17Balances', [address]], + ['getNep17Transfers', [addressWithTransfers, 1468595301000, 1603753592250]], ['getBestBlockHash', []], ['getBlockCount', []], ['getContract', [Hash160.NEO]], diff --git a/packages/neo-one-client-core/src/index.ts b/packages/neo-one-client-core/src/index.ts index a891bda3d8..5cb6bb7070 100644 --- a/packages/neo-one-client-core/src/index.ts +++ b/packages/neo-one-client-core/src/index.ts @@ -1,6 +1,6 @@ import * as args from './args'; import { addLocalKeysSync } from './clientUtils'; -import * as nep5 from './nep5'; +import * as nep17 from './nep17'; export * from './AsyncBlockIterator'; export * from './Client'; @@ -12,4 +12,4 @@ export * from './sc'; export * from './trace'; export * from './types'; export * from './user'; -export { args, nep5, addLocalKeysSync }; +export { args, nep17, addLocalKeysSync }; diff --git a/packages/neo-one-client-core/src/nep5.ts b/packages/neo-one-client-core/src/nep17.ts similarity index 86% rename from packages/neo-one-client-core/src/nep5.ts rename to packages/neo-one-client-core/src/nep17.ts index 1c7d428e0f..7f938ff9aa 100644 --- a/packages/neo-one-client-core/src/nep5.ts +++ b/packages/neo-one-client-core/src/nep17.ts @@ -18,16 +18,16 @@ import BigNumber from 'bignumber.js'; import { Client } from './Client'; import { SmartContract } from './types'; -export type NEP5Event = NEP5TransferEvent; +export type NEP17Event = NEP17TransferEvent; -export interface NEP5TransferEventParameters { +export interface NEP17TransferEventParameters { readonly from: AddressString | undefined; readonly to: AddressString | undefined; readonly amount: BigNumber; } -export interface NEP5TransferEvent extends Event<'transfer', NEP5TransferEventParameters> {} +export interface NEP17TransferEvent extends Event<'transfer', NEP17TransferEventParameters> {} -export interface NEP5SmartContract extends SmartContract { +export interface NEP17SmartContract extends SmartContract { readonly balanceOf: (address: AddressString, options?: SmartContractReadOptions) => Promise; readonly decimals: (options?: SmartContractReadOptions) => Promise; readonly name: (options?: SmartContractReadOptions) => Promise; @@ -39,7 +39,7 @@ export interface NEP5SmartContract extends Smar to: AddressString, amount: BigNumber, options?: TransactionOptions, - ) => TransactionResult>; + ) => TransactionResult>; } const decimalsFunction: ContractMethodDescriptorClient = { @@ -48,6 +48,7 @@ const decimalsFunction: ContractMethodDescriptorClient = { parameters: [], returnType: { type: 'Integer', decimals: 0 }, offset: 0, + safe: true, }; // TODO: check that the script/hash can/should be blank here. also check offsets @@ -63,6 +64,7 @@ export const abi = (decimals: number): ContractABIClient => ({ parameters: [], returnType: { type: 'String' }, offset: 0, + safe: true, }, { name: 'symbol', @@ -70,6 +72,7 @@ export const abi = (decimals: number): ContractABIClient => ({ parameters: [], returnType: { type: 'String' }, offset: 0, + safe: true, }, decimalsFunction, { @@ -78,6 +81,7 @@ export const abi = (decimals: number): ContractABIClient => ({ parameters: [], returnType: { type: 'Integer', decimals }, offset: 0, + safe: true, }, { name: 'transfer', @@ -98,6 +102,7 @@ export const abi = (decimals: number): ContractABIClient => ({ ], returnType: { type: 'Boolean' }, offset: 0, + safe: false, }, { name: 'balanceOf', @@ -110,6 +115,7 @@ export const abi = (decimals: number): ContractABIClient => ({ ], returnType: { type: 'Integer', decimals }, offset: 0, + safe: false, }, ], events: [ @@ -164,12 +170,12 @@ export const getDecimals = async ( return decimalsBigNumber.toNumber(); }; -export const createNEP5SmartContract = ( +export const createNEP17SmartContract = ( client: TClient, networksDefinition: SmartContractNetworksDefinition, decimals: number, -): NEP5SmartContract => - client.smartContract>({ +): NEP17SmartContract => + client.smartContract>({ networks: networksDefinition, manifest: manifest(decimals), }); diff --git a/packages/neo-one-client-core/src/provider/JSONRPCClient.ts b/packages/neo-one-client-core/src/provider/JSONRPCClient.ts index 746b8bad3c..9dbd07b8ab 100644 --- a/packages/neo-one-client-core/src/provider/JSONRPCClient.ts +++ b/packages/neo-one-client-core/src/provider/JSONRPCClient.ts @@ -10,8 +10,8 @@ import { Hash256String, HeaderJSON, InvocationDataJSON, - Nep5BalancesJSON, - Nep5TransfersJSON, + Nep17BalancesJSON, + Nep17TransfersJSON, NetworkSettingsJSON, Peer, PrivateNetworkSettings, @@ -47,23 +47,23 @@ export class JSONRPCClient { ); } - public async getNep5Balances(address: AddressString): Promise { + public async getNep17Balances(address: AddressString): Promise { return this.withInstance(async (provider) => provider.request({ - method: 'getnep5balances', + method: 'getnep17balances', params: [addressToScriptHash(address)], }), ); } - public async getNep5Transfers( + public async getNep17Transfers( address: AddressString, startTime?: number, endTime?: number, - ): Promise { + ): Promise { return this.withInstance(async (provider) => provider.request({ - method: 'getnep5transfers', + method: 'getnep17transfers', params: [addressToScriptHash(address), startTime, endTime], }), ); diff --git a/packages/neo-one-client-core/src/provider/NEOONEDataProvider.ts b/packages/neo-one-client-core/src/provider/NEOONEDataProvider.ts index 0f3fb8e128..8c5548bed9 100644 --- a/packages/neo-one-client-core/src/provider/NEOONEDataProvider.ts +++ b/packages/neo-one-client-core/src/provider/NEOONEDataProvider.ts @@ -270,7 +270,7 @@ export class NEOONEDataProvider implements DeveloperProvider { } public async getAccount(address: AddressString): Promise { - const balances = await this.mutableClient.getNep5Balances(address); + const balances = await this.mutableClient.getNep17Balances(address); return { address, diff --git a/packages/neo-one-client-full-core/src/__data__/factory.ts b/packages/neo-one-client-full-core/src/__data__/factory.ts index b2f3fd47a4..9d7699134c 100644 --- a/packages/neo-one-client-full-core/src/__data__/factory.ts +++ b/packages/neo-one-client-full-core/src/__data__/factory.ts @@ -93,7 +93,7 @@ import { Witness, WitnessJSON, } from '@neo-one/client-common'; -import { Hash256, LockedWallet, nep5, UnlockedWallet } from '@neo-one/client-core'; +import { Hash256, LockedWallet, nep17, UnlockedWallet } from '@neo-one/client-core'; import BigNumber from 'bignumber.js'; import { BN } from 'bn.js'; import { AssetRegister, ContractRegister } from '../types'; @@ -894,7 +894,7 @@ const createStringABIParameter = (options: Partial = {}): St }); const createABI = (options: Partial = {}): ABI => ({ - ...nep5.abi(8), + ...Nep17.abi(8), ...options, }); diff --git a/packages/neo-one-client-full-core/src/__tests__/args.test.ts b/packages/neo-one-client-full-core/src/__tests__/args.test.ts index 8f4730aa3b..9fa4deb34f 100644 --- a/packages/neo-one-client-full-core/src/__tests__/args.test.ts +++ b/packages/neo-one-client-full-core/src/__tests__/args.test.ts @@ -1,4 +1,4 @@ -import { args as clientArgs, nep5 } from '@neo-one/client-core'; +import { args as clientArgs, nep17 } from '@neo-one/client-core'; import { data } from '../__data__'; import * as args from '../args'; @@ -129,14 +129,14 @@ describe('arg assertions', () => { expect(() => args.assertContractRegister('value', value)).toThrowErrorMatchingSnapshot(); }); - test('assertABI - nep5', () => { - const value = nep5.abi(8); + test('assertABI - nep17', () => { + const value = nep17.abi(8); expect(clientArgs.assertContractABIClient('value', value)).toEqual(value); }); test('assertContractManifest', () => { - const value = nep5.manifest(8); + const value = nep17.manifest(8); expect(clientArgs.assertContractManifest('value', value)).toEqual(value); }); diff --git a/packages/neo-one-client-full/src/index.ts b/packages/neo-one-client-full/src/index.ts index 37167dcac8..e55e0e778b 100644 --- a/packages/neo-one-client-full/src/index.ts +++ b/packages/neo-one-client-full/src/index.ts @@ -127,7 +127,7 @@ export { decryptNEP2, encryptNEP2, isNEP2, - nep5, + nep17, privateKeyToAddress, privateKeyToPublicKey, privateKeyToScriptHash, diff --git a/packages/neo-one-client/src/index.ts b/packages/neo-one-client/src/index.ts index a7eacf526d..9912593ea8 100644 --- a/packages/neo-one-client/src/index.ts +++ b/packages/neo-one-client/src/index.ts @@ -198,7 +198,7 @@ export { SmartContract, SmartContractAny, UnlockedWallet, - nep5, + nep17, } from '@neo-one/client-core'; // export { DeveloperTools } from '@neo-one/developer-tools'; diff --git a/packages/neo-one-developer-tools-frame/src/AddToken.tsx b/packages/neo-one-developer-tools-frame/src/AddToken.tsx index ab3f4d4d69..516286ebfc 100644 --- a/packages/neo-one-developer-tools-frame/src/AddToken.tsx +++ b/packages/neo-one-developer-tools-frame/src/AddToken.tsx @@ -1,5 +1,5 @@ import styled from '@emotion/styled'; -import { nep5 } from '@neo-one/client-core'; +import { nep17 } from '@neo-one/client-core'; import { Box, Button, TextInput } from '@neo-one/react-common'; import * as React from 'react'; import { DeveloperToolsContext, useTokens } from './DeveloperToolsContext'; @@ -24,8 +24,8 @@ export function AddToken(props: {}) { Promise.resolve() .then(async () => { const network = client.getCurrentNetwork(); - const decimals = await nep5.getDecimals(client, { [network]: { address } }, network); - const smartContract = nep5.createNEP5SmartContract(client, { [network]: { address } }, decimals); + const decimals = await nep17.getDecimals(client, { [network]: { address } }, network); + const smartContract = nep17.createNEP17SmartContract(client, { [network]: { address } }, decimals); const symbol = await smartContract.symbol({ network }); onChangeTokens(tokens.concat({ network, address, decimals, symbol })); diff --git a/packages/neo-one-developer-tools-frame/src/BalanceSelector.tsx b/packages/neo-one-developer-tools-frame/src/BalanceSelector.tsx index bbec89cf3a..f0730abcd2 100644 --- a/packages/neo-one-developer-tools-frame/src/BalanceSelector.tsx +++ b/packages/neo-one-developer-tools-frame/src/BalanceSelector.tsx @@ -1,6 +1,6 @@ // tslint:disable no-object-mutation import styled from '@emotion/styled'; -import { nep5 } from '@neo-one/client-core'; +import { nep17 } from '@neo-one/client-core'; import { Box, usePrevious, useStream } from '@neo-one/react-common'; import { utils } from '@neo-one/utils'; import BigNumber from 'bignumber.js'; @@ -75,7 +75,7 @@ export function BalanceSelector() { accountState$.pipe(filter(utils.notNull)).pipe( switchMap(async ({ currentUserAccount, account }) => { if (asset.type === 'token') { - const smartContract = nep5.createNEP5SmartContract( + const smartContract = nep17.createNEP17SmartContract( client, { [asset.token.network]: { address: asset.token.address } }, asset.token.decimals, diff --git a/packages/neo-one-developer-tools-frame/src/WalletSelectorBase.tsx b/packages/neo-one-developer-tools-frame/src/WalletSelectorBase.tsx index d3d3851d98..59f7462300 100644 --- a/packages/neo-one-developer-tools-frame/src/WalletSelectorBase.tsx +++ b/packages/neo-one-developer-tools-frame/src/WalletSelectorBase.tsx @@ -1,7 +1,7 @@ // tslint:disable no-any import styled from '@emotion/styled'; import { Account, UserAccount } from '@neo-one/client-common'; -import { Client, Hash256, nep5 } from '@neo-one/client-core'; +import { Client, Hash256, nep17 } from '@neo-one/client-core'; import { Box, Select } from '@neo-one/react-common'; import { PromiseReturnType, utils } from '@neo-one/utils'; import BigNumber from 'bignumber.js'; @@ -43,7 +43,7 @@ export const makeOption = async ({ tokens .filter((token) => token.network === userAccount.id.network) .map>(async (token) => { - const smartContract = nep5.createNEP5SmartContract( + const smartContract = nep17.createNEP17SmartContract( client, { [token.network]: { address: token.address } }, token.decimals, diff --git a/packages/neo-one-developer-tools-frame/src/WalletTransfer.tsx b/packages/neo-one-developer-tools-frame/src/WalletTransfer.tsx index dd44f310bc..454969a5e4 100644 --- a/packages/neo-one-developer-tools-frame/src/WalletTransfer.tsx +++ b/packages/neo-one-developer-tools-frame/src/WalletTransfer.tsx @@ -1,5 +1,5 @@ import { TransactionResult, UserAccount } from '@neo-one/client-common'; -import { nep5 } from '@neo-one/client-core'; +import { nep17 } from '@neo-one/client-core'; import BigNumber from 'bignumber.js'; import * as React from 'react'; import { useNetworkClients } from './DeveloperToolsContext'; @@ -69,7 +69,7 @@ export function WalletTransfer() { // tslint:disable-next-line possible-timing-attack if (asset.type === 'token') { - const smartContract = nep5.createNEP5SmartContract( + const smartContract = nep17.createNEP17SmartContract( client, { [asset.token.network]: { address: asset.token.address } }, asset.token.decimals, diff --git a/packages/neo-one-node-blockchain/src/Blockchain.ts b/packages/neo-one-node-blockchain/src/Blockchain.ts index 9bc80a6a70..2545f01232 100644 --- a/packages/neo-one-node-blockchain/src/Blockchain.ts +++ b/packages/neo-one-node-blockchain/src/Blockchain.ts @@ -24,7 +24,7 @@ import { Header, Mempool, NativeContainer, - Nep5Balance, + Nep17Balance, Notification, RunEngineOptions, Signers, @@ -46,7 +46,7 @@ import { GenesisBlockNotRegisteredError, RecoverBlockchainError, } from './errors'; -import { getNep5UpdateOptions } from './getNep5UpdateOptions'; +import { getNep17UpdateOptions } from './getNep17UpdateOptions'; import { HeaderIndexCache } from './HeaderIndexCache'; import { PersistingBlockchain } from './PersistingBlockchain'; import { utils } from './utils'; @@ -256,16 +256,16 @@ export class Blockchain { return this.storage.blocks; } - public get nep5Balances() { - return this.storage.nep5Balances; + public get nep17Balances() { + return this.storage.nep17Balances; } - public get nep5TransfersReceived() { - return this.storage.nep5TransfersReceived; + public get nep17TransfersReceived() { + return this.storage.nep17TransfersReceived; } - public get nep5TransfersSent() { - return this.storage.nep5TransfersSent; + public get nep17TransfersSent() { + return this.storage.nep17TransfersSent; } public get applicationLogs() { @@ -649,32 +649,32 @@ export class Blockchain { return [updateBlockHashIndex, updateHeaderHashIndex]; } - private updateNep5Balances({ + private updateNep17Balances({ applicationsExecuted, block, }: { readonly applicationsExecuted: readonly ApplicationExecuted[]; readonly block: Block; }) { - const { assetKeys, transfersSent, transfersReceived } = getNep5UpdateOptions({ + const { assetKeys, transfersSent, transfersReceived } = getNep17UpdateOptions({ applicationsExecuted, block, }); - const nep5BalancePairs = assetKeys.map((key) => { + const nep17BalancePairs = assetKeys.map((key) => { const script = new ScriptBuilder().emitAppCall(key.assetScriptHash, 'balanceOf', key.userScriptHash).build(); const callReceipt = this.invokeScript(script); const balanceBuffer = callReceipt.stack[0].getInteger().toBuffer(); - return { key, value: new Nep5Balance({ balanceBuffer, lastUpdatedBlock: this.currentBlockIndex }) }; + return { key, value: new Nep17Balance({ balanceBuffer, lastUpdatedBlock: this.currentBlockIndex }) }; }); - const nep5BalanceChangeSet: ChangeSet = nep5BalancePairs.map(({ key, value }) => { + const nep17BalanceChangeSet: ChangeSet = nep17BalancePairs.map(({ key, value }) => { if (value.balance.eqn(0)) { return { type: 'delete', change: { - type: 'nep5Balance', + type: 'nep17Balance', key, }, }; @@ -683,7 +683,7 @@ export class Blockchain { return { type: 'add', change: { - type: 'nep5Balance', + type: 'nep17Balance', key, value, }, @@ -691,27 +691,27 @@ export class Blockchain { }; }); - const nep5TransfersSentChangeSet: ChangeSet = transfersSent.map(({ key, value }) => ({ + const nep17TransfersSentChangeSet: ChangeSet = transfersSent.map(({ key, value }) => ({ type: 'add', subType: 'add', change: { - type: 'nep5TransferSent', + type: 'nep17TransferSent', key, value, }, })); - const nep5TransfersReceivedChangeSet: ChangeSet = transfersReceived.map(({ key, value }) => ({ + const nep17TransfersReceivedChangeSet: ChangeSet = transfersReceived.map(({ key, value }) => ({ type: 'add', subType: 'add', change: { - type: 'nep5TransferReceived', + type: 'nep17TransferReceived', key, value, }, })); - return nep5BalanceChangeSet.concat(nep5TransfersReceivedChangeSet, nep5TransfersSentChangeSet); + return nep17BalanceChangeSet.concat(nep17TransfersReceivedChangeSet, nep17TransfersSentChangeSet); } private updateApplicationLogs({ @@ -772,8 +772,8 @@ export class Blockchain { const blockMetadataBatch = this.updateBlockMetadata(block); await this.storage.commit(blockMetadataBatch); - const nep5Updates = this.updateNep5Balances({ applicationsExecuted, block }); - await this.storage.commit(nep5Updates); + const nep17Updates = this.updateNep17Balances({ applicationsExecuted, block }); + await this.storage.commit(nep17Updates); const applicationLogUpdates = this.updateApplicationLogs({ applicationsExecuted, block }); await this.storage.commit(applicationLogUpdates); diff --git a/packages/neo-one-node-blockchain/src/getNep5UpdateOptions.ts b/packages/neo-one-node-blockchain/src/getNep17UpdateOptions.ts similarity index 70% rename from packages/neo-one-node-blockchain/src/getNep5UpdateOptions.ts rename to packages/neo-one-node-blockchain/src/getNep17UpdateOptions.ts index ba2ce55b4f..caa21f5c62 100644 --- a/packages/neo-one-node-blockchain/src/getNep5UpdateOptions.ts +++ b/packages/neo-one-node-blockchain/src/getNep17UpdateOptions.ts @@ -4,35 +4,35 @@ import { Block, isByteStringStackItem, isIntegerStackItem, - Nep5BalanceKey, - Nep5Transfer, - Nep5TransferKey, + Nep17BalanceKey, + Nep17Transfer, + Nep17TransferKey, } from '@neo-one/node-core'; import { utils } from './utils'; -export interface Nep5TransferReturn { - readonly key: Nep5TransferKey; - readonly value: Nep5Transfer; +export interface Nep17TransferReturn { + readonly key: Nep17TransferKey; + readonly value: Nep17Transfer; } -export interface Nep5UpdateOptions { - readonly assetKeys: readonly Nep5BalanceKey[]; - readonly transfersSent: readonly Nep5TransferReturn[]; - readonly transfersReceived: readonly Nep5TransferReturn[]; +export interface Nep17UpdateOptions { + readonly assetKeys: readonly Nep17BalanceKey[]; + readonly transfersSent: readonly Nep17TransferReturn[]; + readonly transfersReceived: readonly Nep17TransferReturn[]; } -export function getNep5UpdateOptions({ +export function getNep17UpdateOptions({ applicationsExecuted, block, }: { readonly applicationsExecuted: readonly ApplicationExecuted[]; readonly block: Block; -}): Nep5UpdateOptions { +}): Nep17UpdateOptions { let transferIndex = 0; - const nep5BalancesChanged = new Set(); - const mutableNep5BalancesChangedKeys: Nep5BalanceKey[] = []; - const mutableTransfersSent: Nep5TransferReturn[] = []; - const mutableTransfersReceived: Nep5TransferReturn[] = []; + const nep17BalancesChanged = new Set(); + const mutableNep17BalancesChangedKeys: Nep17BalanceKey[] = []; + const mutableTransfersSent: Nep17TransferReturn[] = []; + const mutableTransfersReceived: Nep17TransferReturn[] = []; applicationsExecuted.forEach((appExecuted) => { if (appExecuted.state === VMState.FAULT) { @@ -77,26 +77,26 @@ export function getNep5UpdateOptions({ if (fromBytes !== undefined) { from = common.bufferToUInt160(fromBytes); - const fromKey = new Nep5BalanceKey({ userScriptHash: from, assetScriptHash: scriptHash }); + const fromKey = new Nep17BalanceKey({ userScriptHash: from, assetScriptHash: scriptHash }); const fromKeyString = fromKey.serializeWire().toString('hex'); // No need to check address balance for every single transfer. Just need to check new balances for // addresses that we know have transferred assets - // mutableNep5BalancesChangedKeys will be used to run scripts to check storage for new balance of each address + // mutableNep17BalancesChangedKeys will be used to run scripts to check storage for new balance of each address // whose balance we know has changed based on the transfers we know happened - if (!nep5BalancesChanged.has(fromKeyString)) { - nep5BalancesChanged.add(fromKeyString); - mutableNep5BalancesChangedKeys.push(fromKey); + if (!nep17BalancesChanged.has(fromKeyString)) { + nep17BalancesChanged.add(fromKeyString); + mutableNep17BalancesChangedKeys.push(fromKey); } } if (toBytes !== undefined) { to = common.bufferToUInt160(toBytes); - const toKey = new Nep5BalanceKey({ userScriptHash: to, assetScriptHash: scriptHash }); + const toKey = new Nep17BalanceKey({ userScriptHash: to, assetScriptHash: scriptHash }); const toKeyString = toKey.serializeWire().toString('hex'); - if (!nep5BalancesChanged.has(toKeyString)) { - nep5BalancesChanged.add(toKeyString); - mutableNep5BalancesChangedKeys.push(toKey); + if (!nep17BalancesChanged.has(toKeyString)) { + nep17BalancesChanged.add(toKeyString); + mutableNep17BalancesChangedKeys.push(toKey); } } @@ -106,13 +106,13 @@ export function getNep5UpdateOptions({ if (!from.equals(common.ZERO_UINT160)) { mutableTransfersSent.push({ - key: new Nep5TransferKey({ + key: new Nep17TransferKey({ userScriptHash: from, timestampMS: block.timestamp, assetScriptHash: scriptHash, blockTransferNotificationIndex: transferIndex, }), - value: new Nep5Transfer({ + value: new Nep17Transfer({ userScriptHash: to, txHash, blockIndex: block.index, @@ -123,13 +123,13 @@ export function getNep5UpdateOptions({ if (!to.equals(common.ZERO_UINT160)) { mutableTransfersReceived.push({ - key: new Nep5TransferKey({ + key: new Nep17TransferKey({ userScriptHash: to, timestampMS: block.timestamp, assetScriptHash: scriptHash, blockTransferNotificationIndex: transferIndex, }), - value: new Nep5Transfer({ + value: new Nep17Transfer({ userScriptHash: from, txHash, blockIndex: block.index, @@ -144,7 +144,7 @@ export function getNep5UpdateOptions({ }); return { - assetKeys: mutableNep5BalancesChangedKeys, + assetKeys: mutableNep17BalancesChangedKeys, transfersSent: mutableTransfersSent, transfersReceived: mutableTransfersReceived, }; diff --git a/packages/neo-one-node-core/src/Nep5Balance.ts b/packages/neo-one-node-core/src/Nep17Balance.ts similarity index 82% rename from packages/neo-one-node-core/src/Nep5Balance.ts rename to packages/neo-one-node-core/src/Nep17Balance.ts index 12ddf4f79f..3a5b53d8e9 100644 --- a/packages/neo-one-node-core/src/Nep5Balance.ts +++ b/packages/neo-one-node-core/src/Nep17Balance.ts @@ -1,15 +1,15 @@ -import { createSerializeWire, IOHelper, Nep5BalanceModel } from '@neo-one/client-common'; +import { createSerializeWire, IOHelper, Nep17BalanceModel } from '@neo-one/client-common'; import { BN } from 'bn.js'; import { DeserializeWireBaseOptions, DeserializeWireOptions } from './Serializable'; import { BinaryReader, utils } from './utils'; -export interface Nep5BalanceAdd { +export interface Nep17BalanceAdd { readonly balanceBuffer: Buffer; readonly lastUpdatedBlock: number; } -export class Nep5Balance extends Nep5BalanceModel { - public static deserializeWireBase(options: DeserializeWireBaseOptions): Nep5Balance { +export class Nep17Balance extends Nep17BalanceModel { + public static deserializeWireBase(options: DeserializeWireBaseOptions): Nep17Balance { const { reader } = options; const balanceBuffer = reader.readVarBytesLE(512); const lastUpdatedBlock = reader.readUInt32LE(); @@ -20,7 +20,7 @@ export class Nep5Balance extends Nep5BalanceModel { }); } - public static deserializeWire(options: DeserializeWireOptions): Nep5Balance { + public static deserializeWire(options: DeserializeWireOptions): Nep17Balance { return this.deserializeWireBase({ context: options.context, reader: new BinaryReader(options.buffer), @@ -41,7 +41,7 @@ export class Nep5Balance extends Nep5BalanceModel { } public clone() { - return new Nep5Balance({ + return new Nep17Balance({ balanceBuffer: this.balanceInternal, lastUpdatedBlock: this.lastUpdatedBlock, }); diff --git a/packages/neo-one-node-core/src/Nep5BalanceKey.ts b/packages/neo-one-node-core/src/Nep17BalanceKey.ts similarity index 78% rename from packages/neo-one-node-core/src/Nep5BalanceKey.ts rename to packages/neo-one-node-core/src/Nep17BalanceKey.ts index df81989843..0f7a56cbb7 100644 --- a/packages/neo-one-node-core/src/Nep5BalanceKey.ts +++ b/packages/neo-one-node-core/src/Nep17BalanceKey.ts @@ -1,14 +1,14 @@ -import { createSerializeWire, IOHelper, Nep5BalanceKeyModel, UInt160 } from '@neo-one/client-common'; +import { createSerializeWire, IOHelper, Nep17BalanceKeyModel, UInt160 } from '@neo-one/client-common'; import { DeserializeWireBaseOptions, DeserializeWireOptions } from './Serializable'; import { BinaryReader, utils } from './utils'; -export interface Nep5BalanceKeyAdd { +export interface Nep17BalanceKeyAdd { readonly userScriptHash: UInt160; readonly assetScriptHash: UInt160; } -export class Nep5BalanceKey extends Nep5BalanceKeyModel { - public static deserializeWireBase(options: DeserializeWireBaseOptions): Nep5BalanceKey { +export class Nep17BalanceKey extends Nep17BalanceKeyModel { + public static deserializeWireBase(options: DeserializeWireBaseOptions): Nep17BalanceKey { const { reader } = options; const userScriptHash = reader.readUInt160(); const assetScriptHash = reader.readUInt160(); @@ -19,7 +19,7 @@ export class Nep5BalanceKey extends Nep5BalanceKeyModel { }); } - public static deserializeWire(options: DeserializeWireOptions): Nep5BalanceKey { + public static deserializeWire(options: DeserializeWireOptions): Nep17BalanceKey { return this.deserializeWireBase({ context: options.context, reader: new BinaryReader(options.buffer), @@ -34,7 +34,7 @@ export class Nep5BalanceKey extends Nep5BalanceKeyModel { } public clone() { - return new Nep5BalanceKey({ + return new Nep17BalanceKey({ userScriptHash: this.userScriptHash, assetScriptHash: this.assetScriptHash, }); diff --git a/packages/neo-one-node-core/src/Nep5Transfer.ts b/packages/neo-one-node-core/src/Nep17Transfer.ts similarity index 84% rename from packages/neo-one-node-core/src/Nep5Transfer.ts rename to packages/neo-one-node-core/src/Nep17Transfer.ts index 4986c1be50..390d80aba1 100644 --- a/packages/neo-one-node-core/src/Nep5Transfer.ts +++ b/packages/neo-one-node-core/src/Nep17Transfer.ts @@ -1,17 +1,17 @@ -import { createSerializeWire, IOHelper, Nep5TransferModel, UInt160, UInt256 } from '@neo-one/client-common'; +import { createSerializeWire, IOHelper, Nep17TransferModel, UInt160, UInt256 } from '@neo-one/client-common'; import { BN } from 'bn.js'; import { DeserializeWireBaseOptions, DeserializeWireOptions } from './Serializable'; import { BinaryReader, utils } from './utils'; -export interface Nep5TransferAdd { +export interface Nep17TransferAdd { readonly userScriptHash: UInt160; readonly blockIndex: number; readonly txHash: UInt256; readonly amountBuffer: Buffer; } -export class Nep5Transfer extends Nep5TransferModel { - public static deserializeWireBase(options: DeserializeWireBaseOptions): Nep5Transfer { +export class Nep17Transfer extends Nep17TransferModel { + public static deserializeWireBase(options: DeserializeWireBaseOptions): Nep17Transfer { const { reader } = options; const userScriptHash = reader.readUInt160(); const blockIndex = reader.readUInt32LE(); @@ -26,7 +26,7 @@ export class Nep5Transfer extends Nep5TransferModel { }); } - public static deserializeWire(options: DeserializeWireOptions): Nep5Transfer { + public static deserializeWire(options: DeserializeWireOptions): Nep17Transfer { return this.deserializeWireBase({ context: options.context, reader: new BinaryReader(options.buffer), @@ -51,7 +51,7 @@ export class Nep5Transfer extends Nep5TransferModel { } public clone() { - return new Nep5Transfer({ + return new Nep17Transfer({ userScriptHash: this.userScriptHash, blockIndex: this.blockIndex, txHash: this.txHash, diff --git a/packages/neo-one-node-core/src/Nep5TransferKey.ts b/packages/neo-one-node-core/src/Nep17TransferKey.ts similarity index 83% rename from packages/neo-one-node-core/src/Nep5TransferKey.ts rename to packages/neo-one-node-core/src/Nep17TransferKey.ts index 012cc9ec5e..072746f4a9 100644 --- a/packages/neo-one-node-core/src/Nep5TransferKey.ts +++ b/packages/neo-one-node-core/src/Nep17TransferKey.ts @@ -1,17 +1,17 @@ -import { createSerializeWire, IOHelper, Nep5TransferKeyModel, UInt160 } from '@neo-one/client-common'; +import { createSerializeWire, IOHelper, Nep17TransferKeyModel, UInt160 } from '@neo-one/client-common'; import { BN } from 'bn.js'; import { DeserializeWireBaseOptions, DeserializeWireOptions } from './Serializable'; import { BinaryReader, utils } from './utils'; -export interface Nep5TransferKeyAdd { +export interface Nep17TransferKeyAdd { readonly userScriptHash: UInt160; readonly timestampMS: BN; readonly assetScriptHash: UInt160; readonly blockTransferNotificationIndex: number; } -export class Nep5TransferKey extends Nep5TransferKeyModel { - public static deserializeWireBase(options: DeserializeWireBaseOptions): Nep5TransferKey { +export class Nep17TransferKey extends Nep17TransferKeyModel { + public static deserializeWireBase(options: DeserializeWireBaseOptions): Nep17TransferKey { const { reader } = options; const userScriptHash = reader.readUInt160(); const timestampMS = reader.readUInt64LE(); @@ -26,7 +26,7 @@ export class Nep5TransferKey extends Nep5TransferKeyModel { }); } - public static deserializeWire(options: DeserializeWireOptions): Nep5TransferKey { + public static deserializeWire(options: DeserializeWireOptions): Nep17TransferKey { return this.deserializeWireBase({ context: options.context, reader: new BinaryReader(options.buffer), @@ -43,7 +43,7 @@ export class Nep5TransferKey extends Nep5TransferKeyModel { } public clone() { - return new Nep5TransferKey({ + return new Nep17TransferKey({ userScriptHash: this.userScriptHash, timestampMS: this.timestampMS, assetScriptHash: this.assetScriptHash, diff --git a/packages/neo-one-node-core/src/Storage.ts b/packages/neo-one-node-core/src/Storage.ts index 8f55036282..8f8c1c5cb8 100644 --- a/packages/neo-one-node-core/src/Storage.ts +++ b/packages/neo-one-node-core/src/Storage.ts @@ -1,15 +1,14 @@ import { ApplicationLogJSON } from '@neo-one/client-common'; import { Observable } from 'rxjs'; import { ApplicationLog } from './ApplicationLog'; -import { ConsensusContext } from './consensus'; import { ContractIDState } from './ContractIDState'; import { ContractKey, ContractState } from './ContractState'; import { HashIndexState } from './HashIndexState'; import { HeaderHashList, HeaderKey } from './HeaderHashList'; -import { Nep5Balance } from './Nep5Balance'; -import { Nep5BalanceKey } from './Nep5BalanceKey'; -import { Nep5Transfer } from './Nep5Transfer'; -import { Nep5TransferKey } from './Nep5TransferKey'; +import { Nep17Balance } from './Nep17Balance'; +import { Nep17BalanceKey } from './Nep17BalanceKey'; +import { Nep17Transfer } from './Nep17Transfer'; +import { Nep17TransferKey } from './Nep17TransferKey'; import { StorageItem } from './StorageItem'; import { StorageKey } from './StorageKey'; import { TransactionKey, TransactionState } from './transaction'; @@ -110,15 +109,15 @@ export type AddChange = | { readonly type: 'blockHashIndex'; readonly value: HashIndexState } | { readonly type: 'headerHashIndex'; readonly value: HashIndexState } | { readonly type: 'contractID'; readonly value: ContractIDState } - | { readonly type: 'nep5Balance'; readonly key: Nep5BalanceKey; readonly value: Nep5Balance } - | { readonly type: 'nep5TransferSent'; readonly key: Nep5TransferKey; readonly value: Nep5Transfer } - | { readonly type: 'nep5TransferReceived'; readonly key: Nep5TransferKey; readonly value: Nep5Transfer } + | { readonly type: 'nep17Balance'; readonly key: Nep17BalanceKey; readonly value: Nep17Balance } + | { readonly type: 'nep17TransferSent'; readonly key: Nep17TransferKey; readonly value: Nep17Transfer } + | { readonly type: 'nep17TransferReceived'; readonly key: Nep17TransferKey; readonly value: Nep17Transfer } | { readonly type: 'applicationLog'; readonly key: TransactionKey; readonly value: ApplicationLog }; export type DeleteChange = | { readonly type: 'contract'; readonly key: ContractKey } | { readonly type: 'storage'; readonly key: StorageKey } - | { readonly type: 'nep5Balance'; readonly key: Nep5BalanceKey }; + | { readonly type: 'nep17Balance'; readonly key: Nep17BalanceKey }; export type Change = | { readonly type: 'add'; readonly change: AddChange; readonly subType: 'add' | 'update' } @@ -128,9 +127,9 @@ export type ChangeSet = readonly Change[]; export interface BlockchainStorage { readonly blocks: ReadStorage; - readonly nep5Balances: ReadAllFindStorage; - readonly nep5TransfersSent: ReadFindStorage; - readonly nep5TransfersReceived: ReadFindStorage; + readonly nep17Balances: ReadAllFindStorage; + readonly nep17TransfersSent: ReadFindStorage; + readonly nep17TransfersReceived: ReadFindStorage; readonly applicationLogs: ReadStorage; // readonly consensusState: ReadMetadataStorage; readonly transactions: ReadStorage; diff --git a/packages/neo-one-node-core/src/index.ts b/packages/neo-one-node-core/src/index.ts index 040a19d6ec..c5e82c416c 100644 --- a/packages/neo-one-node-core/src/index.ts +++ b/packages/neo-one-node-core/src/index.ts @@ -37,8 +37,8 @@ export * from './Witness'; export * from './CallFlags'; export * from './TransactionData'; export * from './Node'; -export * from './Nep5Balance'; -export * from './Nep5Transfer'; -export * from './Nep5BalanceKey'; -export * from './Nep5TransferKey'; +export * from './Nep17Balance'; +export * from './Nep17Transfer'; +export * from './Nep17BalanceKey'; +export * from './Nep17TransferKey'; export * from './ApplicationLog'; diff --git a/packages/neo-one-node-rpc-handler/src/createHandler.ts b/packages/neo-one-node-rpc-handler/src/createHandler.ts index 3c07c426cb..40ec10568e 100644 --- a/packages/neo-one-node-rpc-handler/src/createHandler.ts +++ b/packages/neo-one-node-rpc-handler/src/createHandler.ts @@ -19,8 +19,8 @@ import { CallReceipt, getEndpointConfig, NativeContainer, - Nep5Transfer, - Nep5TransferKey, + Nep17Transfer, + Nep17TransferKey, Node, Signers, StackItem, @@ -113,9 +113,9 @@ const RPC_METHODS: { readonly [key: string]: string } = { sendmany: 'sendmany', sendtoaddress: 'sendtoaddress', - // NEP5 - getnep5transfers: 'getnep5transfers', - getnep5balances: 'getnep5balances', + // NEP17 + getnep17transfers: 'getnep17transfers', + getnep17balances: 'getnep17balances', // TODO: I want to say both of these can be removed since you can make changes to policy contract storage updatesettings: 'updatesettings', @@ -140,7 +140,7 @@ const RPC_METHODS: { readonly [key: string]: string } = { INVALID: 'INVALID', }; -const mapToTransfers = ({ key, value }: { readonly key: Nep5TransferKey; readonly value: Nep5Transfer }) => ({ +const mapToTransfers = ({ key, value }: { readonly key: Nep17TransferKey; readonly value: Nep17Transfer }) => ({ timestamp: key.timestampMS.toNumber(), assethash: common.uInt160ToString(key.assetScriptHash), transferaddress: scriptHashToAddress(common.uInt160ToString(value.userScriptHash)), @@ -659,8 +659,8 @@ export const createHandler = ({ throw new JSONRPCError(-101, 'Not implemented'); }, - // Nep5 - [RPC_METHODS.getnep5transfers]: async (args) => { + // Nep17 + [RPC_METHODS.getnep17transfers]: async (args) => { const addressVersion = blockchain.settings.addressVersion; const { address, scriptHash } = getScriptHashAndAddress(args[0], addressVersion); @@ -678,11 +678,11 @@ export const createHandler = ({ const gte = Buffer.concat([scriptHash, startTimeBytes]); const lte = Buffer.concat([scriptHash, endTimeBytes]); - const sentPromise = blockchain.nep5TransfersSent + const sentPromise = blockchain.nep17TransfersSent .find$(gte, lte) .pipe(take(1000), map(mapToTransfers), toArray()) .toPromise(); - const receivedPromise = blockchain.nep5TransfersReceived + const receivedPromise = blockchain.nep17TransfersReceived .find$(gte, lte) .pipe(take(1000), map(mapToTransfers), toArray()) .toPromise(); @@ -695,10 +695,10 @@ export const createHandler = ({ address, }; }, - [RPC_METHODS.getnep5balances]: async (args) => { + [RPC_METHODS.getnep17balances]: async (args) => { const addressVersion = blockchain.settings.addressVersion; const { address, scriptHash } = getScriptHashAndAddress(args[0], addressVersion); - const storedBalances = await blockchain.nep5Balances.find$(scriptHash).pipe(toArray()).toPromise(); + const storedBalances = await blockchain.nep17Balances.find$(scriptHash).pipe(toArray()).toPromise(); const validBalances = await Promise.all( storedBalances.map(async ({ key, value }) => { const assetStillExists = await native.Management.getContract( diff --git a/packages/neo-one-node-storage-common/src/keys.ts b/packages/neo-one-node-storage-common/src/keys.ts index 94986eb14b..4bc05d799e 100644 --- a/packages/neo-one-node-storage-common/src/keys.ts +++ b/packages/neo-one-node-storage-common/src/keys.ts @@ -1,5 +1,5 @@ import { common, InvalidFormatError, UInt160, UInt256 } from '@neo-one/client-common'; -import { BlockKey, Nep5BalanceKey, Nep5TransferKey, StorageKey, StreamOptions } from '@neo-one/node-core'; +import { BlockKey, Nep17BalanceKey, Nep17TransferKey, StorageKey, StreamOptions } from '@neo-one/node-core'; import { BN } from 'bn.js'; export enum Prefix { @@ -12,9 +12,9 @@ export enum Prefix { CurrentHeader = 0xc1, ContractID = 0xc2, ConsensusState = 0xf4, - Nep5Balance = 0xf8, - Nep5TransferSent = 0xf9, - Nep5TransferReceived = 0xfa, + Nep17Balance = 0xf8, + Nep17TransferSent = 0xf9, + Nep17TransferReceived = 0xfa, ApplicationLog = 0xfb, // Custom internal prefix. Can be changed. // NEO•ONE prefix, watch out for future collisions with https://github.com/neo-project/neo/blob/master/src/neo/Persistence/Prefixes.cs @@ -101,19 +101,19 @@ const createStorageKey = getCreateKey({ prefix: Prefix.Storage, }); -const createNep5BalanceKey = getCreateKey({ +const createNep17BalanceKey = getCreateKey({ serializeKey: (key) => key.serializeWire(), - prefix: Prefix.Nep5Balance, + prefix: Prefix.Nep17Balance, }); -const createNep5TransferSentKey = getCreateKey({ +const createNep17TransferSentKey = getCreateKey({ serializeKey: (key) => key.serializeWire(), - prefix: Prefix.Nep5TransferSent, + prefix: Prefix.Nep17TransferSent, }); -const createNep5TransferReceivedKey = getCreateKey({ +const createNep17TransferReceivedKey = getCreateKey({ serializeKey: (key) => key.serializeWire(), - prefix: Prefix.Nep5TransferReceived, + prefix: Prefix.Nep17TransferReceived, }); const createHeaderHashListKey = getCreateKey({ @@ -142,14 +142,14 @@ const maxBlockKey = createBlockKey({ hashOrIndex: common.MAX_UINT256 }); const getStorageSearchRange = createGetSearchRange(Prefix.Storage); -const getAllNep5BalanceSearchRange = { - gte: Buffer.from([Prefix.Nep5Balance]), - lte: Buffer.from([Prefix.Nep5TransferSent]), +const getAllNep17BalanceSearchRange = { + gte: Buffer.from([Prefix.Nep17Balance]), + lte: Buffer.from([Prefix.Nep17TransferSent]), }; -const getNep5BalanceSearchRange = createGetSearchRange(Prefix.Nep5Balance); -const getNep5TransferReceivedSearchRange = createGetSearchRange(Prefix.Nep5TransferReceived); -const getNep5TransferSentSearchRange = createGetSearchRange(Prefix.Nep5TransferSent); +const getNep17BalanceSearchRange = createGetSearchRange(Prefix.Nep17Balance); +const getNep17TransferReceivedSearchRange = createGetSearchRange(Prefix.Nep17TransferReceived); +const getNep17TransferSentSearchRange = createGetSearchRange(Prefix.Nep17TransferSent); const createApplicationLogKey = getCreateKey({ serializeKey: (key) => key, @@ -158,18 +158,18 @@ const createApplicationLogKey = getCreateKey({ export const keys = { createBlockKey, - createNep5BalanceKey, - createNep5TransferSentKey, - createNep5TransferReceivedKey, + createNep17BalanceKey, + createNep17TransferSentKey, + createNep17TransferReceivedKey, createApplicationLogKey, createTransactionKey, createContractKey, createStorageKey, getStorageSearchRange, - getNep5BalanceSearchRange, - getAllNep5BalanceSearchRange, - getNep5TransferReceivedSearchRange, - getNep5TransferSentSearchRange, + getNep17BalanceSearchRange, + getAllNep17BalanceSearchRange, + getNep17TransferReceivedSearchRange, + getNep17TransferSentSearchRange, createHeaderHashListKey, blockHashIndexKey, headerHashIndexKey, diff --git a/packages/neo-one-node-storage-levelup/src/__tests__/levelUpStorage.test.ts b/packages/neo-one-node-storage-levelup/src/__tests__/levelUpStorage.test.ts index f12af4ca80..32c0dac66d 100644 --- a/packages/neo-one-node-storage-levelup/src/__tests__/levelUpStorage.test.ts +++ b/packages/neo-one-node-storage-levelup/src/__tests__/levelUpStorage.test.ts @@ -2,8 +2,8 @@ import { common } from '@neo-one/client-common'; import { AddChange, DeleteChange, - Nep5Balance, - Nep5BalanceKey, + Nep17Balance, + Nep17BalanceKey, Storage, StorageItem, StorageKey, @@ -16,7 +16,7 @@ import { storage as levelUpStorage } from '../'; describe('levelUpStorage', () => { let storage: Storage; beforeEach(async () => { - storage = levelUpStorage({ db: LevelUp(MemDown()), context: { messageMagic: 1953787457 } }); + storage = levelUpStorage({ db: LevelUp(MemDown()), context: { messageMagic: 1953787457, validatorsCount: 7 } }); }); test('deleted items are undefined', async () => { const hash = common.bufferToUInt160(Buffer.from('3775292229eccdf904f16fff8e83e7cffdc0f0ce', 'hex')); @@ -51,23 +51,23 @@ describe('levelUpStorage', () => { expect(thirdGet).toEqual(undefined); }); - test('Can add and retrieve Nep5Balance', async () => { - const value = new Nep5Balance({ balanceBuffer: new BN(10).toBuffer('le'), lastUpdatedBlock: 1 }); - const key = new Nep5BalanceKey({ + test('Can add and retrieve Nep17Balance', async () => { + const value = new Nep17Balance({ balanceBuffer: new BN(10).toBuffer('le'), lastUpdatedBlock: 1 }); + const key = new Nep17BalanceKey({ userScriptHash: common.bufferToUInt160(Buffer.from('3775292229eccdf904f16fff8e83e7cffdc0f0ce', 'hex')), assetScriptHash: common.bufferToUInt160(Buffer.from('3775292229eccdf904f16fff8e83e7cffdc0f0ce', 'hex')), }); const addChange: AddChange = { - type: 'nep5Balance', + type: 'nep17Balance', key, value, }; - const firstGet = await storage.nep5Balances.tryGet(key); + const firstGet = await storage.nep17Balances.tryGet(key); expect(firstGet).toBeUndefined(); await storage.commit([{ type: 'add', change: addChange, subType: 'add' }]); - const secondGet = await storage.nep5Balances.tryGet(key); + const secondGet = await storage.nep17Balances.tryGet(key); expect(secondGet).toBeDefined(); expect(secondGet?.balance.toString()).toEqual('10'); expect(secondGet?.lastUpdatedBlock).toEqual(1); diff --git a/packages/neo-one-node-storage-levelup/src/convertChange.ts b/packages/neo-one-node-storage-levelup/src/convertChange.ts index d02fbfa2b5..affc29c401 100644 --- a/packages/neo-one-node-storage-levelup/src/convertChange.ts +++ b/packages/neo-one-node-storage-levelup/src/convertChange.ts @@ -12,29 +12,29 @@ import { UnknownChangeTypeError, UnknownTypeError } from './errors'; const convertAddChange = (change: AddChange): readonly PutBatch[] => { switch (change.type) { - case 'nep5Balance': + case 'nep17Balance': return [ { type: 'put', - key: keys.createNep5BalanceKey(change.key), + key: keys.createNep17BalanceKey(change.key), value: change.value.serializeWire(), }, ]; - case 'nep5TransferReceived': + case 'nep17TransferReceived': return [ { type: 'put', - key: keys.createNep5TransferReceivedKey(change.key), + key: keys.createNep17TransferReceivedKey(change.key), value: change.value.serializeWire(), }, ]; - case 'nep5TransferSent': + case 'nep17TransferSent': return [ { type: 'put', - key: keys.createNep5TransferSentKey(change.key), + key: keys.createNep17TransferSentKey(change.key), value: change.value.serializeWire(), }, ]; @@ -140,10 +140,10 @@ const convertDeleteChange = (change: DeleteChange): DelBatch => { key: keys.createStorageKey(change.key), }; - case 'nep5Balance': + case 'nep17Balance': return { type: 'del', - key: keys.createNep5BalanceKey(change.key), + key: keys.createNep17BalanceKey(change.key), }; default: diff --git a/packages/neo-one-node-storage-levelup/src/levelUpStorage.ts b/packages/neo-one-node-storage-levelup/src/levelUpStorage.ts index 3d14a4f9a0..3ad334f426 100644 --- a/packages/neo-one-node-storage-levelup/src/levelUpStorage.ts +++ b/packages/neo-one-node-storage-levelup/src/levelUpStorage.ts @@ -9,10 +9,10 @@ import { HashIndexState, HeaderHashList, // TransactionData, - Nep5Balance, - Nep5BalanceKey, - Nep5Transfer, - Nep5TransferKey, + Nep17Balance, + Nep17BalanceKey, + Nep17Transfer, + Nep17TransferKey, Storage, StorageItem, StorageKey, @@ -86,41 +86,41 @@ export const levelUpStorage = ({ db, context }: LevelUpStorageOptions): Storage return { blocks, - nep5Balances: read.createReadAllFindStorage({ + nep17Balances: read.createReadAllFindStorage({ db, - searchRange: keys.getAllNep5BalanceSearchRange, - getSearchRange: keys.getNep5BalanceSearchRange, - serializeKey: keys.createNep5BalanceKey, + searchRange: keys.getAllNep17BalanceSearchRange, + getSearchRange: keys.getNep17BalanceSearchRange, + serializeKey: keys.createNep17BalanceKey, deserializeValue: (buffer) => - Nep5Balance.deserializeWire({ + Nep17Balance.deserializeWire({ context, buffer, }), - deserializeKey: (buffer) => Nep5BalanceKey.deserializeWire({ context, buffer }), + deserializeKey: (buffer) => Nep17BalanceKey.deserializeWire({ context, buffer }), }), - nep5TransfersReceived: read.createReadFindStorage({ + nep17TransfersReceived: read.createReadFindStorage({ db, - getSearchRange: keys.getNep5TransferReceivedSearchRange, - serializeKey: keys.createNep5TransferReceivedKey, + getSearchRange: keys.getNep17TransferReceivedSearchRange, + serializeKey: keys.createNep17TransferReceivedKey, deserializeValue: (buffer) => - Nep5Transfer.deserializeWire({ + Nep17Transfer.deserializeWire({ context, buffer, }), - deserializeKey: (buffer) => Nep5TransferKey.deserializeWire({ context, buffer }), + deserializeKey: (buffer) => Nep17TransferKey.deserializeWire({ context, buffer }), }), - nep5TransfersSent: read.createReadFindStorage({ + nep17TransfersSent: read.createReadFindStorage({ db, - getSearchRange: keys.getNep5TransferSentSearchRange, - serializeKey: keys.createNep5TransferSentKey, + getSearchRange: keys.getNep17TransferSentSearchRange, + serializeKey: keys.createNep17TransferSentKey, deserializeValue: (buffer) => - Nep5Transfer.deserializeWire({ + Nep17Transfer.deserializeWire({ context, buffer, }), - deserializeKey: (buffer) => Nep5TransferKey.deserializeWire({ context, buffer }), + deserializeKey: (buffer) => Nep17TransferKey.deserializeWire({ context, buffer }), }), applicationLogs: read.createReadStorage({ diff --git a/packages/neo-one-smart-contract-codegen/src/__data__/index.ts b/packages/neo-one-smart-contract-codegen/src/__data__/index.ts index b2518440ff..fda1c47f64 100644 --- a/packages/neo-one-smart-contract-codegen/src/__data__/index.ts +++ b/packages/neo-one-smart-contract-codegen/src/__data__/index.ts @@ -1,3 +1,3 @@ -export * from './nep5'; +export * from './nep17'; export * from './testUtils'; export * from './abiFactory'; diff --git a/packages/neo-one-smart-contract-codegen/src/__data__/nep5.ts b/packages/neo-one-smart-contract-codegen/src/__data__/nep17.ts similarity index 99% rename from packages/neo-one-smart-contract-codegen/src/__data__/nep5.ts rename to packages/neo-one-smart-contract-codegen/src/__data__/nep17.ts index 8a360e73e0..6c0cd28fd0 100644 --- a/packages/neo-one-smart-contract-codegen/src/__data__/nep5.ts +++ b/packages/neo-one-smart-contract-codegen/src/__data__/nep17.ts @@ -155,6 +155,6 @@ const abi = (decimals: number): ABI => ({ ], }); -export const nep5 = { +export const nep17 = { abi, }; diff --git a/packages/neo-one-smart-contract-codegen/src/__tests__/abi/genABI.test.ts b/packages/neo-one-smart-contract-codegen/src/__tests__/abi/genABI.test.ts index 9496598a99..d4c039bfa3 100644 --- a/packages/neo-one-smart-contract-codegen/src/__tests__/abi/genABI.test.ts +++ b/packages/neo-one-smart-contract-codegen/src/__tests__/abi/genABI.test.ts @@ -1,8 +1,8 @@ -import { nep5 } from '@neo-one/client-core'; +import { nep17 } from '@neo-one/client-core'; import { genABI } from '../../abi'; describe('genABI', () => { - test('NEP5', () => { - expect(genABI('Token', nep5.abi(4))).toMatchSnapshot(); + test('NEP17', () => { + expect(genABI('Token', nep17.abi(4))).toMatchSnapshot(); }); }); diff --git a/packages/neo-one-smart-contract-codegen/src/__tests__/genFiles.test.ts b/packages/neo-one-smart-contract-codegen/src/__tests__/genFiles.test.ts index 303ae71c31..ffabfe3045 100644 --- a/packages/neo-one-smart-contract-codegen/src/__tests__/genFiles.test.ts +++ b/packages/neo-one-smart-contract-codegen/src/__tests__/genFiles.test.ts @@ -1,4 +1,4 @@ -import { nep5 } from '../__data__'; +import { nep17 } from '../__data__'; import { genFiles } from '../genFiles'; describe('genFiles', () => { @@ -11,7 +11,7 @@ describe('genFiles', () => { typesPath: '/foo/bar/one/generated/Token/types.js', abiPath: '/foo/bar/one/generated/Token/abi.js', sourceMapsPath: '/foo/bar/one/generated/sourceMaps.js', - abi: nep5.abi(4), + abi: nep17.abi(4), networksDefinition: { main: { address: 'iamahash', diff --git a/packages/neo-one-smart-contract-codegen/src/__tests__/types/genSmartContractTypes.test.ts b/packages/neo-one-smart-contract-codegen/src/__tests__/types/genSmartContractTypes.test.ts index 5c242089b1..2de1eaed02 100644 --- a/packages/neo-one-smart-contract-codegen/src/__tests__/types/genSmartContractTypes.test.ts +++ b/packages/neo-one-smart-contract-codegen/src/__tests__/types/genSmartContractTypes.test.ts @@ -1,8 +1,8 @@ -import { nep5 } from '../../__data__'; +import { nep17 } from '../../__data__'; import { genSmartContractTypes } from '../../types'; describe('genSmartContractTypes', () => { - test('NEP5', () => { - expect(genSmartContractTypes('Token', nep5.abi(4))).toMatchSnapshot(); + test('NEP17', () => { + expect(genSmartContractTypes('Token', nep17.abi(4))).toMatchSnapshot(); }); }); diff --git a/packages/neo-one-smart-contract-lib/src/NEP5Token.ts b/packages/neo-one-smart-contract-lib/src/NEP17Token.ts similarity index 96% rename from packages/neo-one-smart-contract-lib/src/NEP5Token.ts rename to packages/neo-one-smart-contract-lib/src/NEP17Token.ts index 4e5ace966c..3891f7455e 100644 --- a/packages/neo-one-smart-contract-lib/src/NEP5Token.ts +++ b/packages/neo-one-smart-contract-lib/src/NEP17Token.ts @@ -14,8 +14,8 @@ interface TokenPayableContract { readonly onRevokeSendTransfer: (from: Address, amount: Fixed<0>, asset: Address) => void; } -export function NEP5Token>(Base: TBase) { - abstract class NEP5TokenClass extends Base { +export function NEP17Token>(Base: TBase) { + abstract class NEP17TokenClass extends Base { public abstract readonly name: string; public abstract readonly decimals: 8; public abstract readonly symbol: string; @@ -167,5 +167,5 @@ export function NEP5Token>(Base: TBase) } } - return NEP5TokenClass; + return NEP17TokenClass; } diff --git a/packages/neo-one-smart-contract-lib/src/index.ts b/packages/neo-one-smart-contract-lib/src/index.ts index e9d2e88062..f8aab60bc2 100644 --- a/packages/neo-one-smart-contract-lib/src/index.ts +++ b/packages/neo-one-smart-contract-lib/src/index.ts @@ -1,3 +1,3 @@ -export { NEP5Token } from './NEP5Token'; +export { NEP17Token } from './NEP17Token'; export { Ownable, Secondary } from './ownership'; export { ICO } from './ICO'; diff --git a/packages/neo-one-smart-contract-lib/tsconfig.json b/packages/neo-one-smart-contract-lib/tsconfig.json index f8773d3b9a..97e12e3fb6 100644 --- a/packages/neo-one-smart-contract-lib/tsconfig.json +++ b/packages/neo-one-smart-contract-lib/tsconfig.json @@ -24,5 +24,5 @@ "noFallthroughCasesInSwitch": true, "forceConsistentCasingInFileNames": true }, - "exclude": ["./src/index.ts", "./src/ownership/*.ts", "./src/ICO.ts", "./src/NEP5Token.ts"] + "exclude": ["./src/index.ts", "./src/ownership/*.ts", "./src/ICO.ts", "src/NEP17Token.ts"] } diff --git a/packages/neo-one-smart-contract-test/src/__data__/contracts/SimpleToken.ts b/packages/neo-one-smart-contract-test/src/__data__/contracts/SimpleToken.ts index a862c8558c..4f553204cf 100644 --- a/packages/neo-one-smart-contract-test/src/__data__/contracts/SimpleToken.ts +++ b/packages/neo-one-smart-contract-test/src/__data__/contracts/SimpleToken.ts @@ -1,7 +1,7 @@ import { Address, Fixed, SmartContract } from '@neo-one/smart-contract'; -import { NEP5Token } from '@neo-one/smart-contract-lib'; +import { NEP17Token } from '@neo-one/smart-contract-lib'; -export abstract class SimpleToken extends NEP5Token(SmartContract) { +export abstract class SimpleToken extends NEP17Token(SmartContract) { public readonly owner: Address; public readonly decimals: 8 = 8; diff --git a/packages/neo-one-smart-contract-test/src/__data__/contracts/TestICO.ts b/packages/neo-one-smart-contract-test/src/__data__/contracts/TestICO.ts index f1ab27e9c8..b53fdcf622 100644 --- a/packages/neo-one-smart-contract-test/src/__data__/contracts/TestICO.ts +++ b/packages/neo-one-smart-contract-test/src/__data__/contracts/TestICO.ts @@ -1,7 +1,7 @@ import { Address, Fixed, Integer, SmartContract } from '@neo-one/smart-contract'; -import { ICO, NEP5Token } from '@neo-one/smart-contract-lib'; +import { ICO, NEP17Token } from '@neo-one/smart-contract-lib'; -export class TestICO extends ICO(NEP5Token(SmartContract)) { +export class TestICO extends ICO(NEP17Token(SmartContract)) { public readonly name: string = 'TestToken'; public readonly decimals: 8 = 8; public readonly symbol: string = 'TT'; diff --git a/packages/neo-one-smart-contract-test/src/__data__/contracts/TestToken.ts b/packages/neo-one-smart-contract-test/src/__data__/contracts/TestToken.ts index 3888140ac7..a8c7c8b077 100644 --- a/packages/neo-one-smart-contract-test/src/__data__/contracts/TestToken.ts +++ b/packages/neo-one-smart-contract-test/src/__data__/contracts/TestToken.ts @@ -1,7 +1,7 @@ import { Address, SmartContract } from '@neo-one/smart-contract'; -import { NEP5Token } from '@neo-one/smart-contract-lib'; +import { NEP17Token } from '@neo-one/smart-contract-lib'; -export class TestToken extends NEP5Token(SmartContract) { +export class TestToken extends NEP17Token(SmartContract) { public readonly owner: Address; public readonly name: string = 'TestToken'; public readonly decimals: 8 = 8; diff --git a/packages/neo-one-website/docs/4-contributing/1-codebase-overview.md b/packages/neo-one-website/docs/4-contributing/1-codebase-overview.md index 02f6174339..313678f993 100644 --- a/packages/neo-one-website/docs/4-contributing/1-codebase-overview.md +++ b/packages/neo-one-website/docs/4-contributing/1-codebase-overview.md @@ -158,7 +158,7 @@ Creates the environment for compiling smart contracts, which is then used in the ### neo-one-smart-contract-lib -Defines NEP5 tokens and ICOs. +Defines NEP17 tokens and ICOs. ### neo-one-smart-contract-test From e2179158334ddd2e0d1672fabe0a1f3cfcada948 Mon Sep 17 00:00:00 2001 From: Daniel Byrne Date: Thu, 14 Jan 2021 11:36:16 -0800 Subject: [PATCH 5/7] fix(sc): re-organize 'ContractState' to match preview4 --- .../src/models/ContractStateModel.ts | 2 +- packages/neo-one-node-core/src/ContractState.ts | 11 ++++++++++- .../src/manifest/ContractManifest.ts | 9 +-------- 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/packages/neo-one-client-full-common/src/models/ContractStateModel.ts b/packages/neo-one-client-full-common/src/models/ContractStateModel.ts index b2d5c6e11b..b1dd175ecf 100644 --- a/packages/neo-one-client-full-common/src/models/ContractStateModel.ts +++ b/packages/neo-one-client-full-common/src/models/ContractStateModel.ts @@ -1,5 +1,5 @@ -import { ContractManifestModel } from './manifest'; import { UInt160 } from '@neo-one/client-common'; +import { ContractManifestModel } from './manifest'; export interface ContractStateModelAdd { readonly id: number; diff --git a/packages/neo-one-node-core/src/ContractState.ts b/packages/neo-one-node-core/src/ContractState.ts index 4b2b1e82f9..c496c0c73e 100644 --- a/packages/neo-one-node-core/src/ContractState.ts +++ b/packages/neo-one-node-core/src/ContractState.ts @@ -33,7 +33,12 @@ export class ContractState extends ContractStateModel { } private readonly sizeInternal = utils.lazy( - () => IOHelper.sizeOfUInt32LE + IOHelper.sizeOfVarBytesLE(this.script) + this.manifest.size, + () => + IOHelper.sizeOfUInt32LE + + +IOHelper.sizeOfUInt16LE + + IOHelper.sizeOfUInt160 + + IOHelper.sizeOfVarBytesLE(this.script) + + this.manifest.size, ); public get size() { @@ -50,6 +55,10 @@ export class ContractState extends ContractStateModel { }); } + public canCall(manifest: ContractManifest, method: string) { + return this.manifest.permissions.some((permission) => permission.isAllowed(manifest, method)); + } + public serializeJSON(): ContractJSON { return { id: this.id, diff --git a/packages/neo-one-node-core/src/manifest/ContractManifest.ts b/packages/neo-one-node-core/src/manifest/ContractManifest.ts index 474a90b3c7..ce9b413e00 100644 --- a/packages/neo-one-node-core/src/manifest/ContractManifest.ts +++ b/packages/neo-one-node-core/src/manifest/ContractManifest.ts @@ -8,6 +8,7 @@ import { ContractPermission } from './ContractPermission'; export class ContractManifest extends ContractManifestModel { public static parseBytes(bytes: Buffer) { const reader = new BinaryReader(bytes); + return this.deserializeJSON(JSON.parse(reader.readVarString(this.maxLength))); } @@ -39,15 +40,7 @@ export class ContractManifest extends ContractManifestModel permission.isAllowed(manifest, method)); - } - public isValid(hash: UInt160) { - if (!this.abi.hash.equals(hash)) { - return false; - } - return this.groups.every((group) => group.isValid(hash)); } } From df2cf5a2315f70eb3b135796dda00a3aa2269341 Mon Sep 17 00:00:00 2001 From: Daniel Byrne Date: Thu, 14 Jan 2021 13:55:42 -0800 Subject: [PATCH 6/7] nit(nep17): add note to nep17 implementation to update --- packages/neo-one-client-core/src/nep17.ts | 1 - packages/neo-one-smart-contract-lib/src/NEP17Token.ts | 2 ++ 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/neo-one-client-core/src/nep17.ts b/packages/neo-one-client-core/src/nep17.ts index 7f938ff9aa..3a68367979 100644 --- a/packages/neo-one-client-core/src/nep17.ts +++ b/packages/neo-one-client-core/src/nep17.ts @@ -30,7 +30,6 @@ export interface NEP17TransferEvent extends Event<'transfer', NEP17TransferEvent export interface NEP17SmartContract extends SmartContract { readonly balanceOf: (address: AddressString, options?: SmartContractReadOptions) => Promise; readonly decimals: (options?: SmartContractReadOptions) => Promise; - readonly name: (options?: SmartContractReadOptions) => Promise; readonly owner: (options?: SmartContractReadOptions) => Promise; readonly symbol: (options?: SmartContractReadOptions) => Promise; readonly totalSupply: (options?: SmartContractReadOptions) => Promise; diff --git a/packages/neo-one-smart-contract-lib/src/NEP17Token.ts b/packages/neo-one-smart-contract-lib/src/NEP17Token.ts index 3891f7455e..dd1ad89ccd 100644 --- a/packages/neo-one-smart-contract-lib/src/NEP17Token.ts +++ b/packages/neo-one-smart-contract-lib/src/NEP17Token.ts @@ -14,6 +14,8 @@ interface TokenPayableContract { readonly onRevokeSendTransfer: (from: Address, amount: Fixed<0>, asset: Address) => void; } +// TODO: this whole definition will need to be updated to actually meet the current standard +// see https://github.com/neo-project/proposals/pull/126 export function NEP17Token>(Base: TBase) { abstract class NEP17TokenClass extends Base { public abstract readonly name: string; From 495a95926e226363e07e26b80ffdabb40a3c3d2d Mon Sep 17 00:00:00 2001 From: Daniel Byrne Date: Tue, 19 Jan 2021 13:50:09 -0800 Subject: [PATCH 7/7] fix(bc): fixup headerIndexCache, surprised this didn't come up before --- packages/neo-one-node-blockchain/package.json | 2 + .../src/HeaderIndexCache.ts | 2 +- .../src/__tests__/headerIndexCache.test.ts | 37 +++++++++++++++++++ .../4-contributing/1-codebase-overview.md | 2 +- 4 files changed, 41 insertions(+), 2 deletions(-) create mode 100644 packages/neo-one-node-blockchain/src/__tests__/headerIndexCache.test.ts diff --git a/packages/neo-one-node-blockchain/package.json b/packages/neo-one-node-blockchain/package.json index 1f54a93d5e..051756ad3a 100644 --- a/packages/neo-one-node-blockchain/package.json +++ b/packages/neo-one-node-blockchain/package.json @@ -33,9 +33,11 @@ "@types/leveldown": "^4.0.0", "@types/lodash": "^4.14.138", "@types/lru-cache": "^5.1.0", + "@types/memdown": "^3.0.0", "leveldown": "^5.1.1", "levelup": "4.1.0", "gulp": "~4.0.2", + "memdown": "^5.0.0", "tslib": "^1.10.0" } } diff --git a/packages/neo-one-node-blockchain/src/HeaderIndexCache.ts b/packages/neo-one-node-blockchain/src/HeaderIndexCache.ts index 67635bd4e6..aab6e69817 100644 --- a/packages/neo-one-node-blockchain/src/HeaderIndexCache.ts +++ b/packages/neo-one-node-blockchain/src/HeaderIndexCache.ts @@ -59,7 +59,7 @@ export class HeaderIndexCache { return this.getHeaderHashIndexFromCurrent(hashListHashIndex); } - const hashListIndex = (index - hashListHashIndex) / 2000; + const hashListIndex = index - hashListHashIndex; const headerHashList = await this.getHeaderHashList(hashListIndex); if (headerHashList === undefined) { return undefined; diff --git a/packages/neo-one-node-blockchain/src/__tests__/headerIndexCache.test.ts b/packages/neo-one-node-blockchain/src/__tests__/headerIndexCache.test.ts new file mode 100644 index 0000000000..20535bdfdb --- /dev/null +++ b/packages/neo-one-node-blockchain/src/__tests__/headerIndexCache.test.ts @@ -0,0 +1,37 @@ +// tslint:disable: readonly-keyword no-object-mutation +import { crypto } from '@neo-one/client-common'; +import { Storage } from '@neo-one/node-core'; +import { storage as levelStorage } from '@neo-one/node-storage-levelup'; +import { randomBytes } from 'crypto'; +import LevelUp from 'levelup'; +import _ from 'lodash'; +import MemDown from 'memdown'; +import { HeaderIndexCache } from '../HeaderIndexCache'; + +const getUInt = () => crypto.hash256(randomBytes(32)); +const getUInts = (n: number) => _.range(n).map(getUInt); + +describe('headerIndexCache tests', () => { + const context = { messageMagic: 1951352142, validatorsCount: 7 }; + + let storage: Storage; + let db: any; + beforeEach(() => { + db = new LevelUp(new MemDown()); + storage = levelStorage({ db, context }); + }); + + test('headerCacheIndex push 2500 hashes -- retrieves something from different headerHashLists', async () => { + const cache = new HeaderIndexCache({ storage, initCurrentHeaderHashes: [], initStorageCount: 0 }); + const testHashes = getUInts(2500); + // tslint:disable-next-line: no-loop-statement + for (const hash of testHashes) { + await cache.push(hash); + } + + const [listZeroHash, listTwoThousandHash] = await Promise.all([cache.get(11), cache.get(2005)]); + + expect(listZeroHash.equals(testHashes[11])).toEqual(true); + expect(listTwoThousandHash.equals(testHashes[2005])).toEqual(true); + }); +}); diff --git a/packages/neo-one-website/docs/4-contributing/1-codebase-overview.md b/packages/neo-one-website/docs/4-contributing/1-codebase-overview.md index 313678f993..02f6174339 100644 --- a/packages/neo-one-website/docs/4-contributing/1-codebase-overview.md +++ b/packages/neo-one-website/docs/4-contributing/1-codebase-overview.md @@ -158,7 +158,7 @@ Creates the environment for compiling smart contracts, which is then used in the ### neo-one-smart-contract-lib -Defines NEP17 tokens and ICOs. +Defines NEP5 tokens and ICOs. ### neo-one-smart-contract-test