CIP0010: Multi Peer Multi Asset sends

Currently i’m developing CIP0010 (which could be merged with CIP0009 if there’s a general consensus about it, although i think these two CIPs are addressing completely different issues).

Current in-development CIP can be found here

Let’s start the discussion.

I’m assigning this CIP #10.

Please add all the commits to the branch and open a pull request.

We can then add syntax and technical comments on the pull request.

Both of these libraries look helpful for parsing bit-level data.

However, neither of them appear to be widely used. I question if they are stable enough to run in consensus-sensitive code.

[UPDATE] To me, it looks like bitstring is the more mature of the two, even though the github repo is not very active. The bitstring.BitStream class looks like exactly what we need.

Used BitString for the test code, it seems it does its job pretty well and is really easy to use.

Hope anyone can confirm performance as i’ve obtained:

That’s on a 4 core AMD A8 APU 16gb ram running on Debian 8.

Final revision of MPMA cip10 just updated. Please comment.

awesome! nice work!

NIT: If one of the sends inside the whole MPMA message breaks consensus rules, that specific transaction must be silently ignored as to not prevent excution of the rest of the transactions.
I think should be worded: If one of the sends inside the whole MPMA message breaks consensus rules, the transaction as a whole is considered invalid.
no reason to mention any interaction with “the rest of the transactions” since that is how it always works in CP and mentioning it implies there’s something different than the default behavior.

NIT: Asset Signaling Bit 1 in the table should be Asset Signaling Bit M I think?

NIT: assuming the milestones are ordered, from experience I’d also say the more logical way is to do the CLI/RPC methods last, unless you literally leave the body of the methods completely empty and only put a log line in there it’s impossible to do anything of the sort without having the other stuff working.

MAJOR: wondering if we need any constraints, bitcoin tx fees normally protect us against compute intensive payloads because there’s a (rough) correlation between work needed to process a TX and it’s size in bytes (edited)

this would allow humongous sends at a fraction of the cost because normally every 1 SEND has the minimum cost of 1 P2PKH input, 1 P2PKH output, 1 OPRETURN output, 200ish bytes (realistically you also need a change output so 270ish bytes), of which only ~40 bytes are actually used for the SEND (output + OPRETURN).

with some quick napkin calculations you could send 100 assets to 1 recipient with 1100ish bytes (only 4% of the cost of doing 100 old school sends).

oldschool 1 send results in about 300 bytes orso being stored (transactions + sends + credits + debits, rough estimate), roughly same size as the tx
broadcasts are also roughly 1=1 size:dbsize, DEX orders or bets probably result in slightly more dbsize than size of the tx

a 100x CIP10 send tx (~1100 byte) would expand to roughly 25kb (transactions=180 + cip10sends=1000 + ((credits=120 + debits=120) × 100))

MAJOR: would help if example would be example of sending 2 assets, also I think the encoded example is incorrect.
and the more extensive example has 0400 as LUX length, am I an idiot or is that 1024?

MAJOR: in the AssetList how do I know how many bits the Z recipients and LUT Idx Z are?

What does “breaks consensus rules” mean here? Do we mean a syntax error like an invalid asset name? Or trying to send more assets than the address contains?

For the former, I do think the safe thing to do here is to invalidate all of the sends. So one syntax error invalidates the entire MPMA send.

However, for sending assets with insufficient balances… Should that silently be set to the maximum available amount like sends work currently? I guess so in order to stay consistent.

Asset Signaling Bit 1 means literally a bit with a value of b1.

This purpose of CIP 10 is to make transactions as cheap as possible. Bitcoin fees are so high right now that low value assets are not worth the fees of sending them.

MPMA sends today are still more expensive than standard sends a couple of years ago. For reference, here is a distribution send of LTBCOIN from Jun 27th, 2014. The BTC dust and fee combined were on the order of 0.0001 BTC. That was about 5 cents at the time.

Today, sending 24 bytes of data in an MPMA send would cost around 15 cents. So the spam protection for legitimate sends is as good as it was in 2014.

With that said… Is there a legitimate attack vector here? If someone created the highest amount of sends with the lowest amount of data, what would happen? Could they do it in a way that actually creates database entries? What about sending the same asset back and forth between the same 2 addresses 1000 times?

Agreed. I would also benefit from an example with multiple assets.

I had the same question and chiguireitor clarified it for me. Use the minumum number of bits required to cover the value of LUT size. This formula is:

Number of Bits = Log base 2 of LUT size rounded up to the nearest integer

I guess this makes better sense then, will modify the cip accordingly.

This. When a bit of value 0 gets signalled, the MPMA send ends, disregarding any padding bits left.

Will add a better example.

The examples were made previously before changing INT to big endian as CP does. Will have to update accordingly.

Yes that depends totally on the way each one works. I’m more of the “build skeleton first and fill in later” type, but that could be changed.

Nothing should ever be done silently / implicit, there’s no reason to construct a bad TX other than bugs.

I’m 100% sure it needs constraints, I could do a 10k send in 90kb, which would rquire processing 10k sends and store ~2.5mb of data.
I know atm with how high bitcoin fees are and how relatively small our DB is that seems fine, but both of those might change.

I also don’t see why we’d want to allow unlimited MPMA’s, but idk what kind of use cases you guys have in mind for this CIP

At 9 bytes per send, I assume you are sending to the same address over and over again. I think the sanity check here is that we need to limit the number of times the same address can be used in one send.

I suggest we should:

  1. Not allow the same recipient/asset combination to be used more than once in the same MPMA send.
  2. Not allow the same recipient LUT entry to be used more than, say, 10 times. This means I can send 10 different assets to a recipient before I need to commit 21 more bytes to add that recipient a second time in the lookup table. To be clear, I can send more than 10 assets to the same recipient - but I just need to commit 21 more bytes to do it.
  3. Completely ignore sends that would be quantity 0. Do not create an entry in the database.

