Po.et Documentation
Technical documentation for the Po.et Network

About Po.et
Use Po.et
Reference
Process
RDD

Partial Claims in IPFS Bug

Researching why this claim is full in the production db, but only partial on ipfs.

IPFS Link: https://ipfs.io/ipfs/QmcpLPy9QPnQK2QwjcmpciWcN29S3xJaE6SwJTozKckETF

From Production DB:

{
	"_id" : ObjectId("5ac3c48e0457d30b2e726476"),
	"id" : "937c5e9596bf142f47147254c9e92b479e3ca3e8b91960e227f657e4535e1dd4",
	"publicKey" : "0356cb88e76cc85bad886e0ccfb871d993418c5515a2439214038b016ca32f9ad9",
	"signature" : "3045022100f1377e088771a8cc9461e7ba33ce3dab9c9f65c9234be6b842a813a9a346a18302200ac38b6f4628efa0167837b23699b7bb78981f9e9e574b478b41ef0c58aa275b",
	"type" : "Work",
	"dateCreated" : "2018-04-03T18:15:11.454Z",
	"attributes" : {
		"name" : "Ein paar offene Worte zu Kooperationen",
		"datePublished" : "2018-04-03T20:14:40+00:00",
		"dateCreated" : "2018-03-15T11:33:54+00:00",
		"author" : "flowers on my plate",
		"tags" : "",
		"content" : "<h3><a href=\"https://flowersonmyplate.de/wp-content/uploads/working-mum1.jpg\"><img class=\"alignnone size-full wp-image-21098\" src=\"https://flowersonmyplate.de/wp-content/uploads/working-mum1.jpg\" alt=\"Ein paar offene Worte zu Kooperationen {flowers on my plate}\" width=\"1520\" height=\"1125\" /></a>Liebe Leser,</h3>\r\nihr habt vielleicht schon mitbekommen, dass wir mit diesem Blog hier auch Geld verdienen. Das ganze Thema mit dem Geld und dem Bloggen ist manchmal eine etwas heikle Angelegenheit und wir können das ein Stück weit sogar gut nachvollziehen, da wir anfangs auch unsicher waren, inwiefern sich beides verträgt. Wir haben im Laufe der Zeit aber festgestellt, dass es für uns gut zusammen passt, solange wir ein paar Dinge beachten.\r\n\r\nBei uns ist es so: Was vor fast 10 Jahren (ja, langsam fühlen wir uns alt...) als reines Hobby angefangen hat, ist mittlerweile zu einem unserer finanziellen Standbeine geworden. Hinter jedem einzelnen unserer Artikel stecken viele Stunden Arbeit und Herzblut, dazu kommt die Zeit für emails, Social Media, Verwaltung und vieles mehr. Zeit, die wir natürlich gerne hier investieren, gleichzeitig aber an anderer Stelle kappen. Spätestens seit Pollys Geburt priorisieren wir unsere gemeinsame Zeit noch mehr als früher und daher mussten wir uns irgendwann entscheiden: Ganz bewusst weniger externe Arbeit, dafür mehr Fokus auf den Blog und damit letzten Endes vielleicht sogar etwas mehr Zeit für die Familie? Da mussten wir nicht lange überlegen. Denn wenn man die Chance hat, mit dem \"Hobby\", das einem großen Spaß macht, das einen inspiriert und kreativ wachsen lässt, einen Teil seines Lebensunterhaltes zu verdienen, ist die Sache ziemlich schnell klar. Dann dankt man dem Universum und freut sich, denn besser wird’s wohl nicht.\r\n\r\nDiese Entwicklung ist bei uns nicht über Nacht passiert, sondern hat sich bewusst langsam aber stetig entwickelt. Sehr (sehr...) viele Anfragen die uns erreichen lehnen wir ab, weil sie schlichtweg nicht passen, da kann das Angebot noch so lukrativ sein. Was übrigens besonders oft bei großen Marken der Fall ist, die zwar ein beneidenswert hohes Marketing-Budget haben, \"leider\" aber meist so gar nicht zu unserer Philosophie passen ;) Ganz klar also, dass wir hierfür keine Werbung machen. Nach 10 Jahren Bloggerei, unzähligen Angeboten und ja, auch ein paar lessons learned wissen wir, dass sich das \"schnelle Geld\" nicht lohnt, wenn nicht wirklich alles passt. Wir wählen daher sehr gewissenhaft aus, mit wem und wie wir zusammen arbeiten möchten.  Dabei achten wir auch immer darauf, einen Mehrwert für euch, unsere Leser, zu schaffen. Sei es ein weiteres Rezept, ein Gewinnspiel oder einfach ein (Produkt)Tipp, den wir gerne mit euch teilen, weil wir selbst begeistert davon sind. Ohne euch wäre all das erst gar nicht möglich, das ist uns völlig klar. Ehrlich gesagt, hätte uns vor 10 Jahren jemand erzählt, dass wir irgendwann tatsächlich mal mehr Leser haben werden als ein paar enge Freunde und Verwandte (hallo Mama!), wir hätten es wohl nicht geglaubt. Aber das ist eine andere Geschichte.\r\n\r\nGeld sollte kein Tabuthema sein, wir alle brauchen es. Das Geld, das wir mit dem Blog verdienen, hilft uns dabei, genau diesen regelmäßig mit Inhalten zu füttern. Es unterstützt uns dabei, genau das Leben zu führen, das wir hier mit euch rund um die Themen <em>genießen</em>, <em>entdecken</em> und <em>leben</em> teilen. Denn unsere Reisen, die Küchenausstattung, nachhaltige Lebensmittel, die Fotoausrüstung und mit Bedacht ausgewählte Produkte kosten natürlich Geld. Alles was ihr hier seht, ist ein echter Auszug unseres Lebens; wir kaufen die Bio Lebensmittel, wir besuchen gerne besondere Hotels (ob in Kooperation oder selbst bezahlt) und wir mögen nachhaltige Marken. All das sind Dinge, die wir gerne - auch finanziell - unterstützen. Wenn wir also das Geld, das wir mit dem Blog einnehmen, so weiterreichen können, dann schließt sich für uns der Kreis.\r\n\r\nUm das Ganze etwas transparenter für euch zu machen, möchten wir zum Schluss noch auflisten, womit wir meistens so arbeiten:\r\n<ul>\r\n \t<li><strong>Advertorials</strong>, also Blogartikel, in denen wir euch ab und zu Marken oder Produkte vorstellen. Absolut klar, dass das natürlich Marken oder Produkte sind, hinter denen wir auch selbst stehen. So gut wie immer sind diese Artikel mit einem Rezept verknüpft und selbstverständlich sind wir dabei völlig frei in unserer Wortwahl; es gibt weder reine Werbeposts noch gekaufte Meinungen. Wenn wir begeistert klingen, dann deshalb, weil wir es auch tatsächlich sind. Unsere Advertorials sind mit dem Stichwort \"Werbung\" versehen und haben zusätzlich einen Hinweis am Schluss des Artikels</li>\r\n \t<li><strong>Partner Links / Affiliate Links</strong>: wenn ihr über einen der von uns verlinkten Shops etwas bestellt, ist es oft ein mit einem * markierter Partnerlink, der uns einen kleinen Prozentsatz Provision gewährt. So könnt ihr, wenn ihr möchtet, uns ganz simpel und direkt unterstützen - für euch entstehen dabei natürlich keinerlei Kosten und ihr bestellt einfach wie gewohnt</li>\r\n \t<li><strong>PR Sample</strong>: Manchmal bekommen wir hochwertige Produkte kostenfrei zur Verfügung gestellt (z.B. Kleidung oder Schuhe von nachhaltig arbeitenden, ganz wunderbaren Small Business Marken) und berichten auf dem Blog und/oder unseren Social Media Kanälen davon. Wenn das der Fall ist, kennzeichnen wir es ebenfalls entsprechend mit einem * und einem zusätzlichen Hinweis am Schluss des Artikels. Auch hier versteht es sich natürlich von selbst, dass wir das jeweilige Produkt so toll finden, dass wir es uns jederzeit selbst kaufen würden oder oft genug auch lange nach einer Zusammenarbeit noch weiterhin selbst erwerben</li>\r\n \t<li><strong>Externe Auftragsarbeiten für Kunden</strong>. Diese sind meist unabhängig vom Blog, ab und an berichten wir aber auch hier davon</li>\r\n</ul>\r\nEs gibt noch viele weitere Möglichkeiten mit einem Blog Geld zu verdienen, das sind aber die, für die wir uns entschieden haben, weil sie zu uns passen. Wir hoffen, dass wir mit diesem Artikel ein paar eventuell noch offene Fragen klären konnten. Wenn ihr Anmerkungen oder weitere Fragen habt, schickt uns gerne jederzeit eine email an <a href=\"mailto:dani@flowersonmyplate.de\" target=\"_blank\" rel=\"nofollow noopener\">dani@flowersonmyplate.de</a> oder <a href=\"mailto:michael@flowersonmyplate.de\" target=\"_blank\" rel=\"nofollow noopener\">michael@flowersonmyplate.de</a>\r\n\r\nWir wissen all das sehr zu schätzen, denn nochmal: Ohne euch wäre es nicht möglich. Vielen Dank für euer Vertrauen und eure Unterstützung!"
	},
	"timestamp" : {
		"transactionId" : "c0f208186959132e72b3eafcfe0dce5f2aaaf108e23f70186d9aa0dcbf111444",
		"outputIndex" : 0,
		"prefix" : "BARD",
		"version" : [
			0,
			0,
			0,
			2
		],
		"ipfsHash" : "QmcpLPy9QPnQK2QwjcmpciWcN29S3xJaE6SwJTozKckETF",
		"blockHeight" : 1290489,
		"blockHash" : "00000000000004f29660499a44004e5db107eeda6bad4cafc8fbbe659f3de8f1"
	}
}

