nanocurrency / nano-node

Nano is digital currency. Its ticker is: XNO and its currency symbol is: Ӿ
https://nano.org
BSD 3-Clause "New" or "Revised" License
3.49k stars 787 forks source link

Default multisig only for receive blocks #1150

Open pedfx opened 6 years ago

pedfx commented 6 years ago

Every transaction is composed of two blocks, a send block and a receive block. This is perfect to process transactions, since it's an asynchronous network.

But while the receive block have not yet been signed, the send block is stuck on a state that makes it not possible to be pruned. What leaves opened this vector of spam for the pruned network.

To solve this situation it could be created a new version of the block which once it's perceived as a pending transaction, the receive block could be signed by someone else in the network as if it was on a multisig signature. For example, if a block is pending it can be assigned 12 representatives (MuSign) to sign the receive block and it would be added to the individual blockchain receiving the transaction.

This would only be possible at this case of receive block, any other type of block would only be permitted to be signed by the account owner.

Is this possible to be done to individual blockchain? Would only a block update make this happen?

kayabaNerve commented 6 years ago

This alters a core principle of Nano where only the user writes to their chain.

This also raises an attack vector where representatives can delete blocks from a blockchain by overwriting them with a multisig receive block This can be nullified, of course. It's more a comment on the complexities of the implementation than the design itself.

I also don't believe this is even an attack vector to consider as:

inkeliz commented 6 years ago

The weight of the representative may change over time, also you didn't know the weight if you are a light-wallet, for instance.

I think the representative could create a receive-block, but only the representative. If a xbr_aaa defines a xbr_bbb as a representive, both could send a receive block. If the representative is offline or the account is unopened, the transaction still pending.

It's must simpler than use a MuSign. The verifier, even a ligh-wallet, could verify if the block was signed by himself ( xbr_aaa) or the representative (xbr_bbb ), which is defined in the previous block and at least one block was signed by himself pointing to one rep.

Actually, the pending blocks could be partially pruned. The node need only the hash, the amount and the public-key of the receiver, it's 80 bytes against 216 bytes of a full state-block.

But the PoW still a problem.

pedfx commented 6 years ago

@kayabaNerve

I would have to disagree, the core principle of Nano is to be a currency and do it well, as long it follows this, it's doing fine. As the receive block just shows a transaction that already happened and the money is already owned by the private key (just pending to be signed), no one is creating new transactions on a blockchain as an independent party, they're just confirming the last part of the transaction when the blockchain receiving it have no risk involved.

Sure you pointed a real problem that could happen, the overwritten block. But that's easily fixed by this multisig blocks having a lower priority than a singlesig. For example if any new block appears before the multisig receive block is >75% confirmed, the network can discard the multisig and delay the creation of it until the singlesig has >75%.

The gains are focused on the pruning, a full historical node for once has little to gain. But as it is expected for the majority of the network's node to be pruned ones, it's a real gain overall.

PaulBGD commented 6 years ago

As long as the light client has the latest block, it can always traverse the chain of the sender's blocks if need be. I'm also sure there's a lot of ways that a light client could be smart about this, such as limiting the amount of previous send blocks it stores for a single account or pruning them after time.

pedfx commented 6 years ago

Just to separate comments:

@Inkeliz

That's an alternative way of looking at it. Sure it could be used only by the account's representative to sign the receive block. (The weights of the representatives creating the block are not really relevant, as the block would have to be validated by the network anyway)

But there's a reason I propose MuSign, that being you can split the block PoW into the 12 signers and each representative may do only a 1/12 PoW compared to the threshold, what makes the job easier for each one and still have the same, if not better, block spam prevention mechanism - it takes more time before the block start its propagation with no consequences to the transaction speed accepted - if the owner wants it to be signed faster he can still sign the block himself.

I don't know how the pendings are indexed right now, but if it's bigger than the 80 bytes idea it could be worth to use the smaller option.

