/*
* Hi!
*
* I'm sending this tiny library for you to check. This is the basis of the
* on-chain signature collection solution I'm writing. It includes collecting
* signatures for multi-signatures accounts as well as sharing transactions XDR
* between signers.
*
* The present module implement a messaging system to cut and send those datas
* to the blockchain. It takes advantage of the fact that one can set the value
* of the same data entry up to 100 times in one transaction. Actually, 99 as
* the first operation is a payment of 0.0000001XLM to the destination address.
*
* The signature/transaction sharing solution will makes use of dedicated
* addresses where to send/collect those datas.
*
* The reason I'm sending this to you is that the same messaging system could be
* used to "abuse" the network. Well, actually you're the one to say if it would
* be an abuse or not. And I'd like to know about that.
*
* Using this library, one can send up to 6KB to the blockchain for a cost of
* 100 stroops. This could open very interesting possibilities, like mailing
* over Stellar, on-chain twitter-like services and even some basic blogging
* capabilities as gzip would allow to emit articles up to 16KB.
*
* I know you keep your archive light, so this may be a bit disruptive or
* incompatible with your current goals for Stellar.
*
* Just for you to know, I'm not the only one who found about this and some
* people mentionned it indirectly on Galactic Talk. Umbrel implemented it in
* a transaction-passing solution for papaya bot a few days ago. So this
* possibility is not going to stay secret anyway.
*
* I've been thinking about how to prevent abuse of this features and I didn't
* found solution, really. It could be made that one have to use 99 different
* data entry instead, but it would burden the account with cryptic labels
* and the additionnal cost would be payed only once - it wouldn't do.
*
* We could fix a maximum of 10 manageData operation or so per transaction.
* But it would only make it a bit harder to code the exact same thing.
*
* We could raise the fee for this kind of transaction, but it would make
* multi-sig collection expansive which may not be desirable at all.
*
* Another solution that would cut the possibility of on-chain signature
* collection would be to forbid mixing manageData operations with other kind
* of operations. But of course it would forbid a lot of precious innovations
* as well.
*
* So I would recommend to let it happen and see how much GB it's going to grow.
* Eventually the message-passing transactions could be recognized as such and
* deleted after a delay of a year or so, to prevent the archive to grow too
* big. I assume that the cost of the GB of storage is low enough for that to
* works.
*
* Well anyway it's only the conclusion I came to. I assume to are in a better
* position than me to say what we should do with that. And if you're open to it
* I'd be glad to code some mailing over Stellar demonstrating the possibilities
* of the network.
*
* I really wonder if you did expect this kind of things when calling
* developpers to innovate and surprise you with new uses of your blockchain?
*
* Antoine alias Mister.Ticot
*/
(function (root, f) {
'use_strict'
if (typeof module !== 'undefined' && module.exports) module.exports = f(root)
else root.messenger = f(root)
}(this, function(root) {
'use_strict'
if (typeof require !== 'undefined') var StellarSdk = require('stellar-sdk')
else StellarSdk = root.StellarSdk
/// Get Buffer constructor from StellarSdk
var memo = new StellarSdk.Memo('hash', '0000000000000000000000000000000000000000000000000000000000000000')
var Buffer = memo.value.__proto__.constructor
var messenger = {}
/**
* Build a transaction to be signed by `senderAccount` to send `message` to
* `destination`, with `object` as memo. The maximum size for `message` is
* 6336 bytes.
*
* The cost of emission is 1 stroop + 1 stroop for each 64 bytes to send.
*
* @param {AccountResponse} senderAccount The Account object as return by `StellarSdk.Server.loadAccount()`
* @param {String} destination The publicKey where to send the message
* @param {String} object The memo of the transaction (max. 28 bytes)
* @param {String} message The message to be send
* @return {Transaction} A StellarSdk Transaction object
*/
messenger.send = function (senderAccount, destination, object, message) {
var transaction = new StellarSdk.TransactionBuilder(senderAccount)
if (object.length > 28) console.log('Warning: object will be truncated.')
transaction.addMemo(new StellarSdk.Memo('text', object.substr(0,28)))
transaction.addOperation(StellarSdk.Operation.payment({
destination: destination,
asset: StellarSdk.Asset.native(),
amount: '0.0000001'
}))
var array = new Buffer(message)
if (array.length > 99*64) console.log('Warning: message will be truncated.')
for (let i = 0; i < 99; i++) {
const chunk = array.slice(i*64, i*64+64)
if (chunk.length === 0) break
transaction.addOperation(StellarSdk.Operation.manageData({
name: 'Send',
value: chunk
}))
}
return transaction.build()
}
/**
* Return the message object from `txHash`, using `server` to fetch datas.
*
* @param {Server} server A StellarSdk Server object
* @param {String} txHash A transaction hash
* @return {Object} A message object with `sender`, `object`, `date` and
* `message` fields.
*/
messenger.read = function(server, txHash) {
var caller = server.transactions()
return caller.transaction(txHash).call()
.then(function(answer) {
return {
sender: answer.source_account,
object: answer.memo,
date: answer.created_at,
message: extractMessage(answer)
}
})
}
function extractMessage (txCallAnswer) {
if (txCallAnswer.operation_count < 2) return null
var array = []
var tx = new StellarSdk.Transaction(txCallAnswer.envelope_xdr)
tx.operations.forEach(entry => {
if (entry.type === 'manageData' && entry.name === 'Send') {
console.log(entry.value)
array.push(entry.value)
}
})
return Buffer.concat(array).toString()
}
}))
I can't speak for the SDF, but since you are asking about this, you probably already have guessed that this is not intended functionality. As such, I wouldn't rely on this behavior being there forever for any particular product you're developing. I would expect this to be addressed if it ever became a widespread problem.