Here is just the claim.

{
  "id" : "937c5e9596bf142f47147254c9e92b479e3ca3e8b91960e227f657e4535e1dd4",
	"publicKey" : "0356cb88e76cc85bad886e0ccfb871d993418c5515a2439214038b016ca32f9ad9",
	"signature" : "3045022100f1377e088771a8cc9461e7ba33ce3dab9c9f65c9234be6b842a813a9a346a18302200ac38b6f4628efa0167837b23699b7bb78981f9e9e574b478b41ef0c58aa275b",
	"type" : "Work",
	"dateCreated" : "2018-04-03T18:15:11.454Z",
	"attributes" : {
		"name" : "Ein paar offene Worte zu Kooperationen",
		"datePublished" : "2018-04-03T20:14:40+00:00",
		"dateCreated" : "2018-03-15T11:33:54+00:00",
		"author" : "flowers on my plate",
		"tags" : "",
		"content" : "<h3><a href=\"https://flowersonmyplate.de/wp-content/uploads/working-mum1.jpg\"><img class=\"alignnone size-full wp-image-21098\" src=\"https://flowersonmyplate.de/wp-content/uploads/working-mum1.jpg\" alt=\"Ein paar offene Worte zu Kooperationen {flowers on my plate}\" width=\"1520\" height=\"1125\" /></a>Liebe Leser,</h3>\r\nihr habt vielleicht schon mitbekommen, dass wir mit diesem Blog hier auch Geld verdienen. Das ganze Thema mit dem Geld und dem Bloggen ist manchmal eine etwas heikle Angelegenheit und wir können das ein Stück weit sogar gut nachvollziehen, da wir anfangs auch unsicher waren, inwiefern sich beides verträgt. Wir haben im Laufe der Zeit aber festgestellt, dass es für uns gut zusammen passt, solange wir ein paar Dinge beachten.\r\n\r\nBei uns ist es so: Was vor fast 10 Jahren (ja, langsam fühlen wir uns alt...) als reines Hobby angefangen hat, ist mittlerweile zu einem unserer finanziellen Standbeine geworden. Hinter jedem einzelnen unserer Artikel stecken viele Stunden Arbeit und Herzblut, dazu kommt die Zeit für emails, Social Media, Verwaltung und vieles mehr. Zeit, die wir natürlich gerne hier investieren, gleichzeitig aber an anderer Stelle kappen. Spätestens seit Pollys Geburt priorisieren wir unsere gemeinsame Zeit noch mehr als früher und daher mussten wir uns irgendwann entscheiden: Ganz bewusst weniger externe Arbeit, dafür mehr Fokus auf den Blog und damit letzten Endes vielleicht sogar etwas mehr Zeit für die Familie? Da mussten wir nicht lange überlegen. Denn wenn man die Chance hat, mit dem \"Hobby\", das einem großen Spaß macht, das einen inspiriert und kreativ wachsen lässt, einen Teil seines Lebensunterhaltes zu verdienen, ist die Sache ziemlich schnell klar. Dann dankt man dem Universum und freut sich, denn besser wird’s wohl nicht.\r\n\r\nDiese Entwicklung ist bei uns nicht über Nacht passiert, sondern hat sich bewusst langsam aber stetig entwickelt. Sehr (sehr...) viele Anfragen die uns erreichen lehnen wir ab, weil sie schlichtweg nicht passen, da kann das Angebot noch so lukrativ sein. Was übrigens besonders oft bei großen Marken der Fall ist, die zwar ein beneidenswert hohes Marketing-Budget haben, \"leider\" aber meist so gar nicht zu unserer Philosophie passen ;) Ganz klar also, dass wir hierfür keine Werbung machen. Nach 10 Jahren Bloggerei, unzähligen Angeboten und ja, auch ein paar lessons learned wissen wir, dass sich das \"schnelle Geld\" nicht lohnt, wenn nicht wirklich alles passt. Wir wählen daher sehr gewissenhaft aus, mit wem und wie wir zusammen arbeiten möchten.  Dabei achten wir auch immer darauf, einen Mehrwert für euch, unsere Leser, zu schaffen. Sei es ein weiteres Rezept, ein Gewinnspiel oder einfach ein (Produkt)Tipp, den wir gerne mit euch teilen, weil wir selbst begeistert davon sind. Ohne euch wäre all das erst gar nicht möglich, das ist uns völlig klar. Ehrlich gesagt, hätte uns vor 10 Jahren jemand erzählt, dass wir irgendwann tatsächlich mal mehr Leser haben werden als ein paar enge Freunde und Verwandte (hallo Mama!), wir hätten es wohl nicht geglaubt. Aber das ist eine andere Geschichte.\r\n\r\nGeld sollte kein Tabuthema sein, wir alle brauchen es. Das Geld, das wir mit dem Blog verdienen, hilft uns dabei, genau diesen regelmäßig mit Inhalten zu füttern. Es unterstützt uns dabei, genau das Leben zu führen, das wir hier mit euch rund um die Themen <em>genießen</em>, <em>entdecken</em> und <em>leben</em> teilen. Denn unsere Reisen, die Küchenausstattung, nachhaltige Lebensmittel, die Fotoausrüstung und mit Bedacht ausgewählte Produkte kosten natürlich Geld. Alles was ihr hier seht, ist ein echter Auszug unseres Lebens; wir kaufen die Bio Lebensmittel, wir besuchen gerne besondere Hotels (ob in Kooperation oder selbst bezahlt) und wir mögen nachhaltige Marken. All das sind Dinge, die wir gerne - auch finanziell - unterstützen. Wenn wir also das Geld, das wir mit dem Blog einnehmen, so weiterreichen können, dann schließt sich für uns der Kreis.\r\n\r\nUm das Ganze etwas transparenter für euch zu machen, möchten wir zum Schluss noch auflisten, womit wir meistens so arbeiten:\r\n<ul>\r\n \t<li><strong>Advertorials</strong>, also Blogartikel, in denen wir euch ab und zu Marken oder Produkte vorstellen. Absolut klar, dass das natürlich Marken oder Produkte sind, hinter denen wir auch selbst stehen. So gut wie immer sind diese Artikel mit einem Rezept verknüpft und selbstverständlich sind wir dabei völlig frei in unserer Wortwahl; es gibt weder reine Werbeposts noch gekaufte Meinungen. Wenn wir begeistert klingen, dann deshalb, weil wir es auch tatsächlich sind. Unsere Advertorials sind mit dem Stichwort \"Werbung\" versehen und haben zusätzlich einen Hinweis am Schluss des Artikels</li>\r\n \t<li><strong>Partner Links / Affiliate Links</strong>: wenn ihr über einen der von uns verlinkten Shops etwas bestellt, ist es oft ein mit einem * markierter Partnerlink, der uns einen kleinen Prozentsatz Provision gewährt. So könnt ihr, wenn ihr möchtet, uns ganz simpel und direkt unterstützen - für euch entstehen dabei natürlich keinerlei Kosten und ihr bestellt einfach wie gewohnt</li>\r\n \t<li><strong>PR Sample</strong>: Manchmal bekommen wir hochwertige Produkte kostenfrei zur Verfügung gestellt (z.B. Kleidung oder Schuhe von nachhaltig arbeitenden, ganz wunderbaren Small Business Marken) und berichten auf dem Blog und/oder unseren Social Media Kanälen davon. Wenn das der Fall ist, kennzeichnen wir es ebenfalls entsprechend mit einem * und einem zusätzlichen Hinweis am Schluss des Artikels. Auch hier versteht es sich natürlich von selbst, dass wir das jeweilige Produkt so toll finden, dass wir es uns jederzeit selbst kaufen würden oder oft genug auch lange nach einer Zusammenarbeit noch weiterhin selbst erwerben</li>\r\n \t<li><strong>Externe Auftragsarbeiten für Kunden</strong>. Diese sind meist unabhängig vom Blog, ab und an berichten wir aber auch hier davon</li>\r\n</ul>\r\nEs gibt noch viele weitere Möglichkeiten mit einem Blog Geld zu verdienen, das sind aber die, für die wir uns entschieden haben, weil sie zu uns passen. Wir hoffen, dass wir mit diesem Artikel ein paar eventuell noch offene Fragen klären konnten. Wenn ihr Anmerkungen oder weitere Fragen habt, schickt uns gerne jederzeit eine email an <a href=\"mailto:dani@flowersonmyplate.de\" target=\"_blank\" rel=\"nofollow noopener\">dani@flowersonmyplate.de</a> oder <a href=\"mailto:michael@flowersonmyplate.de\" target=\"_blank\" rel=\"nofollow noopener\">michael@flowersonmyplate.de</a>\r\n\r\nWir wissen all das sehr zu schätzen, denn nochmal: Ohne euch wäre es nicht möglich. Vielen Dank für euer Vertrauen und eure Unterstützung!"
	}
}