For non historical nodes that still leaves us with a lot of blocks on pending not capable of being fully pruned, so by doing the multisig receive block you can save, for example, the state of an account after receiving 10000+ blocks on pending in one or two state blocks (after pruned), instead of having to save all the 10000+ blocks on pending even on a pruned account.

pedfx commented 6 years ago

@PaulBGD

One of the reasons state block was created is to make it easier to integrate block information with hardware independently from a central point, so we should be able to fully experience its benefits by pruning optimization.

Pruning should be solved at a protocol level, clients can do anything with the data even now, but that just sounds like a quick fix for a real problem.

kayabaNerve commented 6 years ago

I would rather take the simpler solution of having the representative do it, over a multisig. By picking 12 people do the works of tens/hundreds of representatives, even if they do 1/12 of the work per TX, they still must do it for more TXs.

I also think it should be an opt-in feature as to not overload the more popular representatives, and that we shouldn't use 75% over a flat 51%.

rotilho commented 6 years ago

What if the destination account does not exist? Or the assigned representative is on purpose offline?

kayabaNerve commented 6 years ago

Do you mean an invalid account or lack of an open block?

The second one is only an issue if we don't use a multisig (unless that just makes it even worse if one of the twelve are offline). I assume it means that send block can't be pruned.

pedfx commented 6 years ago

@rotilho

Unopened accounts are indeed a problem, as they don't have a previously chosen representative. But it can be assigned the same representative of the sender account, as the vote weight was on his possession and he was already assigning to this representative, so at the end of this tx no weight would have moved from this representative and that's safe enough. Another better option would be to assign the weight to the same account receiving the funds, that's even safer as only the private key owner would be able decide a delegated representative.

@kayabaNerve

Multisig is not optional, you can't have people that don't own the private key from the account signing transactions if you don't have Multisig.
I'll assume you were talking about MuSign, so the twelve reps are supposed to be randomly assigned by how fast they answer the signal sent to the network, and then after they sign a tx they'll have a cool down period when they won't receive any signal to sign these type of tx, this is already used (the cool down time) in some rebroadcast features.

kayabaNerve commented 6 years ago

You can have their representative do it. Then it's not a multi-sig. It's just the rep's signature.

I was referring to "MuSign" though. Random people writing to my chain with a fixed cooldown time sounds broken as hell.

clemahieu commented 6 years ago

As a clarification on how pending entries are stored internally: when a send is created, a pending entry containing the source hash and the amount to be received is created, rai::pending_entry We don’t actually reference the source block from that point on so the source account chain can still be pruned. Bloat of this table is something we should look at.

clemahieu commented 6 years ago

Additionally these entries are very small, 32 + 16 bytes. A solution that involves even 1 signature at 64 bytes would be larger.

pedfx commented 6 years ago

This question is focused on upgrading the block type because it supposedly can help to clear this pending entries table as a final solution. If it won't help, or if it makes the tx processing risky or heavier, the focus can be changed.

To prevent the bloat of this table on full and pruned nodes, it can be used MuSig stapling on the hash. As @clemahieu said, the entries are 32 + 16 bytes.

When you can count a lot of them you could use MuSig stapling and have a line of hash 32 bytes N (up to 127) entries / N (stapling) = 32 bytes total, while keeping the amount value untouched leaving a line of 16 bytes N entries = 16 bytes per entry. Reducing thus the total up from 32 127 +16 127 bytes to 32 + 16 * 127 bytes. At the maximum stapling capacity it would save (6069 bytes - 2064 bytes) 4032 bytes. One could say an R value is needed, but as these hash are not implying any trusted party on them (signature), you only need to check the hash of the block itself.

If the pending entry can contain only the source hash, the reduction of the table can be massive from (up to) 6069 to 32 bytes.

Right now this is about looking for an easier option where no block needs to be created on chain, and all the pendings can be stored on the same space used to keep one or two state block if not less.

pedfx commented 6 years ago

https://github.com/nanocurrency/raiblocks/pull/955

This may help with the idea