Commit 8e758af6 authored by Cédric Moreau's avatar Cédric Moreau

[fix] #1030 + begin #1043 refactoring

parent 8401cf5a
......@@ -2,6 +2,7 @@ app/cli.js
app/lib/blockchain/*.js
app/lib/blockchain/interfaces/*.js
app/lib/computation/*.js
app/lib/common-libs/*.js
app/lib/db/*.js
app/lib/dto/*.js
app/lib/indexer.js
......
......@@ -32,6 +32,31 @@ const MAXIMUM_LEN_OF_COMPACT_TX = 100
const MAXIMUM_LEN_OF_OUTPUT = 2000
const MAXIMUM_LEN_OF_UNLOCK = MAXIMUM_LEN_OF_OUTPUT
export enum DuniterDocument {
ENTITY_NULL,
ENTITY_BLOCK,
ENTITY_IDENTITY,
ENTITY_CERTIFICATION,
ENTITY_MEMBERSHIP,
ENTITY_REVOCATION,
ENTITY_TRANSACTION,
ENTITY_PEER
}
export const duniterDocument2str = (type:DuniterDocument) => {
switch (type) {
case DuniterDocument.ENTITY_BLOCK: return "block"
case DuniterDocument.ENTITY_IDENTITY: return "identity"
case DuniterDocument.ENTITY_CERTIFICATION: return "certification"
case DuniterDocument.ENTITY_REVOCATION: return "revocation"
case DuniterDocument.ENTITY_MEMBERSHIP: return "membership"
case DuniterDocument.ENTITY_TRANSACTION: return "transaction"
case DuniterDocument.ENTITY_PEER: return "peer"
default:
return ""
}
}
export const CommonConstants = {
FORMATS: {
......
......@@ -22,7 +22,7 @@ export abstract class GenericParser extends stream.Transform {
}
syncWrite(str:string, logger:any = null): any {
let error;
let error = ""
const obj = {};
this._parse(str, obj);
this._clean(obj);
......@@ -32,7 +32,7 @@ export abstract class GenericParser extends stream.Transform {
if (!error) {
const raw = this.rawerFunc(obj);
if (hashf(str) !== hashf(raw))
error = CommonConstants.ERRORS.WRONG_DOCUMENT;
error = CommonConstants.ERRORS.WRONG_DOCUMENT.uerr.message;
if (error) {
logger && logger.trace(error);
logger && logger.trace('-----------------');
......
......@@ -39,7 +39,6 @@ export class BlockParser extends GenericParser {
}
_clean(obj:any) {
obj.documentType = 'block';
obj.identities = obj.identities || [];
obj.joiners = obj.joiners || [];
obj.actives = obj.actives || [];
......
......@@ -19,7 +19,6 @@ export class CertificationParser extends GenericParser {
}
_clean(obj:any) {
obj.documentType = 'certification';
obj.sig = obj.signature;
obj.block = obj.buid;
if (obj.block) {
......@@ -31,9 +30,9 @@ export class CertificationParser extends GenericParser {
}
}
_verify(obj:any) {
return ["version", "type", "currency", "issuer", "idty_issuer", "idty_sig", "idty_buid", "idty_uid", "block"].reduce(function (p, field) {
return p || (!obj[field] && "Wrong format for certification");
}, null)
_verify(obj:any): string {
return ["version", "type", "currency", "issuer", "idty_issuer", "idty_sig", "idty_buid", "idty_uid", "block"].reduce((p, field) => {
return p || (!obj[field] && "Wrong format for certification") || ""
}, "")
}
}
\ No newline at end of file
......@@ -17,7 +17,6 @@ export class IdentityParser extends GenericParser {
}
_clean(obj:any) {
obj.documentType = 'identity';
obj.sig = obj.signature;
if (obj.uid && obj.buid && obj.pubkey) {
obj.hash = hashf(obj.uid + obj.buid + obj.pubkey).toUpperCase();
......
......@@ -18,7 +18,6 @@ export class MembershipParser extends GenericParser {
}
_clean(obj:any) {
obj.documentType = 'membership';
if (obj.block) {
obj.number = obj.block.split('-')[0];
obj.fpr = obj.block.split('-')[1];
......
......@@ -17,7 +17,6 @@ export class PeerParser extends GenericParser {
}
_clean(obj:any) {
obj.documentType = 'peer';
obj.endpoints = obj.endpoints || [];
// Removes trailing space
if (obj.endpoints.length > 0)
......
......@@ -18,7 +18,6 @@ export class RevocationParser extends GenericParser {
}
_clean(obj:any) {
obj.documentType = 'revocation';
obj.pubkey = obj.issuer;
obj.revocation = obj.signature;
if (obj.uid && obj.buid && obj.pubkey) {
......
......@@ -20,7 +20,6 @@ export class TransactionParser extends GenericParser {
}
_clean(obj:any) {
obj.documentType = 'transaction';
obj.comment = obj.comment || "";
obj.locktime = parseInt(obj.locktime) || 0;
obj.signatures.push(obj.signature);
......
......@@ -488,6 +488,9 @@ export class FileDAL {
async isMember(pubkey:string) {
try {
const idty = await this.iindexDAL.getFromPubkey(pubkey);
if (!idty) {
return false
}
return idty.member;
} catch (err) {
return false;
......
......@@ -2,9 +2,14 @@ import {AbstractSQLite} from "./AbstractSQLite"
import {SQLiteDriver} from "../drivers/SQLiteDriver"
import {SandBox} from "./SandBox"
import {IdentityDTO} from "../../dto/IdentityDTO"
import {Cloneable} from "../../dto/Cloneable";
const constants = require('../../constants');
export abstract class DBIdentity {
export abstract class DBIdentity implements Cloneable {
clone(): any {
return DBIdentity.copyFromExisting(this)
}
certs:any[] = []
signed:any[] = []
......
......@@ -3,8 +3,6 @@ import {AbstractSQLite} from "./AbstractSQLite"
export class DBPeer {
readonly documentType = "peer"
version: number
currency: string
status: string
......
import {TransactionDTO} from "./TransactionDTO"
import {CurrencyConfDTO} from "./ConfDTO"
import {hashf} from "../common"
import {Cloneable} from "./Cloneable";
const DEFAULT_DOCUMENT_VERSION = 10
export class BlockDTO {
export class BlockDTO implements Cloneable {
clone(): any {
return BlockDTO.fromJSONObject(this)
}
version: number
number: number
......@@ -38,8 +43,8 @@ export class BlockDTO {
monetaryMass: number
UDTime: number
constructor(
) {}
constructor() {
}
json() {
return {
......
import {IdentityDTO} from "./IdentityDTO"
import {Buid} from "../common-libs/buid"
import {Cloneable} from "./Cloneable";
const DEFAULT_DOCUMENT_VERSION = 10
......@@ -25,7 +26,11 @@ export class ShortCertificationDTO {
}
}
export class CertificationDTO extends ShortCertificationDTO {
export class CertificationDTO extends ShortCertificationDTO implements Cloneable {
clone(): any {
return CertificationDTO.fromJSONObject(this)
}
constructor(
public version: number,
......
export interface Cloneable {
clone(): any
}
\ No newline at end of file
export interface Jsonable {
json(): any
}
\ No newline at end of file
import {IdentityDTO} from "./IdentityDTO"
import * as moment from "moment"
import {Cloneable} from "./Cloneable";
const DEFAULT_DOCUMENT_VERSION = 10
export class MembershipDTO {
export class MembershipDTO implements Cloneable {
clone(): any {
return MembershipDTO.fromJSONObject(this)
}
sigDate?:number
date?:number
......
import {DBPeer} from "../dal/sqliteDAL/PeerDAL"
import {hashf} from "../common"
import {CommonConstants} from "../common-libs/constants"
import {Cloneable} from "./Cloneable";
export class PeerDTO {
export class PeerDTO implements Cloneable {
clone(): any {
return PeerDTO.fromJSONObject(this)
}
readonly documentType = "peer"
member = false
constructor(
......@@ -164,6 +168,10 @@ export class PeerDTO {
return parseInt(blockstamp)
}
static fromDBPeer(p:DBPeer) {
return new PeerDTO(p.version, p.currency, p.pubkey, p.block, p.endpoints, p.signature, p.status, p.statusTS, false)
}
static fromJSONObject(obj:any) {
return new PeerDTO(
obj.version,
......
import {Cloneable} from "./Cloneable";
const DEFAULT_DOCUMENT_VERSION = 10
export interface ShortRevocation {
......@@ -5,9 +6,11 @@ export interface ShortRevocation {
revocation: string
}
export class RevocationDTO implements ShortRevocation {
export class RevocationDTO implements ShortRevocation, Cloneable {
public readonly documentType = 'revocation'
clone(): any {
return RevocationDTO.fromJSONObject(this)
}
constructor(
public version: number,
......
import {hashf} from "../common"
import {Cloneable} from "./Cloneable";
export interface BaseDTO {
base: number
......@@ -24,7 +25,11 @@ export class OutputDTO implements BaseDTO {
) {}
}
export class TransactionDTO {
export class TransactionDTO implements Cloneable {
clone(): any {
return TransactionDTO.fromJSONObject(this)
}
constructor(
public version: number,
......@@ -58,6 +63,14 @@ export class TransactionDTO {
return this.outputs.reduce((maxBase, output) => Math.max(maxBase, parseInt(output.split(':')[1])), 0)
}
get blockNumber() {
return parseInt(this.blockstamp)
}
get block_hash() {
return this.blockstamp.split('-')[1]
}
getLen() {
return 2 // header + blockstamp
+ this.issuers.length * 2 // issuers + signatures
......
......@@ -3,13 +3,6 @@ export const BMAConstants = {
BMA_PORTS_START: 10901,
BMA_PORTS_END: 10999,
ENTITY_BLOCK: 'block',
ENTITY_IDENTITY: 'identity',
ENTITY_CERTIFICATION: 'certification',
ENTITY_MEMBERSHIP: 'membership',
ENTITY_REVOCATION: 'revocation',
ENTITY_TRANSACTION: 'transaction',
ENTITY_PEER: 'peer',
DEFAULT_PORT: 10901,
IPV4_REGEXP: /^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$/,
IPV6_REGEXP: /^((([0-9A-Fa-f]{1,4}:){7}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){6}:[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){5}:([0-9A-Fa-f]{1,4}:)?[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){4}:([0-9A-Fa-f]{1,4}:){0,2}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){3}:([0-9A-Fa-f]{1,4}:){0,3}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){2}:([0-9A-Fa-f]{1,4}:){0,4}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){6}((b((25[0-5])|(1d{2})|(2[0-4]d)|(d{1,2}))b).){3}(b((25[0-5])|(1d{2})|(2[0-4]d)|(d{1,2}))b))|(([0-9A-Fa-f]{1,4}:){0,5}:((b((25[0-5])|(1d{2})|(2[0-4]d)|(d{1,2}))b).){3}(b((25[0-5])|(1d{2})|(2[0-4]d)|(d{1,2}))b))|(::([0-9A-Fa-f]{1,4}:){0,5}((b((25[0-5])|(1d{2})|(2[0-4]d)|(d{1,2}))b).){3}(b((25[0-5])|(1d{2})|(2[0-4]d)|(d{1,2}))b))|([0-9A-Fa-f]{1,4}::([0-9A-Fa-f]{1,4}:){0,5}[0-9A-Fa-f]{1,4})|(::([0-9A-Fa-f]{1,4}:){0,6}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){1,7}:))$/,
......
import {Server} from "../../../../../server"
import {dos2unix} from "../../../../lib/common-libs/dos2unix"
import {Server} from "../../../../../server";
import {dos2unix} from "../../../../lib/common-libs/dos2unix";
export abstract class AbstractController {
......@@ -30,14 +30,12 @@ export abstract class AbstractController {
return this.server.MerkleService
}
async pushEntity(req:any, rawer:(req:any)=>string, type:any) {
async pushEntity<T>(req:any, rawer:(req:any)=>string, task:(raw:string) => Promise<T>): Promise<T> {
let rawDocument = rawer(req);
rawDocument = dos2unix(rawDocument);
const written = await this.server.writeRaw(rawDocument, type);
try {
return written.json();
return await task(rawDocument)
} catch (e) {
this.logger.error('Written:', written);
this.logger.error(e);
throw e;
}
......
"use strict";
import {Server} from "../../../../../server"
import {AbstractController} from "./AbstractController"
import {ParametersService} from "../parameters"
import {BMAConstants} from "../constants"
import {MembershipDTO} from "../../../../lib/dto/MembershipDTO"
import {Server} from "../../../../../server";
import {AbstractController} from "./AbstractController";
import {ParametersService} from "../parameters";
import {BMAConstants} from "../constants";
import {MembershipDTO} from "../../../../lib/dto/MembershipDTO";
import {HttpMembership} from "../dtos";
const _ = require('underscore');
const http2raw = require('../http2raw');
......@@ -29,9 +30,23 @@ export class BlockchainBinding extends AbstractController {
}
}
parseMembership = (req:any) => this.pushEntity(req, http2raw.membership, BMAConstants.ENTITY_MEMBERSHIP);
async parseMembership(req:any): Promise<HttpMembership> {
const res = await this.pushEntity(req, http2raw.membership, (raw:string) => this.server.writeRawMembership(raw))
return {
signature: res.signature,
membership: {
version: res.version,
currency: res.currency,
issuer: res.issuer,
membership: res.membership,
date: res.date || 0,
sigDate: res.sigDate || 0,
raw: res.getRaw()
}
}
}
parseBlock = (req:any) => this.pushEntity(req, http2raw.block, BMAConstants.ENTITY_BLOCK);
parseBlock = (req:any) => this.pushEntity(req, http2raw.block, (raw:string) => this.server.writeRawBlock(raw))
parameters = () => this.server.dal.getParameters();
......
import {AbstractController} from "./AbstractController"
import {BMAConstants} from "../constants"
import {AbstractController} from "./AbstractController";
import {BMAConstants} from "../constants";
import {HttpPeer} from "../dtos";
const _ = require('underscore');
const http2raw = require('../http2raw');
......@@ -33,8 +34,17 @@ export class NetworkBinding extends AbstractController {
})
}
peersPost(req:any) {
return this.pushEntity(req, http2raw.peer, BMAConstants.ENTITY_PEER)
async peersPost(req:any): Promise<HttpPeer> {
const peerDTO = await this.pushEntity(req, http2raw.peer, (raw:string) => this.server.writeRawPeer(raw))
return {
version: peerDTO.version,
currency: peerDTO.currency,
pubkey: peerDTO.pubkey,
block: peerDTO.blockstamp,
endpoints: peerDTO.endpoints,
signature: peerDTO.signature,
raw: peerDTO.getRaw()
}
}
async peers() {
......
import {AbstractController} from "./AbstractController"
import {ParametersService} from "../parameters"
import {Source} from "../entity/source"
import {BMAConstants} from "../constants"
import {TransactionDTO} from "../../../../lib/dto/TransactionDTO"
import {AbstractController} from "./AbstractController";
import {ParametersService} from "../parameters";
import {Source} from "../entity/source";
import {BMAConstants} from "../constants";
import {TransactionDTO} from "../../../../lib/dto/TransactionDTO";
const _ = require('underscore');
const http2raw = require('../http2raw');
......@@ -10,7 +10,7 @@ const http2raw = require('../http2raw');
export class TransactionBinding extends AbstractController {
parseTransaction(req:any) {
return this.pushEntity(req, http2raw.transaction, BMAConstants.ENTITY_TRANSACTION)
return this.pushEntity(req, http2raw.transaction, (raw:string) => this.server.writeRawTransaction(raw))
}
async getSources(req:any) {
......
import {AbstractController} from "./AbstractController"
import {BMAConstants} from "../constants"
import {DBIdentity} from "../../../../lib/dal/sqliteDAL/IdentityDAL"
import {AbstractController} from "./AbstractController";
import {BMAConstants} from "../constants";
import {DBIdentity} from "../../../../lib/dal/sqliteDAL/IdentityDAL";
import {HttpCert, HttpCertIdentity} from "../dtos";
const _ = require('underscore');
const http2raw = require('../http2raw');
......@@ -215,15 +216,27 @@ export class WOTBinding extends AbstractController {
}
add(req:any) {
return this.pushEntity(req, http2raw.identity, BMAConstants.ENTITY_IDENTITY)
return this.pushEntity(req, http2raw.identity, (raw:string) => this.server.writeRawIdentity(raw))
}
certify(req:any) {
return this.pushEntity(req, http2raw.certification, BMAConstants.ENTITY_CERTIFICATION)
async certify(req:any): Promise<HttpCert> {
const res = await this.pushEntity(req, http2raw.certification, (raw:string) => this.server.writeRawCertification(raw))
const target:HttpCertIdentity = {
issuer: res.idty_issuer,
uid: res.idty_uid,
timestamp: res.idty_buid,
sig: res.idty_sig
}
return {
issuer: res.issuer,
timestamp: res.buid,
sig: res.sig,
target
}
}
revoke(req:any) {
return this.pushEntity(req, http2raw.revocation, BMAConstants.ENTITY_REVOCATION)
return this.pushEntity(req, http2raw.revocation, (raw:string) => this.server.writeRawRevocation(raw))
}
async pendingMemberships() {
......
......@@ -44,6 +44,19 @@ export const Membership = {
}
};
export interface HttpMembership {
signature: string
membership: {
version: number
currency: string
issuer: string
membership: string
date: number
sigDate: number
raw: string
}
}
export const Memberships = {
"pubkey": String,
"uid": String,
......@@ -295,6 +308,13 @@ export const CertIdentity = {
"sig": String
};
export interface HttpCertIdentity {
issuer: string
uid: string
timestamp: string
sig: string
}
export const Cert = {
"issuer": String,
"timestamp": String,
......@@ -302,6 +322,13 @@ export const Cert = {
"target": CertIdentity
};
export interface HttpCert {
issuer: string
timestamp: string
sig: string
target: HttpCertIdentity
}
export const Identity = {
"pubkey": String,
"uids": [UID],
......
......@@ -127,7 +127,7 @@ export class PeerCrawler implements DuniterService {
let p = found[i];
try {
// Try to write it
await server.singleWritePromise(p);
await server.writePeer(p)
} catch(e) {
// Silent error
}
......
......@@ -135,8 +135,7 @@ async function submitMembership(ms:any, to:any, logger:any = null) {
async function submitIdentityToServer(idty:any, toServer:any, logger:any = null) {
try {
const obj = parsers.parseIdentity.syncWrite(idty)
obj.documentType = 'identity'
await toServer.singleWritePromise(obj)
await toServer.writeIdentity(obj)
logger && logger.trace('Sandbox pulling: success with identity \'%s\'', idty.uid)
} catch (e) {
// Silent error
......@@ -146,8 +145,7 @@ async function submitIdentityToServer(idty:any, toServer:any, logger:any = null)
async function submitCertificationToServer(cert:any, toServer:any, logger:any = null) {
try {
const obj = parsers.parseCertification.syncWrite(cert)
obj.documentType = 'certification'
await toServer.singleWritePromise(obj)
await toServer.writeCertification(obj)
logger && logger.trace('Sandbox pulling: success with cert key %s => %s', cert.from.substr(0, 6), cert.idty_uid)
} catch (e) {
// Silent error
......@@ -157,8 +155,7 @@ async function submitCertificationToServer(cert:any, toServer:any, logger:any =
async function submitMembershipToServer(ms:any, toServer:any, logger:any = null) {
try {
const obj = parsers.parseMembership.syncWrite(ms)
obj.documentType = 'membership'
await toServer.singleWritePromise(obj)
await toServer.writeMembership(obj)
logger && logger.trace('Sandbox pulling: success with membership \'%s\'', ms.uid)
} catch (e) {
// Silent error
......
......@@ -163,7 +163,7 @@ export class PermanentProver {
this.lastComputedBlock = await this.generator.makeNextBlock(null, trial2);
try {
const obj = parsers.parseBlock.syncWrite(dos2unix(this.lastComputedBlock.getRawSigned()));
await this.server.singleWritePromise(obj);
await this.server.writeBlock(obj)
} catch (err) {
this.logger.warn('Proof-of-work self-submission: %s', err.message || err);
}
......
......@@ -113,13 +113,13 @@ export class BlockchainService {
return [];
}
submitBlock(obj:any, doCheck:boolean, forkAllowed:boolean) {
submitBlock(obj:any, doCheck:boolean, forkAllowed:boolean): Promise<BlockDTO> {
return GlobalFifoPromise.pushFIFO(() => {