Posting the claim to the node again

Attempting to post this claim to the node again results in:

Here is the error from the storage writer.

[2018-09-11T22:37:12.187Z] ERROR (2514 on Kenneths-MacBook-Pro.local): Uncaught Exception while Storing Claim
[2]     module: "StorageWriter"
[2]     file: "Router"
[2]     method: "onNewClaim"
[2]     error: {
[2]       "name": "FetchError",
[2]       "message": "invalid json response body at http://localhost:5001/api/v0/add reason: Unexpected token { in JSON at position 86",
[2]       "type": "invalid-json",
[2]       "stack": [
[2]         "FetchError: invalid json response body at http://localhost:5001/api/v0/add reason: Unexpected token { in JSON at position 86",
[2]         "    at /Users/kennethlavender/projects/poet/node/node_modules/node-fetch/lib/body.js:48:31",
[2]         "    at process._tickCallback (internal/process/next_tick.js:68:7)"
[2]       ]
[2]     }

The error says invalid json, but if I validate the json using something like jsonlint then it says the json is valid.

Notes

Replacing the claim content

If I replace the claim content with an empty string, the node accepts the claim, and the storage writer does not complain and the claim gets posted to ipfs with no issues.

https://ipfs.io/ipfs/QmUefgK6mNX5PkckuLodjaePUWjzPkt2LUdnHym9XJWr9V

