Wenn A eben nicht immer ein A ist

IT kann auch Spaß machen, bis man auf einen Fehler trifft, den es eigentlich gar nicht geben kann. So passiert beim Einsatz einer node.js Erweiterung IOTA.lib.js. Das Modul hier soll eigentlich die Verbindung zu einem Node Server herstellen und bietet Schnittstellen zur Abfrage von Adressen, Nodes und eben auch zur Überweisung von IOTA.

Das node.js Script ist hier schnell erstellt und macht auch das was es soll:

const IOTA = require(‚iota.lib.js‘)
var iota = new IOTA({
‚host‘: ‚http://173.212.241.84‘,
‚port‘: 14265
});

const seed ='<secret Seed>‘
var gg=[]
gg[0]={}
gg[0].address=’PEQWKUNMWFJBGJZEVGLLNYWDKFGXYTUVZCUSSZFMX9AFFZIUBAYLSAWRZVSTSJYMEJC9SJJBOSQMVEUIWALGATGWSC‘
gg[0].value=1
gg[0].message=“
gg[0].tag=“
console.log(JSON.stringify(gg))
iota.api.sendTransfer(seed,4,15,gg,function( e, inputs ) {

if (!e) {
console.log(’new transfer generated: ‚ + inputs)
} else {
console.log(‚error’+e)
}})

Gleicher Aufruf unter Node-Red führt jedoch zu einem Fehler.

Something went wrong: Error: Invalid transfers object
at Object.invalidTransfers (/root/node_modules/iota.lib.js/lib/errors/inputErrors.js:23:16)
at api.prepareTransfers (/root/node_modules/iota.lib.js/lib/api/api.js:1099:32)
at api.sendTransfer (/root/node_modules/iota.lib.js/lib/api/api.js:621:10)
at evalmachine.<anonymous>:5:21
at evalmachine.<anonymous>:23:3
at ContextifyScript.Script.runInContext (vm.js:59:29)
at FunctionNode.<anonymous> (/makenode/node-red-0.17.5/nodes/core/core/80-function.js:197:33)
at emitOne (events.js:116:13)
at FunctionNode.emit (events.js:211:7)
at FunctionNode.Node.receive (/makenode/node-red-0.17.5/red/runtime/nodes/Node.js:215:14)
at Node.send (/makenode/node-red-0.17.5/red/runtime/nodes/Node.js:202:14)
at Node.<anonymous> (/makenode/node-red-0.17.5/red/runtime/nodes/flows/Flow.js:397:50)
at emitOne (events.js:116:13)
at Node.emit (events.js:211:7)
at Node.receive (/makenode/node-red-0.17.5/red/runtime/nodes/Node.js:215:14)
at FunctionNode.Node.send (/makenode/node-red-0.17.5/red/runtime/nodes/Node.js:202:14)

Was ist passiert ? Keine Ahnung. Nach langem rätseln und rumprobieren bleibt nur die gezielte Analyse über.
Angemakelt wird also hier, das der Übergebene Parameter „transfer“ ein ungültiges Object ist.
Laut Dokumentation (https://github.com/iotaledger/iota.lib.js/#sendtransfer) soll als Transfer Object folgendes definiert sein:

  • transfers: Array of transfer objects:
    address: String 81-tryte encoded address of recipient
    value: Int value to be transferred.
    message: String tryte-encoded message to be included in the bundle.
    tag: String 27-tryte encoded tag.

OK. Dann kann nur der aufgebaute Parameter hier nicht den Vorgaben entsprechen.

Ein Blick in den Source Code api.js scheint das auch zu bestätigen. In der Funktion: api.prototype.prepareTransfers = function(seed, transfers, options, callback) erfolgen mehrere Prüfungen. U.a.:

// Input validation of transfers object
if (!inputValidator.isTransfersArray(transfers)) {
return callback(errors.invalidTransfers());

Mit dem Callback Aufruf wird genau die Fehlermeldung ausgegeben, die auch beim Node Red Aufruf erzeugt wird. Es liegt die Vermutung nahe, das hier geprüft wird ob das Übergebene Object ein Array ist.  Müssen also nur noch die Daten geprüft werden:

1.) Untersuchung des Transfer Objects.
Im Node Script sieht übergebene Parameter transfer zunächst so aus

[{„address“:“PEQWKUNMWFJBGJZEVGLLNYWDKFGXYTUVZCUSSZFMX9AFFZIUBAYLSAWRZVSTSJYMEJC9SJJBOSQMVEUIWALGATGWSC“,“value“:1,“message“:““,“tag“:““}]

Er ist vom Type Array. Also alles OK und daher gibt es hier auch keinen Fehler.

2.) Untersuchung des Transfer Objects im Node-Red
Eine einfache Ausgabe des Objekts über die Konsole bringt eine Überraschung zutage, leider nur keine Lösung:

[{„address“:“PEQWKUNMWFJBGJZEVGLLNYWDKFGXYTUVZCUSSZFMX9AFFZIUBAYLSAWRZVSTSJYMEJC9SJJBOSQMVEUIWALGATGWSC“,“value“:1,“message“:““,“tag“:““}]

Nach mehrfacher Prüfung, kommt man zu dem Ergebnis das beide Objekte absolut gleich sind ? Doch es muss einen Unterschied geben sonst würde der Node-Red Aufruf hier funktionieren.
Also zurück zum Code. Was macht hier !inputValidator.isTransfersArray(transfers). Scheinbar eine eigene Modul Methode. Diese findet man erwartungsgemäß auch im ../utils/inputValidator.js:

var isTransfersArray = function(transfersArray) {
if (!isArray(transfersArray)) return false;
for (var i = 0; i < transfersArray.length; i++) {

Bevor also über ein Array (hier unsere Transfers) iteriert wird, erfolgt die Prüfung ob es auch ein Array ist. Auch hier stammt die !isArray(transfersArray) Funktion aus einer Erweiterung. Dies finden wir dann auch hier:

/**
* checks whether input is an array or not
*
* @method isArray
* @param {object}
* @returns {boolean}
**/
var isArray = function(array) {
return array instanceof Array;
}

Also alles ok ? Mitnichten.

Ein Test ob das übergebene Object ein Array ist führt zu verblüffenden Ergebnis:

Javascript:
var test = gg instanceof Array  => true

Bei Node-Red wird jedoch an der Stelle ein false ausgegeben. Scheinbar sind die gleichen Objekte doch nicht gleich. Dort führt die Prüfung mittels:

Array.isArray(Node-Red-Obj) zu true !

Ein Blick in die Javascript Dokumentation zeigt, dass Array eben nicht gleich Array ist und das es wichtig ist wie die instance von Array erzeugt wurde. Um nicht andere Teile des Codes zu beeinflussen entscheide ich mich für eine pragmatische Lösung:

/**
* checks whether input is an array or not
*
* @method isArray
* @param {object}
* @returns {boolean}
**/
var isArray = function(array) {
var r1 = Array.isArray(array);
var r2 = array instanceof Array;
return r1||r2;
}

Dies deckt immerhin beide Fälle ab. Was nun innerhalb von Node-Red passiet kann man leider so schnell nicht klären, aber die Lösung funktioniert und der Transfers ins IOTA Tangle funktioniert.

Dieser Beitrag wurde unter Uncategorized veröffentlicht. Setzen Sie ein Lesezeichen auf den Permalink.