These three things should prevent abuse. Anything I’m missing here?

The purpose of this CIP is to make it cheaper to send multiple assets. Foldingcoin, for example, sends a distribution of FLDC to hundreds of addresses on a regular basis. It is an order of magnitude too expensive for them to do that right now.

Currently this is how standard sends work. If I send you 100 PEPECASH, but I only have 30 PEPECASH at my address, the protocol processes the send and sends you 30 PEPECASH instead. Are you suggesting we change this functionality in MPMA sends? I don’t think we should. I think we should stay consistent with standard sends.

The exception is with a send of 0. I do think we should completely (and silently) ignore MPMA send entries with a quantity of 0.

Limiting the amount of times an address appears on a MPMA send is nonsensical from a bandwidth standpoint.

However, limiting the amount of MPMA sends would require sybil attack mitigation. I don’t know if there’s a way to solve that without imposing a global MPMA limit (and that would mean this would be a pretty limited channel for sends).

Use cases are many: batch processing of withdrawals from exchanges, address sweeping, sending booster packs to addresses, giveaways, etc.

Understood and agree. MPMA send should be well constructed from the get go.

This is the best approach, as stating the same LUT index in the same asset is just SPAM. MPMA sends which incur in this should be considered malformed.

Same reasoning than before, any MPMA with a 0 asset send should be classified as malformed and rejected wholly.

This behavior is interesting, would this be needed? MPMA are mostly for automated systems, so allowing this kind of behavior could be inconsistent with the precision of the message type.

Can you elaborate on this? I don’t understand.

There are 2 cases where the send is of quantity 0.

  1. The amount in the send is actually entered with a zero. I agree this should be rejected as a syntax error and the whole transaction should be marked invalid.
  2. A previous send in the same block emptied out all of the quantity in the address. To be consistent with standard sends, this should not invalidate the rest of the sends in the MPMA.

I don’t know, but it is this way with standard sends. We should be consistent. It is useful for sweeping assets I guess.

    # Oversend
    cursor.execute('''SELECT * FROM balances \
                                 WHERE (address = ? AND asset = ?)''', (tx['source'], asset))
    balances = cursor.fetchall()
    if not balances:
        status = 'invalid: insufficient funds'
    elif balances[0]['quantity'] < quantity:
        quantity = min(balances[0]['quantity'], quantity)

I’m flabbergasted, you’re right, and imo a very poor design choice … I don’t think there’s ever a reason why a sender would want to protocol to adjust his send to his maximum amount unless he was trying to empty his wallet (and still it wouldn’t make sense for him to input a wrong amount)!

I put a reminder in slack for myself to rethink this later this week… let’s ignore it for now and focus on the 2 main issues…

I understand this MPMA is to efficiently do bigger send operations, but there needs to be limits in place to prevent it being used to DoS nodes.

looking at your listed use-cases they’re all cases where you send 1 asset (or maybe a few more, but not to many) to many addresses.
except the address sweeping and tbh that’s a use-case I care very little for since it’s an edge case.

a 10k assets send to 10k different addresses would be a ~300kb TX (only 1:8 txsize:dbsize, compared to the 1:30 ratio of the 90kb 10k assets send to 1 address)

1:8 ratio isn’t that big… in fact, that’s pretty ok in term of bandwidth optimization vs. amount of txs inserted into the db.

Most use cases will be batch processing, probably to send a wide collection of assets to several addresses:

  • Exchanges could batch XCP assets (i.e. polo withdrawals of XCP, FLDC and SJCX could be done on one fell sweep instead of several operations per each user, prolly each address would be used once per asset).
  • Booster pack sales will send several different assets to same address. Limiting the amount of times each addy appears could make senders spam the network with several MPMA.

I think to avoid overloading nodes, consensus should only allow 1 MPMA per block per origin address, thus reducing the possibility of spamming the network with phony request from the same addy. Only the first MPMA appearing on a block from a given address is taken into account.

Also, i guess MPMA sends should be more strict regarding amounts of each asset. Assets on a MPMA send that have origin balance lower than sent total should invalidate the whole MPMA, because there’s no way to determine from the multiple sent assets what should receive partial amounts and whatnot.

When it goes live? Status on other CIPs?

You can view the status of CIPS at

You can view a list of all the CIPs at

Ehmmm … CIP10 is where???

CIP10 is not an official CIP yet, so it is not in the CIP repo yet. You can find the details at :

I think this is a bad idea. This is non-obvious to the user and will cause transactions to be rejected for unexpected reasons. What if my transaction takes 3 blocks to confirm? And in that time, I sent another one. If they both happen to confirm in the same block, one will get rejected even though the user was doing nothing wrong.

The real attack vector is spamming a lot of sends with a low-cost transaction. I think we can prevent that with a few constraints (repeated here for convenience):

  1. Do not allow the same recipient/asset combination to be used more than once in the same MPMA send.
  2. Do not allow the same recipient LUT entry to be used more than, say, 10 times. This means I can send 10 different assets to a recipient before I need to commit 21 more bytes to add that recipient a second time in the lookup table. To be clear, I can send more than 10 assets to the same recipient - but I just need to commit 21 more bytes to do it.
  3. Completely ignore sends that would be quantity 0. Either invalidate that send or invalidate the entire transaction (!).

I’d like to see an asset name lookup table too. A common use case is distributions of one address to many specific addresses. For example, FOLDINGCOIN sends the same asset to hundreds of recipients every month. Storj was interested in doing the same thing.

CIP-13 also has an asset name lookup table penciled in.