Claim with content replaced

{
  "id" : "937c5e9596bf142f47147254c9e92b479e3ca3e8b91960e227f657e4535e1dd4",
	"publicKey" : "0356cb88e76cc85bad886e0ccfb871d993418c5515a2439214038b016ca32f9ad9",
	"signature" : "3045022100f1377e088771a8cc9461e7ba33ce3dab9c9f65c9234be6b842a813a9a346a18302200ac38b6f4628efa0167837b23699b7bb78981f9e9e574b478b41ef0c58aa275b",
	"type" : "Work",
	"dateCreated" : "2018-04-03T18:15:11.454Z",
	"attributes" : {
		"name" : "Ein paar offene Worte zu Kooperationen",
		"datePublished" : "2018-04-03T20:14:40+00:00",
		"dateCreated" : "2018-03-15T11:33:54+00:00",
		"author" : "flowers on my plate",
		"tags" : "",
                "content": ""
        }
}

Notes

Digging Deeper to the actual source of the issue

I tracked the issue down to the ipfs file where it creates a stream from the claim, uploads the claim and gets back an incorrect response.

https://github.com/poetapp/node/blob/master/src/StorageWriter/IPFS.ts#L19-L38

It was complaining about response.json() not being correctly formed, so I tried response.text() and logged the result, here is the result:

{"Name":"file","Hash":"QmcpLPy9QPnQK2QwjcmpciWcN29S3xJaE6SwJTozKckETF","Size":"7308"}
[2] {"Message":"multipart: NextPart: EOF","Code":0,"Type":"error"}

Tada! response.text() is giving us our hash that matches our incomplete hash from above and an error to research further!

Notes

response.json() throws a error when this issue happens meaning that the claim would never have been given an ipfs hash, maybe this was response.text() previously?

We still need to figure out what about this claim is causing IPFS or maybe our stream/upload to have issues.

Here is what we know so far

Next Steps

Testing the claim via curl

Testing the claim via curl should give us some more insight on where the issue lies. If curl successfully stores the claim then its likely the issue lies in our stream/form data logic.

Create the files

