From e59013dfc96fb650349b1b15f9bb2041d329431c Mon Sep 17 00:00:00 2001
From: cgeek <cem.moreau@gmail.com>
Date: Sat, 28 Oct 2017 14:21:48 +0200
Subject: [PATCH] [fix] #1156 Reject transactions with incorrect output scheme

---
 app/lib/common-libs/parsers/transaction.ts |  5 +++
 app/lib/common-libs/txunlock.ts            |  7 +++-
 test/fast/modules/common/grammar-test.js   |  6 +++
 test/integration/documents-currency.ts     | 43 ++++++++++++++++++----
 4 files changed, 52 insertions(+), 9 deletions(-)

diff --git a/app/lib/common-libs/parsers/transaction.ts b/app/lib/common-libs/parsers/transaction.ts
index 01b5e4fb0..6fe526908 100644
--- a/app/lib/common-libs/parsers/transaction.ts
+++ b/app/lib/common-libs/parsers/transaction.ts
@@ -1,6 +1,7 @@
 import {CommonConstants} from "../../../lib/common-libs/constants"
 import {GenericParser} from "./GenericParser"
 import {rawer} from "../../../lib/common-libs/index"
+import { unlock } from '../txunlock';
 
 export class TransactionParser extends GenericParser {
 
@@ -105,6 +106,10 @@ function extractOutputs(raw:string) {
   for (const line of lines) {
     if (line.match(CommonConstants.TRANSACTION.TARGET)) {
       outputs.push(line);
+      const unlocked = unlock(line.split(':')[2], [], {})
+      if (unlocked === null) {
+        throw Error("Wrong output format")
+      }
     } else {
       // Not a transaction input, stop reading
       break;
diff --git a/app/lib/common-libs/txunlock.ts b/app/lib/common-libs/txunlock.ts
index fd156e2b9..f01c2bafe 100644
--- a/app/lib/common-libs/txunlock.ts
+++ b/app/lib/common-libs/txunlock.ts
@@ -44,7 +44,7 @@ let grammar = {
   }
 };
 
-export function unlock(conditionsStr:string, executions:any, metadata:any) {
+export function unlock(conditionsStr:string, executions:any, metadata:any): boolean|null {
 
   let parser = new Parser(grammar);
 
@@ -56,6 +56,9 @@ export function unlock(conditionsStr:string, executions:any, metadata:any) {
     },
     xHx: function(hash:string) {
       let xhxParam = executions[this.i++];
+      if (xhxParam === undefined) {
+        xhxParam = ""
+      }
       return hashf(xhxParam) === hash;
     },
     cltv: function(deadline:string) {
@@ -69,6 +72,6 @@ export function unlock(conditionsStr:string, executions:any, metadata:any) {
   try {
     return parser.parse(conditionsStr);
   } catch(e) {
-    return false;
+    return null;
   }
 }
\ No newline at end of file
diff --git a/test/fast/modules/common/grammar-test.js b/test/fast/modules/common/grammar-test.js
index 72270bf8d..49979860e 100644
--- a/test/fast/modules/common/grammar-test.js
+++ b/test/fast/modules/common/grammar-test.js
@@ -2,6 +2,7 @@
 
 const unlock    = require('../../../../app/lib/common-libs').txunlock
 const should    = require('should');
+const assert    = require('assert');
 
 describe('Grammar', () => {
 
@@ -67,4 +68,9 @@ describe('Grammar', () => {
     unlock('SIG(' + k1 + ') && XHX(' + Ha + ') || XHX(' + Hz + ')', [{ pubkey: k1, sigOK: false },'z','z']).should.equal(true);
     unlock('(SIG(EA7Dsw39ShZg4SpURsrgMaMqrweJPUFPYHwZA8e92e3D) || XHX(03AC674216F3E15C761EE1A5E255F067953623C8B388B4459E13F978D7C846F4))', [{ pubkey: k1, sigOK: false },'1234']).should.equal(true);
   });
+
+  it('Wrong syntax should return `null`', () => {
+
+    assert.equal(unlock('XHX(03AC674216F3E15C761EE1A5E255F067953623C8B388B4459E13F978D7C846F4))', []), null)
+  });
 });
diff --git a/test/integration/documents-currency.ts b/test/integration/documents-currency.ts
index e18173af5..2bffa0b1a 100644
--- a/test/integration/documents-currency.ts
+++ b/test/integration/documents-currency.ts
@@ -1,14 +1,15 @@
-import {NewTestingServer} from "./tools/toolbox"
+import { NewTestingServer } from './tools/toolbox';
 
 const co        = require('co');
 const should    = require('should');
 const user      = require('./tools/user');
-const commit    = require('./tools/commit');
 
 let s1:any, s2:any, cat1:any, tac1:any, toc2:any, tic2:any;
 
 describe("Document pool currency", function() {
 
+  const now = 1500000000
+
   before(() => co(function*() {
 
     s1 = NewTestingServer({
@@ -16,7 +17,10 @@ describe("Document pool currency", function() {
       pair: {
         pub: 'HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd',
         sec: '51w4fEShBk1jCMauWu4mLpmDVfHksKmWcygpxriqCEZizbtERA6de4STKRkQBpxmMUwsKXRjSzuQ8ECwmqN1u2DP'
-      }
+      },
+      udTime0: now - 1,
+      dt: 1,
+      ud0: 1500
     });
     s2 = NewTestingServer({
       currency: 'currency_two',
@@ -138,17 +142,17 @@ describe("Document pool currency", function() {
     try {
       yield cat1.cert(tac1);
       yield tac1.cert(cat1);
-      yield s1.commit();
-      yield s1.commit();
+      yield s1.commit({ time: now });
+      yield s1.commit({ time: now });
       const current = yield s1.get('/blockchain/current');
       const tx = cat1.makeTX(
         [{
-          src: "1500:1:D:DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo:1",
+          src: "1500:0:D:DKpQPUL4ckzXYdnDRvCRKAm1gNvSdmAXnTrJZ7LvM5Qo:1",
           unlock: "SIG(0)"
         }],
         [{
           qty: 1500,
-          base: 1,
+          base: 0,
           lock: "XHX(8AFC8DF633FC158F9DB4864ABED696C1AA0FE5D617A7B5F7AB8DE7CA2EFCD4CB)"
         }],
         {
@@ -164,6 +168,31 @@ describe("Document pool currency", function() {
     }
   }));
 
+  it('Transaction with wrong XHX should be rejected', () => co(function*() {
+    try {
+      const current = yield s1.get('/blockchain/current');
+      const tx = cat1.makeTX(
+        [{
+          src: "1500:1:D:HgTTJLAQ5sqfknMq7yLPZbehtuLSsKj9CxWN7k8QvYJd:1",
+          unlock: "SIG(0)"
+        }],
+        [{
+          qty: 1500,
+          base: 1,
+          lock: "XHX(6B86B273FF34FCE19D6B804EFF5A3F5747ADA4EAA22F1D49C01E52DDB7875B4B))"
+        }],
+        {
+          blockstamp: [current.number, current.hash].join('-')
+        });
+      yield s1.postRawTX(tx);
+      throw "Transaction should not have been accepted, since it has wrong output format";
+    } catch (e) {
+      should.exist(e.error);
+      e.should.be.an.Object();
+      e.error.message.should.match(/Wrong output format/);
+    }
+  }));
+
   it('Peer with wrong currency should be rejected', () => co(function*() {
     try {
       const peer = yield toc2.makePeer(['BASIC_MERKLED_API localhost 10901'], {
-- 
GitLab