echo "{"id":"937c5e9596bf142f47147254c9e92b479e3ca3e8b91960e227f657e4535e1dd4","publicKey":"0356cb88e76cc85bad886e0ccfb871d993418c5515a2439214038b016ca32f9ad9","signature":"3045022100f1377e088771a8cc9461e7ba33ce3dab9c9f65c9234be6b842a813a9a346a18302200ac38b6f4628efa0167837b23699b7bb78981f9e9e574b478b41ef0c58aa275b","type":"Work","dateCreated":"2018-04-03T18:15:11.454Z","attributes":{"name":"Ein paar offene Worte zu Kooperationen","datePublished":"2018-04-03T20:14:40+00:00","dateCreated":"2018-03-15T11:33:54+00:00","author":"flowers on my plate","tags":"","content":"<h3><a href=\"https://flowersonmyplate.de/wp-content/uploads/working-mum1.jpg\"><img class=\"alignnone size-full wp-image-21098\" src=\"https://flowersonmyplate.de/wp-content/uploads/working-mum1.jpg\" alt=\"Ein paar offene Worte zu Kooperationen {flowers on my plate}\" width=\"1520\" height=\"1125\" /></a>Liebe Leser,</h3>\r\nihr habt vielleicht schon mitbekommen, dass wir mit diesem Blog hier auch Geld verdienen. Das ganze Thema mit dem Geld und dem Bloggen ist manchmal eine etwas heikle Angelegenheit und wir können das ein Stück weit sogar gut nachvollziehen, da wir anfangs auch unsicher waren, inwiefern sich beides verträgt. Wir haben im Laufe der Zeit aber festgestellt, dass es für uns gut zusammen passt, solange wir ein paar Dinge beachten.\r\n\r\nBei uns ist es so: Was vor fast 10 Jahren (ja, langsam fühlen wir uns alt...) als reines Hobby angefangen hat, ist mittlerweile zu einem unserer finanziellen Standbeine geworden. Hinter jedem einzelnen unserer Artikel stecken viele Stunden Arbeit und Herzblut, dazu kommt die Zeit für emails, Social Media, Verwaltung und vieles mehr. Zeit, die wir natürlich gerne hier investieren, gleichzeitig aber an anderer Stelle kappen. Spätestens seit Pollys Geburt priorisieren wir unsere gemeinsame Zeit noch mehr als früher und daher mussten wir uns irgendwann entscheiden: Ganz bewusst weniger externe Arbeit, dafür mehr Fokus auf den Blog und damit letzten Endes vielleicht sogar etwas mehr Zeit für die Familie? Da mussten wir nicht lange überlegen. Denn wenn man die Chance hat, mit dem \"Hobby\", das einem großen Spaß macht, das einen inspiriert und kreativ wachsen lässt, einen Teil seines Lebensunterhaltes zu verdienen, ist die Sache ziemlich schnell klar. Dann dankt man dem Universum und freut sich, denn besser wird’s wohl nicht.\r\n\r\nDiese Entwicklung ist bei uns nicht über Nacht passiert, sondern hat sich bewusst langsam aber stetig entwickelt. Sehr (sehr...) viele Anfragen die uns erreichen lehnen wir ab, weil sie schlichtweg nicht passen, da kann das Angebot noch so lukrativ sein. Was übrigens besonders oft bei großen Marken der Fall ist, die zwar ein beneidenswert hohes Marketing-Budget haben, \"leider\" aber meist so gar nicht zu unserer Philosophie passen ;) Ganz klar also, dass wir hierfür keine Werbung machen. Nach 10 Jahren Bloggerei, unzähligen Angeboten und ja, auch ein paar lessons learned wissen wir, dass sich das \"schnelle Geld\" nicht lohnt, wenn nicht wirklich alles passt. Wir wählen daher sehr gewissenhaft aus, mit wem und wie wir zusammen arbeiten möchten.  Dabei achten wir auch immer darauf, einen Mehrwert für euch, unsere Leser, zu schaffen. Sei es ein weiteres Rezept, ein Gewinnspiel oder einfach ein (Produkt)Tipp, den wir gerne mit euch teilen, weil wir selbst begeistert davon sind. Ohne euch wäre all das erst gar nicht möglich, das ist uns völlig klar. Ehrlich gesagt, hätte uns vor 10 Jahren jemand erzählt, dass wir irgendwann tatsächlich mal mehr Leser haben werden als ein paar enge Freunde und Verwandte (hallo Mama!), wir hätten es wohl nicht geglaubt. Aber das ist eine andere Geschichte.\r\n\r\nGeld sollte kein Tabuthema sein, wir alle brauchen es. Das Geld, das wir mit dem Blog verdienen, hilft uns dabei, genau diesen regelmäßig mit Inhalten zu füttern. Es unterstützt uns dabei, genau das Leben zu führen, das wir hier mit euch rund um die Themen <em>genießen</em>, <em>entdecken</em> und <em>leben</em> teilen. Denn unsere Reisen, die Küchenausstattung, nachhaltige Lebensmittel, die Fotoausrüstung und mit Bedacht ausgewählte Produkte kosten natürlich Geld. Alles was ihr hier seht, ist ein echter Auszug unseres Lebens; wir kaufen die Bio Lebensmittel, wir besuchen gerne besondere Hotels (ob in Kooperation oder selbst bezahlt) und wir mögen nachhaltige Marken. All das sind Dinge, die wir gerne - auch finanziell - unterstützen. Wenn wir also das Geld, das wir mit dem Blog einnehmen, so weiterreichen können, dann schließt sich für uns der Kreis.\r\n\r\nUm das Ganze etwas transparenter für euch zu machen, möchten wir zum Schluss noch auflisten, womit wir meistens so arbeiten:\r\n<ul>\r\n \t<li><strong>Advertorials</strong>, also Blogartikel, in denen wir euch ab und zu Marken oder Produkte vorstellen. Absolut klar, dass das natürlich Marken oder Produkte sind, hinter denen wir auch selbst stehen. So gut wie immer sind diese Artikel mit einem Rezept verknüpft und selbstverständlich sind wir dabei völlig frei in unserer Wortwahl; es gibt weder reine Werbeposts noch gekaufte Meinungen. Wenn wir begeistert klingen, dann deshalb, weil wir es auch tatsächlich sind. Unsere Advertorials sind mit dem Stichwort \"Werbung\" versehen und haben zusätzlich einen Hinweis am Schluss des Artikels</li>\r\n \t<li><strong>Partner Links / Affiliate Links</strong>: wenn ihr über einen der von uns verlinkten Shops etwas bestellt, ist es oft ein mit einem * markierter Partnerlink, der uns einen kleinen Prozentsatz Provision gewährt. So könnt ihr, wenn ihr möchtet, uns ganz simpel und direkt unterstützen - für euch entstehen dabei natürlich keinerlei Kosten und ihr bestellt einfach wie gewohnt</li>\r\n \t<li><strong>PR Sample</strong>: Manchmal bekommen wir hochwertige Produkte kostenfrei zur Verfügung gestellt (z.B. Kleidung oder Schuhe von nachhaltig arbeitenden, ganz wunderbaren Small Business Marken) und berichten auf dem Blog und/oder unseren Social Media Kanälen davon. Wenn das der Fall ist, kennzeichnen wir es ebenfalls entsprechend mit einem * und einem zusätzlichen Hinweis am Schluss des Artikels. Auch hier versteht es sich natürlich von selbst, dass wir das jeweilige Produkt so toll finden, dass wir es uns jederzeit selbst kaufen würden oder oft genug auch lange nach einer Zusammenarbeit noch weiterhin selbst erwerben</li>\r\n \t<li><strong>Externe Auftragsarbeiten für Kunden</strong>. Diese sind meist unabhängig vom Blog, ab und an berichten wir aber auch hier davon</li>\r\n</ul>\r\nEs gibt noch viele weitere Möglichkeiten mit einem Blog Geld zu verdienen, das sind aber die, für die wir uns entschieden haben, weil sie zu uns passen. Wir hoffen, dass wir mit diesem Artikel ein paar eventuell noch offene Fragen klären konnten. Wenn ihr Anmerkungen oder weitere Fragen habt, schickt uns gerne jederzeit eine email an <a href=\"mailto:dani@flowersonmyplate.de\" target=\"_blank\" rel=\"nofollow noopener\">dani@flowersonmyplate.de</a> oder <a href=\"mailto:michael@flowersonmyplate.de\" target=\"_blank\" rel=\"nofollow noopener\">michael@flowersonmyplate.de</a>\r\n\r\nWir wissen all das sehr zu schätzen, denn nochmal: Ohne euch wäre es nicht möglich. Vielen Dank für euer Vertrauen und eure Unterstützung!"}}" > claim-with-issue.json
echo "{"id":"937c5e9596bf142f47147254c9e92b479e3ca3e8b91960e227f657e4535e1dd4","publicKey":"0356cb88e76cc85bad886e0ccfb871d993418c5515a2439214038b016ca32f9ad9","signature":"3045022100f1377e088771a8cc9461e7ba33ce3dab9c9f65c9234be6b842a813a9a346a18302200ac38b6f4628efa0167837b23699b7bb78981f9e9e574b478b41ef0c58aa275b","type":"Work","dateCreated":"2018-04-03T18:15:11.454Z","attributes":{"name":"Ein paar offene Worte zu Kooperationen","datePublished":"2018-04-03T20:14:40+00:00","dateCreated":"2018-03-15T11:33:54+00:00","author":"flowers on my plate","tags":"","content":""}}" > claim-no-issue.json

Test the files

Test the claim with no content command

curl -0 -F foo=@claim-no-issue.json http://localhost:5001/api/v0/add

Response

{"Name":"claim-no-issue.json","Hash":"QmTMfJ3GuhthNU2jbwuAsuW49GWd82ESJYzxbZ3tpsUR8y","Size":"640"}

Test the claim with the content

curl -0 -F foo=@claim-with-issue.json http://localhost:5001/api/v0/add

Response

{"Name":"claim-with-issue.json","Hash":"QmZzqHkeiXbL4KGa97BJwKXuZu4B2iA23bbfezgSXmWboq","Size":"7385"}

Both tests result in a full claim in ipfs. Its looking like the issue might revolve around our stream/form data logic.

Creating Integration Tests

Creating some integration tests should help us make changes to the stream/form data logic to see if we can get the error to go away without adjusting the claim.

Created the integration tests here: https://github.com/poetapp/node/pull/429

Uploading the content only

Uploading the content only to IPFS still results in the same error from IPFS.

"<h3><a href=\"https://flowersonmyplate.de/wp-content/uploads/working-mum1.jpg\"><img class=\"alignnone size-full wp-image-21098\" src=\"https://flowersonmyplate.de/wp-content/uploads/working-mum1.jpg\" alt=\"Ein paar offene Worte zu Kooperationen {flowers on my plate}\" width=\"1520\" height=\"1125\" /></a>Liebe Leser,</h3>\r\nihr habt vielleicht schon mitbekommen, dass wir mit diesem Blog hier auch Geld verdienen. Das ganze Thema mit dem Geld und dem Bloggen ist manchmal eine etwas heikle Angelegenheit und wir können das ein Stück weit sogar gut nachvollziehen, da wir anfangs auch unsicher waren, inwiefern sich beides verträgt. Wir haben im Laufe der Zeit aber festgestellt, dass es für uns gut zusammen passt, solange wir ein paar Dinge beachten.\r\n\r\nBei uns ist es so: Was vor fast 10 Jahren (ja, langsam fühlen wir uns alt...) als reines Hobby angefangen hat, ist mittlerweile zu einem unserer finanziellen Standbeine geworden. Hinter jedem einzelnen unserer Artikel stecken viele Stunden Arbeit und Herzblut, dazu kommt die Zeit für emails, Social Media, Verwaltung und vieles mehr. Zeit, die wir natürlich gerne hier investieren, gleichzeitig aber an anderer Stelle kappen. Spätestens seit Pollys Geburt priorisieren wir unsere gemeinsame Zeit noch mehr als früher und daher mussten wir uns irgendwann entscheiden: Ganz bewusst weniger externe Arbeit, dafür mehr Fokus auf den Blog und damit letzten Endes vielleicht sogar etwas mehr Zeit für die Familie? Da mussten wir nicht lange überlegen. Denn wenn man die Chance hat, mit dem \"Hobby\", das einem großen Spaß macht, das einen inspiriert und kreativ wachsen lässt, einen Teil seines Lebensunterhaltes zu verdienen, ist die Sache ziemlich schnell klar. Dann dankt man dem Universum und freut sich, denn besser wird’s wohl nicht.\r\n\r\nDiese Entwicklung ist bei uns nicht über Nacht passiert, sondern hat sich bewusst langsam aber stetig entwickelt. Sehr (sehr...) viele Anfragen die uns erreichen lehnen wir ab, weil sie schlichtweg nicht passen, da kann das Angebot noch so lukrativ sein. Was übrigens besonders oft bei großen Marken der Fall ist, die zwar ein beneidenswert hohes Marketing-Budget haben, \"leider\" aber meist so gar nicht zu unserer Philosophie passen ;) Ganz klar also, dass wir hierfür keine Werbung machen. Nach 10 Jahren Bloggerei, unzähligen Angeboten und ja, auch ein paar lessons learned wissen wir, dass sich das \"schnelle Geld\" nicht lohnt, wenn nicht wirklich alles passt. Wir wählen daher sehr gewissenhaft aus, mit wem und wie wir zusammen arbeiten möchten.  Dabei achten wir auch immer darauf, einen Mehrwert für euch, unsere Leser, zu schaffen. Sei es ein weiteres Rezept, ein Gewinnspiel oder einfach ein (Produkt)Tipp, den wir gerne mit euch teilen, weil wir selbst begeistert davon sind. Ohne euch wäre all das erst gar nicht möglich, das ist uns völlig klar. Ehrlich gesagt, hätte uns vor 10 Jahren jemand erzählt, dass wir irgendwann tatsächlich mal mehr Leser haben werden als ein paar enge Freunde und Verwandte (hallo Mama!), wir hätten es wohl nicht geglaubt. Aber das ist eine andere Geschichte.\r\n\r\nGeld sollte kein Tabuthema sein, wir alle brauchen es. Das Geld, das wir mit dem Blog verdienen, hilft uns dabei, genau diesen regelmäßig mit Inhalten zu füttern. Es unterstützt uns dabei, genau das Leben zu führen, das wir hier mit euch rund um die Themen <em>genießen</em>, <em>entdecken</em> und <em>leben</em> teilen. Denn unsere Reisen, die Küchenausstattung, nachhaltige Lebensmittel, die Fotoausrüstung und mit Bedacht ausgewählte Produkte kosten natürlich Geld. Alles was ihr hier seht, ist ein echter Auszug unseres Lebens; wir kaufen die Bio Lebensmittel, wir besuchen gerne besondere Hotels (ob in Kooperation oder selbst bezahlt) und wir mögen nachhaltige Marken. All das sind Dinge, die wir gerne - auch finanziell - unterstützen. Wenn wir also das Geld, das wir mit dem Blog einnehmen, so weiterreichen können, dann schließt sich für uns der Kreis.\r\n\r\nUm das Ganze etwas transparenter für euch zu machen, möchten wir zum Schluss noch auflisten, womit wir meistens so arbeiten:\r\n<ul>\r\n \t<li><strong>Advertorials</strong>, also Blogartikel, in denen wir euch ab und zu Marken oder Produkte vorstellen. Absolut klar, dass das natürlich Marken oder Produkte sind, hinter denen wir auch selbst stehen. So gut wie immer sind diese Artikel mit einem Rezept verknüpft und selbstverständlich sind wir dabei völlig frei in unserer Wortwahl; es gibt weder reine Werbeposts noch gekaufte Meinungen. Wenn wir begeistert klingen, dann deshalb, weil wir es auch tatsächlich sind. Unsere Advertorials sind mit dem Stichwort \"Werbung\" versehen und haben zusätzlich einen Hinweis am Schluss des Artikels</li>\r\n \t<li><strong>Partner Links / Affiliate Links</strong>: wenn ihr über einen der von uns verlinkten Shops etwas bestellt, ist es oft ein mit einem * markierter Partnerlink, der uns einen kleinen Prozentsatz Provision gewährt. So könnt ihr, wenn ihr möchtet, uns ganz simpel und direkt unterstützen - für euch entstehen dabei natürlich keinerlei Kosten und ihr bestellt einfach wie gewohnt</li>\r\n \t<li><strong>PR Sample</strong>: Manchmal bekommen wir hochwertige Produkte kostenfrei zur Verfügung gestellt (z.B. Kleidung oder Schuhe von nachhaltig arbeitenden, ganz wunderbaren Small Business Marken) und berichten auf dem Blog und/oder unseren Social Media Kanälen davon. Wenn das der Fall ist, kennzeichnen wir es ebenfalls entsprechend mit einem * und einem zusätzlichen Hinweis am Schluss des Artikels. Auch hier versteht es sich natürlich von selbst, dass wir das jeweilige Produkt so toll finden, dass wir es uns jederzeit selbst kaufen würden oder oft genug auch lange nach einer Zusammenarbeit noch weiterhin selbst erwerben</li>\r\n \t<li><strong>Externe Auftragsarbeiten für Kunden</strong>. Diese sind meist unabhängig vom Blog, ab und an berichten wir aber auch hier davon</li>\r\n</ul>\r\nEs gibt noch viele weitere Möglichkeiten mit einem Blog Geld zu verdienen, das sind aber die, für die wir uns entschieden haben, weil sie zu uns passen. Wir hoffen, dass wir mit diesem Artikel ein paar eventuell noch offene Fragen klären konnten. Wenn ihr Anmerkungen oder weitere Fragen habt, schickt uns gerne jederzeit eine email an <a href=\"mailto:dani@flowersonmyplate.de\" target=\"_blank\" rel=\"nofollow noopener\">dani@flowersonmyplate.de</a> oder <a href=\"mailto:michael@flowersonmyplate.de\" target=\"_blank\" rel=\"nofollow noopener\">michael@flowersonmyplate.de</a>\r\n\r\nWir wissen all das sehr zu schätzen, denn nochmal: Ohne euch wäre es nicht möglich. Vielen Dank für euer Vertrauen und eure Unterstützung!"

Pick apart the content string for invalid characters

I originally tried to segment the string and test the segments individually. This ended up being way to tedious because there were too many segments that caused the ipfs error.

After doing some digging and some trial and error, I was thinking it might be invalid utf8 characters. I don’t know much about encoding so I will need to do some reading about this.

But I did google for a quick way to strip invalid utf8 characters, found this https://stackoverflow.com/a/19828943

function cleanString(input: string) {
  let output = ""
  for (var i=0; i<input.length; i++) {
      if (input.charCodeAt(i) <= 127) {
          output += input.charAt(i);
      }
  }
  return output;
}

After using that function to strip characters from the content it successfully uploaded to ipfs without errors.

I modifed the function a bit to give me back the removed characters as well, here they are:

öüäüüüüäüüüüßßä’üüßüääöüäööäääääßüüüßüüäüöüößüüöüüäöääüäööüüüüääüüüäöüäääöüü

Now because I don’t know much about encoding, I am unsure if this function is doing what the author claims it is doing. I need to read about uft-8 and invalid character codes and see if all or some of these are actually invalid. Then from there go about seeing what we can/should do about these characters if they are invalid.

After stripping these characters from the content the claim also successfully uploads completely to ipfs. http://ipfs.io/ipfs/QmPYbcPXAaw8WsUta924kzkM758rHtcWHLrZqj5xd6BBwV

This brings up some questions

Do we limit users to specific encodings for claim content? Probably not. So how do we support any type of file the user wants to upload to ipfs? This is probably an issue around the Buffer and Form Data, not sure about solutions. Uploading the content separately as we are planning would most likely help because we probably do want to limit claims to being utf8.


Possible solution 1?

It was bugging me that curl uploaded the content to ipfs just fine. But somehow our node implementation, even though we were not doing anything special with the data, pretty much passing it through, was resulting in missing content due to encoding.

I knew that even after we split out the work file from the claim, we are going to need to upload data that has any type of encoding through the node to ipfs. Doing so with our current implmentation would fail.

With the above 2 thoughts in my head, I started looking for a way to upload data from the node to ipfs that did not have the encoding issue similar to curl.

I came across request that supports multipart/form-data and started giving it a shot.

I tried the following with request

I also tried the above with the original code: form-data and fetch from node-fetch, but none of the combinations worked.

So we have a working solution for this type of partial claim issue, all of the integration tests I made now pass, but still not sure of the exact cause for streams not to work.

I’ve added the solution to the integration test PR, here is the solution code: https://github.com/poetapp/node/blob/3d46e052b47056dc56ffb04cd1877b52abf6fd20/src/StorageWriter/IPFS.ts#L18-L28

Here are the 4 claims on ipfs

Incorrect description of characters used above

I have been using the phrase invalid utf8 characters to describe the characters that were breaking the ipfs uploads. But what I was truly describing were valid utf8 non-ascii characters.

Streams not working might be a possible issue in go-ipfs

I noticed an X-STREAM-ERROR error in the http response when trying to use streams.

{
  "err": null,
  "httpResponse": {
    "statusCode": 200,
    "body": "{\"Name\":\"QmbsSsLq9Au3K51xFhTLa8io9vu9rf1mmxSmYeh5SJzqqv\",\"Hash\":\"QmbsSsLq9Au3K51xFhTLa8io9vu9rf1mmxSmYeh5SJzqqv\",\"Size\":\"66\"}\n{\"Message\":\"multipart: NextPart: EOF\",\"Code\":0,\"Type\":\"error\"}\n",
    "headers": {
      "access-control-allow-headers": "X-Stream-Output, X-Chunked-Output, X-Content-Length",
      "access-control-expose-headers": "X-Stream-Output, X-Chunked-Output, X-Content-Length",
      "content-type": "application/json",
      "server": "go-ipfs/0.4.17",
      "trailer": "X-Stream-Error",
      "vary": "Origin",
      "x-chunked-output": "1",
      "date": "Fri, 14 Sep 2018 23:16:05 GMT",
      "connection": "close",
      "transfer-encoding": "chunked"
    },
    "request": {
      "uri": {
        "protocol": "http:",
        "slashes": true,
        "auth": null,
        "host": "localhost:5001",
        "port": "5001",
        "hostname": "localhost",
        "hash": null,
        "search": null,
        "query": null,
        "pathname": "/api/v0/add",
        "path": "/api/v0/add",
        "href": "http://localhost:5001/api/v0/add"
      },
      "method": "POST",
      "headers": {
        "content-type": "multipart/form-data; boundary=--------------------------597525477875289845863189",
        "content-length": 199
      }
    }
  },
  "body": "{\"Name\":\"QmbsSsLq9Au3K51xFhTLa8io9vu9rf1mmxSmYeh5SJzqqv\",\"Hash\":\"QmbsSsLq9Au3K51xFhTLa8io9vu9rf1mmxSmYeh5SJzqqv\",\"Size\":\"66\"}\n{\"Message\":\"multipart: NextPart: EOF\",\"Code\":0,\"Type\":\"error\"}\n"
}

After some digging it might be on the ipfs side, they have an issue that might be related: https://github.com/ipfs/js-ipfs-api/issues/797

And another, maybe slightly less related: https://github.com/ipfs/go-ipfs/issues/5168

And they have an open PR for this issue: https://github.com/ipfs/go-ipfs-cmds/pull/116

fs.createReadStream vs other Readable streams

I tried a bunch of Readable Stream implementations and none worked.

fs.createReadStream returns the same type of Readable stream these other streams implement.

So I started looking to see what the difference there might be between createReadStream and these other streams.

I noticed that createReadStream sets a path property on itself, as far as I know, the other streams do not because they are not loading a file from a path.

I added the path property to the string-to-stream stream and it seems to work if the path is not an empty string. The string can also contain a file ending, like ‘claim.json’. The path does not seem to make any difference to the returned object from IPFS.

I am not sure why it is needed to set a path on the stream for the IPFS API, it may not be on purpose or they may have a reason to need it.

Note: If you provide a knownLength property with form-data the stream does not need a path. This is why the original implementation did not have this path issue.

I’ve switched back to the original implementation with node-fetch and form-data as it requires the least amount of code to change.

knownLength

Resolving the stream issue revealed the true issue with the original implementation. The original implementation got knownLength from the text itself. This I think was causing our non-ascii claims to fail because they become a different length when converted to a buffer inside the stream. Getting the length after the text has been converted to a buffer fixed this issue.

Previous

// ...
    formData.append('file', str(text), {
      knownLength: text.length,
      filename: 'file',
      contentType: 'plain/text',
    })

// ...
}

Fix

// ...
    formData.append('file', str(text), {
      knownLength: Buffer.from(text).length,
      filename: 'file',
      contentType: 'plain/text',
    })

// ...
}

We need to add another integration test with a very large claim to make sure this change is not just accidentally correct.

I swear this was one of the first things I tried but it did not seem to fix the issue. This was before having integration tests, so I could have manually tested incorrectly. It seems this is the only thing that needs to change to fix the non-ascii character issue.

Based on the above there are 2 solutions