Solnet icon indicating copy to clipboard operation
Solnet copied to clipboard

[Bug] Cannot sign a partially signed transaction.

Open nazbrok opened this issue 3 years ago • 11 comments

When I try to deserialize a partially signed transaction (using Message.Deserialize), the existing Signers aren't deserialized.

var message = Message.Deserialize(compiledTransaction);
var tx = Transaction.Populate(message);

tx.Signers is empty

Example of transaction partially signed :

2,1,9,22,138,180,156,252,109,252,108,26,186,0,196,69,57,102,15,151,149,242,119,181,171,113,120,224,0,118,155,61,246,56,178,47,5,127,54,85,153,40,206,27,171,173,182,91,139,93,158,49,186,39,248,83,155,236,96,44,203,26,220,42,251,159,70,112,183,85,45,211,31,117,170,249,115,142,150,7,154,72,234,129,11,230,240,210,134,238,214,97,253,27,211,30,75,60,118,127,101,227,21,206,161,126,156,225,86,221,116,65,168,99,209,82,86,59,16,110,183,108,230,243,66,64,71,40,117,164,187,99,63,134,33,168,224,98,57,6,130,207,74,70,177,120,155,22,187,210,145,210,87,121,127,133,186,230,130,227,186,45,8,203,174,193,163,124,28,112,153,122,201,57,164,147,48,3,118,148,224,223,30,201,169,42,101,186,221,16,12,105,205,206,184,40,59,36,183,144,56,251,155,81,96,93,7,7,219,43,71,8,208,98,194,93,185,165,22,67,53,73,19,3,205,198,244,136,12,158,58,228,224,183,152,74,250,18,157,96,7,160,158,224,142,150,46,161,202,218,73,218,230,18,50,147,194,191,195,125,8,175,246,228,16,89,36,102,175,155,72,107,229,118,121,242,246,139,65,205,220,49,224,32,146,119,74,143,99,98,237,19,209,153,198,66,18,170,194,214,107,34,24,236,131,130,61,208,73,81,158,126,202,103,0,217,87,191,29,139,185,179,80,124,9,53,112,39,242,45,163,184,137,196,188,191,254,181,145,62,221,231,28,53,225,167,180,239,1,79,78,188,11,127,10,244,55,72,197,77,248,37,66,27,52,17,65,62,34,245,181,2,195,178,157,92,136,150,245,185,188,43,112,46,121,233,229,183,6,65,156,6,69,48,246,214,66,103,66,217,59,252,205,155,71,130,219,39,90,159,10,158,105,79,210,149,191,206,251,237,195,27,24,204,62,20,138,10,82,147,129,137,32,237,250,237,171,57,30,73,51,108,11,116,219,102,157,16,71,3,66,75,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,159,168,130,96,176,127,33,78,199,111,187,23,51,224,75,77,123,238,132,54,175,209,79,66,238,152,255,201,92,49,107,204,100,183,92,7,83,215,231,109,133,77,59,235,252,5,77,52,253,206,87,198,134,219,200,139,133,234,2,250,83,168,138,53,6,221,246,225,215,101,161,147,217,203,225,70,206,235,121,172,28,180,133,237,95,91,55,145,58,140,245,133,126,255,0,169,6,167,213,23,25,44,92,81,33,140,201,76,61,74,241,127,88,218,238,8,155,161,253,68,227,219,217,138,0,0,0,0,140,151,37,143,78,36,137,241,187,61,16,41,20,142,13,131,11,90,19,153,218,255,16,132,4,142,123,216,219,233,248,89,0,11,227,225,235,161,122,71,63,137,176,247,232,226,73,64,242,10,235,142,188,167,26,136,253,233,93,75,131,183,26,9,5,33,159,137,154,129,212,255,132,251,89,61,46,223,138,144,172,27,58,179,66,88,247,223,35,62,165,3,2,177,189,46,113,99,38,145,255,18,151,141,114,210,40,195,146,232,115,42,123,115,199,137,26,52,227,146,215,220,71,228,185,73,34,84,3,21,6,0,1,2,8,13,14,17,242,35,198,137,82,225,242,182,255,0,202,154,59,0,0,0,0,21,12,0,1,15,16,2,8,13,3,8,17,14,18,34,102,6,61,18,1,218,235,234,255,255,0,202,154,59,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,21,23,0,4,1,5,15,16,2,6,8,13,7,3,8,9,8,17,14,19,20,18,10,11,12,42,37,74,217,157,79,49,35,6,255,250,0,202,154,59,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255

nazbrok avatar Jun 16 '22 21:06 nazbrok

Not a bug, Message doesn't hold signatures, this design is a mirror of web3.js.

You only get signatures if you do TransactionBuilder.Build(....) or Transaction.Build(..) followed by Transaction.Deserialize(..) or Transaction.Populate(...)

tiago18c avatar Jun 16 '22 21:06 tiago18c

ok so how do you handle partial sign with Solnet ?

I am not sure what is the good way to do it with Solnet. So far I tried those 2 solutions which both failed (even using the fix for #386).

Still using the info from above, here is what I tried and the error I get.

Using PartialSign :

var walletMnemonic = "lens scheme misery search address destroy shallow police picture gown apart rural cotton vivid cage disagree enrich govern history kit early near cloth alarm";
var buyerAccount = (new Wallet.Wallet(walletMnemonic)).GetAccount(0);

-- This data comes from MagicEden using the test wallet above
 var data = new byte[] { 2, 1, 9, 22, 138, 180, 156, 252, 109, 252, 108, 26, 186, 0, 196, 69, 57, 102, 15, 151, 149, 242, 119, 181, 171, 113, 120, 224, 0, 118, 155, 61, 246, 56, 178, 47, 5, 127, 54, 85, 153, 40, 206, 27, 171, 173, 182, 91, 139, 93, 158, 49, 186, 39, 248, 83, 155, 236, 96, 44, 203, 26, 220, 42, 251, 159, 70, 112, 183, 85, 45, 211, 31, 117, 170, 249, 115, 142, 150, 7, 154, 72, 234, 129, 11, 230, 240, 210, 134, 238, 214, 97, 253, 27, 211, 30, 75, 60, 118, 127, 101, 227, 21, 206, 161, 126, 156, 225, 86, 221, 116, 65, 168, 99, 209, 82, 86, 59, 16, 110, 183, 108, 230, 243, 66, 64, 71, 40, 117, 164, 187, 99, 63, 134, 33, 168, 224, 98, 57, 6, 130, 207, 74, 70, 177, 120, 155, 22, 187, 210, 145, 210, 87, 121, 127, 133, 186, 230, 130, 227, 186, 45, 8, 203, 174, 193, 163, 124, 28, 112, 153, 122, 201, 57, 164, 147, 48, 3, 118, 148, 224, 223, 30, 201, 169, 42, 101, 186, 221, 16, 12, 105, 205, 206, 184, 40, 59, 36, 183, 144, 56, 251, 155, 81, 96, 93, 7, 7, 219, 43, 71, 8, 208, 98, 194, 93, 185, 165, 22, 67, 53, 73, 19, 3, 205, 198, 244, 136, 12, 158, 58, 228, 224, 183, 152, 74, 250, 18, 157, 96, 7, 160, 158, 224, 142, 150, 46, 161, 202, 218, 73, 218, 230, 18, 50, 147, 194, 191, 195, 125, 8, 175, 246, 228, 16, 89, 36, 102, 175, 155, 72, 107, 229, 118, 121, 242, 246, 139, 65, 205, 220, 49, 224, 32, 146, 119, 74, 143, 99, 98, 237, 19, 209, 153, 198, 66, 18, 170, 194, 214, 107, 34, 24, 236, 131, 130, 61, 208, 73, 81, 158, 126, 202, 103, 0, 217, 87, 191, 29, 139, 185, 179, 80, 124, 9, 53, 112, 39, 242, 45, 163, 184, 137, 196, 188, 191, 254, 181, 145, 62, 221, 231, 28, 53, 225, 167, 180, 239, 1, 79, 78, 188, 11, 127, 10, 244, 55, 72, 197, 77, 248, 37, 66, 27, 52, 17, 65, 62, 34, 245, 181, 2, 195, 178, 157, 92, 136, 150, 245, 185, 188, 43, 112, 46, 121, 233, 229, 183, 6, 65, 156, 6, 69, 48, 246, 214, 66, 103, 66, 217, 59, 252, 205, 155, 71, 130, 219, 39, 90, 159, 10, 158, 105, 79, 210, 149, 191, 206, 251, 237, 195, 27, 24, 204, 62, 20, 138, 10, 82, 147, 129, 137, 32, 237, 250, 237, 171, 57, 30, 73, 51, 108, 11, 116, 219, 102, 157, 16, 71, 3, 66, 75, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 159, 168, 130, 96, 176, 127, 33, 78, 199, 111, 187, 23, 51, 224, 75, 77, 123, 238, 132, 54, 175, 209, 79, 66, 238, 152, 255, 201, 92, 49, 107, 204, 100, 183, 92, 7, 83, 215, 231, 109, 133, 77, 59, 235, 252, 5, 77, 52, 253, 206, 87, 198, 134, 219, 200, 139, 133, 234, 2, 250, 83, 168, 138, 53, 6, 221, 246, 225, 215, 101, 161, 147, 217, 203, 225, 70, 206, 235, 121, 172, 28, 180, 133, 237, 95, 91, 55, 145, 58, 140, 245, 133, 126, 255, 0, 169, 6, 167, 213, 23, 25, 44, 92, 81, 33, 140, 201, 76, 61, 74, 241, 127, 88, 218, 238, 8, 155, 161, 253, 68, 227, 219, 217, 138, 0, 0, 0, 0, 140, 151, 37, 143, 78, 36, 137, 241, 187, 61, 16, 41, 20, 142, 13, 131, 11, 90, 19, 153, 218, 255, 16, 132, 4, 142, 123, 216, 219, 233, 248, 89, 0, 11, 227, 225, 235, 161, 122, 71, 63, 137, 176, 247, 232, 226, 73, 64, 242, 10, 235, 142, 188, 167, 26, 136, 253, 233, 93, 75, 131, 183, 26, 9, 5, 33, 159, 137, 154, 129, 212, 255, 132, 251, 89, 61, 46, 223, 138, 144, 172, 27, 58, 179, 66, 88, 247, 223, 35, 62, 165, 3, 2, 177, 189, 46, 113, 99, 38, 145, 255, 18, 151, 141, 114, 210, 40, 195, 146, 232, 115, 42, 123, 115, 199, 137, 26, 52, 227, 146, 215, 220, 71, 228, 185, 73, 34, 84, 3, 21, 6, 0, 1, 2, 8, 13, 14, 17, 242, 35, 198, 137, 82, 225, 242, 182, 255, 0, 202, 154, 59, 0, 0, 0, 0, 21, 12, 0, 1, 15, 16, 2, 8, 13, 3, 8, 17, 14, 18, 34, 102, 6, 61, 18, 1, 218, 235, 234, 255, 255, 0, 202, 154, 59, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 23, 0, 4, 1, 5, 15, 16, 2, 6, 8, 13, 7, 3, 8, 9, 8, 17, 14, 19, 20, 18, 10, 11, 12, 42, 37, 74, 217, 157, 79, 49, 35, 6, 255, 250, 0, 202, 154, 59, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255 };

var transaction = Transaction.Populate(Message.Deserialize(data));
transaction.PartialSign(buyerAccount);

var tx = transaction.Serialize();
var rpc = ClientFactory.GetClient(Cluster.MainNet);
var res = rpc.SendTransaction(tx, true, Types.Commitment.Confirmed);

**=> Failed : res.Reason = "invalid transaction: Transaction failed to sanitize accounts offsets correctly"**

Using AddSignature :

var walletMnemonic = "lens scheme misery search address destroy shallow police picture gown apart rural cotton vivid cage disagree enrich govern history kit early near cloth alarm";
var buyerAccount = (new Wallet.Wallet(walletMnemonic)).GetAccount(0);

-- This data comes from MagicEden using the test wallet above
 var data = new byte[] { 2, 1, 9, 22, 138, 180, 156, 252, 109, 252, 108, 26, 186, 0, 196, 69, 57, 102, 15, 151, 149, 242, 119, 181, 171, 113, 120, 224, 0, 118, 155, 61, 246, 56, 178, 47, 5, 127, 54, 85, 153, 40, 206, 27, 171, 173, 182, 91, 139, 93, 158, 49, 186, 39, 248, 83, 155, 236, 96, 44, 203, 26, 220, 42, 251, 159, 70, 112, 183, 85, 45, 211, 31, 117, 170, 249, 115, 142, 150, 7, 154, 72, 234, 129, 11, 230, 240, 210, 134, 238, 214, 97, 253, 27, 211, 30, 75, 60, 118, 127, 101, 227, 21, 206, 161, 126, 156, 225, 86, 221, 116, 65, 168, 99, 209, 82, 86, 59, 16, 110, 183, 108, 230, 243, 66, 64, 71, 40, 117, 164, 187, 99, 63, 134, 33, 168, 224, 98, 57, 6, 130, 207, 74, 70, 177, 120, 155, 22, 187, 210, 145, 210, 87, 121, 127, 133, 186, 230, 130, 227, 186, 45, 8, 203, 174, 193, 163, 124, 28, 112, 153, 122, 201, 57, 164, 147, 48, 3, 118, 148, 224, 223, 30, 201, 169, 42, 101, 186, 221, 16, 12, 105, 205, 206, 184, 40, 59, 36, 183, 144, 56, 251, 155, 81, 96, 93, 7, 7, 219, 43, 71, 8, 208, 98, 194, 93, 185, 165, 22, 67, 53, 73, 19, 3, 205, 198, 244, 136, 12, 158, 58, 228, 224, 183, 152, 74, 250, 18, 157, 96, 7, 160, 158, 224, 142, 150, 46, 161, 202, 218, 73, 218, 230, 18, 50, 147, 194, 191, 195, 125, 8, 175, 246, 228, 16, 89, 36, 102, 175, 155, 72, 107, 229, 118, 121, 242, 246, 139, 65, 205, 220, 49, 224, 32, 146, 119, 74, 143, 99, 98, 237, 19, 209, 153, 198, 66, 18, 170, 194, 214, 107, 34, 24, 236, 131, 130, 61, 208, 73, 81, 158, 126, 202, 103, 0, 217, 87, 191, 29, 139, 185, 179, 80, 124, 9, 53, 112, 39, 242, 45, 163, 184, 137, 196, 188, 191, 254, 181, 145, 62, 221, 231, 28, 53, 225, 167, 180, 239, 1, 79, 78, 188, 11, 127, 10, 244, 55, 72, 197, 77, 248, 37, 66, 27, 52, 17, 65, 62, 34, 245, 181, 2, 195, 178, 157, 92, 136, 150, 245, 185, 188, 43, 112, 46, 121, 233, 229, 183, 6, 65, 156, 6, 69, 48, 246, 214, 66, 103, 66, 217, 59, 252, 205, 155, 71, 130, 219, 39, 90, 159, 10, 158, 105, 79, 210, 149, 191, 206, 251, 237, 195, 27, 24, 204, 62, 20, 138, 10, 82, 147, 129, 137, 32, 237, 250, 237, 171, 57, 30, 73, 51, 108, 11, 116, 219, 102, 157, 16, 71, 3, 66, 75, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 159, 168, 130, 96, 176, 127, 33, 78, 199, 111, 187, 23, 51, 224, 75, 77, 123, 238, 132, 54, 175, 209, 79, 66, 238, 152, 255, 201, 92, 49, 107, 204, 100, 183, 92, 7, 83, 215, 231, 109, 133, 77, 59, 235, 252, 5, 77, 52, 253, 206, 87, 198, 134, 219, 200, 139, 133, 234, 2, 250, 83, 168, 138, 53, 6, 221, 246, 225, 215, 101, 161, 147, 217, 203, 225, 70, 206, 235, 121, 172, 28, 180, 133, 237, 95, 91, 55, 145, 58, 140, 245, 133, 126, 255, 0, 169, 6, 167, 213, 23, 25, 44, 92, 81, 33, 140, 201, 76, 61, 74, 241, 127, 88, 218, 238, 8, 155, 161, 253, 68, 227, 219, 217, 138, 0, 0, 0, 0, 140, 151, 37, 143, 78, 36, 137, 241, 187, 61, 16, 41, 20, 142, 13, 131, 11, 90, 19, 153, 218, 255, 16, 132, 4, 142, 123, 216, 219, 233, 248, 89, 0, 11, 227, 225, 235, 161, 122, 71, 63, 137, 176, 247, 232, 226, 73, 64, 242, 10, 235, 142, 188, 167, 26, 136, 253, 233, 93, 75, 131, 183, 26, 9, 5, 33, 159, 137, 154, 129, 212, 255, 132, 251, 89, 61, 46, 223, 138, 144, 172, 27, 58, 179, 66, 88, 247, 223, 35, 62, 165, 3, 2, 177, 189, 46, 113, 99, 38, 145, 255, 18, 151, 141, 114, 210, 40, 195, 146, 232, 115, 42, 123, 115, 199, 137, 26, 52, 227, 146, 215, 220, 71, 228, 185, 73, 34, 84, 3, 21, 6, 0, 1, 2, 8, 13, 14, 17, 242, 35, 198, 137, 82, 225, 242, 182, 255, 0, 202, 154, 59, 0, 0, 0, 0, 21, 12, 0, 1, 15, 16, 2, 8, 13, 3, 8, 17, 14, 18, 34, 102, 6, 61, 18, 1, 218, 235, 234, 255, 255, 0, 202, 154, 59, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 23, 0, 4, 1, 5, 15, 16, 2, 6, 8, 13, 7, 3, 8, 9, 8, 17, 14, 19, 20, 18, 10, 11, 12, 42, 37, 74, 217, 157, 79, 49, 35, 6, 255, 250, 0, 202, 154, 59, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255 };

var signature = buyerAccount.Sign(data);
var transaction = Transaction.Populate(Message.Deserialize(data));
transaction.AddSignature(buyerAccount, signature);

var tx = transaction.Serialize();
var rpc = ClientFactory.GetClient(Cluster.MainNet);
var res = rpc.SendTransaction(tx, true, Types.Commitment.Confirmed);

**=> Failed : res.Reason = "invalid transaction: Transaction failed to sanitize accounts offsets correctly"**

Note : In BOTH case, the new generated tx has for the first byte the value 1 while I expect it to still be 2 (2 signers required).

Also (using the same partially signed data)

var transaction = Transaction.Populate(Message.Deserialize(data));
var tx = transaction.Serialize();

transaction = Transaction.Populate(Message.Deserialize(tx));

i would expect this code to works but it throw the exception below

Exception has occurred: CLR/System.IndexOutOfRangeException
An exception of type 'System.IndexOutOfRangeException' occurred in System.Private.CoreLib.dll but was not handled in user code: 'Index was outside the bounds of the array.'
   at System.ThrowHelper.ThrowIndexOutOfRangeException()
   at System.ReadOnlySpan`1.get_Item(Int32 index)
   at Solnet.Rpc.Models.CompiledInstruction.Deserialize(ReadOnlySpan`1 data) in /Users/bouh/Development/Solnet/src/Solnet.Rpc/Models/TransactionInstruction.cs:line 104
   at Solnet.Rpc.Models.Message.Deserialize(ReadOnlySpan`1 data) in /Users/bouh/Development/Solnet/src/Solnet.Rpc/Models/Message.cs:line 200
   at Solnet.Rpc.Test.TransactionTest.PartialSignME3Test() in /Users/bouh/Development/Solnet/test/Solnet.Rpc.Test/TransactionTest.cs:line 430

I expect the (re)serialized tx to be the same as the data but it's not. The Serialized() method added an extra byte of value 0

[ Capture d’écran 2022-06-17 à 10 54 22 ]

nazbrok avatar Jun 17 '22 09:06 nazbrok

Is that payload the entire payload?

I tried decoding it and it decodes perfectly as a Message, and all bytes are consumed. The message part is only the contents of the transaction (instructions), it contains no signatures. The header of the message starts with the # of required signatures for that given message. The header for the transaction starts with the number of signatures that follows the first byte.

The reason a Message starts with byte 2, gets prepended the byte 0 as a transaction is because you have a message with 2 required signatures, and put it together as a transaction with 0 signatures.

The only reason I see this happening is that something might be missing from that payload. I don't have time right now to dig deeper into this, so it will have to wait for the weekend.

Paging @murlokito to give this a second look, as he is the expert on partial signatures as he did here.

tiago18c avatar Jun 17 '22 18:06 tiago18c

My mistake, they updated their Json structure and added a second entry for the signed tx.

Gonna do further test to see if all is ok.

nazbrok avatar Jun 17 '22 20:06 nazbrok

So here is the actual Json :

{"tx":
    {"type":"Buffer","data":[2,1,9,21,138,180,156,252,109,252,108,26,186,0,196,69,57,102,15,151,149,242,119,181,171,113,120,224,0,118,155,61,246,56,178,47,5,127,54,85,153,40,206,27,171,173,182,91,139,93,158,49,186,39,248,83,155,236,96,44,203,26,220,42,251,159,70,112,183,85,45,211,31,117,170,249,115,142,150,7,154,72,234,129,11,230,240,210,134,238,214,97,253,27,211,30,75,60,118,127,218,176,102,253,138,71,38,27,7,235,46,158,242,104,170,249,49,171,231,130,73,47,250,5,136,65,180,48,162,196,127,192,178,248,17,88,10,67,202,209,218,64,160,122,201,124,188,183,138,1,80,124,103,191,46,109,19,251,220,6,232,127,202,86,104,121,236,161,163,145,22,104,251,214,195,167,40,144,165,137,125,103,252,82,238,244,187,231,34,135,239,204,177,236,32,22,219,249,47,88,27,43,106,93,53,216,83,236,153,109,229,251,36,9,200,49,145,15,129,77,34,112,114,173,36,62,236,110,12,158,58,228,224,183,152,74,250,18,157,96,7,160,158,224,142,150,46,161,202,218,73,218,230,18,50,147,194,191,195,125,8,175,246,228,16,89,36,102,175,155,72,107,229,118,121,242,246,139,65,205,220,49,224,32,146,119,74,143,99,98,237,19,13,132,117,14,245,6,153,169,85,40,27,100,21,174,68,187,108,212,30,222,128,217,201,249,45,138,186,94,166,187,10,235,41,205,82,109,253,176,130,42,238,206,165,200,24,50,188,208,215,135,5,248,131,82,116,201,31,159,53,80,184,225,198,95,236,2,240,147,220,248,179,32,243,104,68,185,1,15,88,227,79,223,130,47,250,151,111,36,193,141,55,202,21,126,183,103,195,27,24,204,62,20,138,10,82,147,129,137,32,237,250,237,171,57,30,73,51,108,11,116,219,102,157,16,71,3,66,75,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,93,243,113,106,118,124,29,94,205,38,194,235,5,148,37,179,98,119,9,113,206,219,131,76,219,44,227,175,199,22,189,116,235,174,247,254,13,195,90,171,13,244,110,2,65,58,174,203,197,197,222,179,199,159,186,249,24,233,203,208,43,166,206,6,221,246,225,215,101,161,147,217,203,225,70,206,235,121,172,28,180,133,237,95,91,55,145,58,140,245,133,126,255,0,169,6,167,213,23,25,44,92,81,33,140,201,76,61,74,241,127,88,218,238,8,155,161,253,68,227,219,217,138,0,0,0,0,140,151,37,143,78,36,137,241,187,61,16,41,20,142,13,131,11,90,19,153,218,255,16,132,4,142,123,216,219,233,248,89,0,11,227,225,235,161,122,71,63,137,176,247,232,226,73,64,242,10,235,142,188,167,26,136,253,233,93,75,131,183,26,9,5,33,159,137,154,129,212,255,132,251,89,61,46,223,138,144,172,27,58,179,66,88,247,223,35,62,165,3,2,177,189,46,25,81,161,120,205,221,148,12,81,228,109,193,138,66,240,124,244,131,160,152,232,136,137,76,110,42,15,170,244,59,99,147,3,20,6,0,1,2,8,12,13,17,242,35,198,137,82,225,242,182,255,0,0,0,0,0,0,0,0,20,12,0,1,14,15,2,8,12,3,8,16,13,17,34,102,6,61,18,1,218,235,234,252,255,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,22,0,4,1,5,14,15,2,6,8,12,7,3,8,9,8,16,13,18,19,17,10,11,42,37,74,217,157,79,49,35,6,255,250,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255]},
 "txSigned":
    {"type":"Buffer","data":[2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,101,129,74,17,32,0,255,158,115,99,39,240,246,70,239,176,137,61,191,181,74,239,161,238,51,192,66,152,252,175,211,133,206,87,198,87,97,225,124,109,26,59,186,58,122,100,158,92,25,182,142,77,70,189,254,192,177,4,189,44,40,44,20,15,2,1,9,21,138,180,156,252,109,252,108,26,186,0,196,69,57,102,15,151,149,242,119,181,171,113,120,224,0,118,155,61,246,56,178,47,5,127,54,85,153,40,206,27,171,173,182,91,139,93,158,49,186,39,248,83,155,236,96,44,203,26,220,42,251,159,70,112,183,85,45,211,31,117,170,249,115,142,150,7,154,72,234,129,11,230,240,210,134,238,214,97,253,27,211,30,75,60,118,127,8,175,246,228,16,89,36,102,175,155,72,107,229,118,121,242,246,139,65,205,220,49,224,32,146,119,74,143,99,98,237,19,218,176,102,253,138,71,38,27,7,235,46,158,242,104,170,249,49,171,231,130,73,47,250,5,136,65,180,48,162,196,127,192,178,248,17,88,10,67,202,209,218,64,160,122,201,124,188,183,138,1,80,124,103,191,46,109,19,251,220,6,232,127,202,86,104,121,236,161,163,145,22,104,251,214,195,167,40,144,165,137,125,103,252,82,238,244,187,231,34,135,239,204,177,236,32,22,219,249,47,88,27,43,106,93,53,216,83,236,153,109,229,251,36,9,200,49,145,15,129,77,34,112,114,173,36,62,236,110,12,158,58,228,224,183,152,74,250,18,157,96,7,160,158,224,142,150,46,161,202,218,73,218,230,18,50,147,194,191,195,125,13,132,117,14,245,6,153,169,85,40,27,100,21,174,68,187,108,212,30,222,128,217,201,249,45,138,186,94,166,187,10,235,41,205,82,109,253,176,130,42,238,206,165,200,24,50,188,208,215,135,5,248,131,82,116,201,31,159,53,80,184,225,198,95,236,2,240,147,220,248,179,32,243,104,68,185,1,15,88,227,79,223,130,47,250,151,111,36,193,141,55,202,21,126,183,103,195,27,24,204,62,20,138,10,82,147,129,137,32,237,250,237,171,57,30,73,51,108,11,116,219,102,157,16,71,3,66,75,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,93,243,113,106,118,124,29,94,205,38,194,235,5,148,37,179,98,119,9,113,206,219,131,76,219,44,227,175,199,22,189,116,235,174,247,254,13,195,90,171,13,244,110,2,65,58,174,203,197,197,222,179,199,159,186,249,24,233,203,208,43,166,206,6,221,246,225,215,101,161,147,217,203,225,70,206,235,121,172,28,180,133,237,95,91,55,145,58,140,245,133,126,255,0,169,6,167,213,23,25,44,92,81,33,140,201,76,61,74,241,127,88,218,238,8,155,161,253,68,227,219,217,138,0,0,0,0,140,151,37,143,78,36,137,241,187,61,16,41,20,142,13,131,11,90,19,153,218,255,16,132,4,142,123,216,219,233,248,89,0,11,227,225,235,161,122,71,63,137,176,247,232,226,73,64,242,10,235,142,188,167,26,136,253,233,93,75,131,183,26,9,5,33,159,137,154,129,212,255,132,251,89,61,46,223,138,144,172,27,58,179,66,88,247,223,35,62,165,3,2,177,189,46,25,81,161,120,205,221,148,12,81,228,109,193,138,66,240,124,244,131,160,152,232,136,137,76,110,42,15,170,244,59,99,147,3,20,6,0,1,2,3,12,13,17,242,35,198,137,82,225,242,182,255,0,0,0,0,0,0,0,0,20,12,0,1,14,15,2,3,12,4,3,16,13,17,34,102,6,61,18,1,218,235,234,252,255,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,22,0,5,1,6,14,15,2,7,3,12,8,4,3,9,3,16,13,18,19,17,10,11,42,37,74,217,157,79,49,35,6,255,250,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255,255,255]}}

The txSigned contains the partial signature in position 2.

using this code :

var walletMnemonic = "lens scheme misery search address destroy shallow police picture gown apart rural cotton vivid cage disagree enrich govern history kit early near cloth alarm";
var buyerAccount = (new Wallet.Wallet(walletMnemonic)).GetAccount(0);

var data = new byte[] { 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 101, 129, 74, 17, 32, 0, 255, 158, 115, 99, 39, 240, 246, 70, 239, 176, 137, 61, 191, 181, 74, 239, 161, 238, 51, 192, 66, 152, 252, 175, 211, 133, 206, 87, 198, 87, 97, 225, 124, 109, 26, 59, 186, 58, 122, 100, 158, 92, 25, 182, 142, 77, 70, 189, 254, 192, 177, 4, 189, 44, 40, 44, 20, 15, 2, 1, 9, 21, 138, 180, 156, 252, 109, 252, 108, 26, 186, 0, 196, 69, 57, 102, 15, 151, 149, 242, 119, 181, 171, 113, 120, 224, 0, 118, 155, 61, 246, 56, 178, 47, 5, 127, 54, 85, 153, 40, 206, 27, 171, 173, 182, 91, 139, 93, 158, 49, 186, 39, 248, 83, 155, 236, 96, 44, 203, 26, 220, 42, 251, 159, 70, 112, 183, 85, 45, 211, 31, 117, 170, 249, 115, 142, 150, 7, 154, 72, 234, 129, 11, 230, 240, 210, 134, 238, 214, 97, 253, 27, 211, 30, 75, 60, 118, 127, 8, 175, 246, 228, 16, 89, 36, 102, 175, 155, 72, 107, 229, 118, 121, 242, 246, 139, 65, 205, 220, 49, 224, 32, 146, 119, 74, 143, 99, 98, 237, 19, 218, 176, 102, 253, 138, 71, 38, 27, 7, 235, 46, 158, 242, 104, 170, 249, 49, 171, 231, 130, 73, 47, 250, 5, 136, 65, 180, 48, 162, 196, 127, 192, 178, 248, 17, 88, 10, 67, 202, 209, 218, 64, 160, 122, 201, 124, 188, 183, 138, 1, 80, 124, 103, 191, 46, 109, 19, 251, 220, 6, 232, 127, 202, 86, 104, 121, 236, 161, 163, 145, 22, 104, 251, 214, 195, 167, 40, 144, 165, 137, 125, 103, 252, 82, 238, 244, 187, 231, 34, 135, 239, 204, 177, 236, 32, 22, 219, 249, 47, 88, 27, 43, 106, 93, 53, 216, 83, 236, 153, 109, 229, 251, 36, 9, 200, 49, 145, 15, 129, 77, 34, 112, 114, 173, 36, 62, 236, 110, 12, 158, 58, 228, 224, 183, 152, 74, 250, 18, 157, 96, 7, 160, 158, 224, 142, 150, 46, 161, 202, 218, 73, 218, 230, 18, 50, 147, 194, 191, 195, 125, 13, 132, 117, 14, 245, 6, 153, 169, 85, 40, 27, 100, 21, 174, 68, 187, 108, 212, 30, 222, 128, 217, 201, 249, 45, 138, 186, 94, 166, 187, 10, 235, 41, 205, 82, 109, 253, 176, 130, 42, 238, 206, 165, 200, 24, 50, 188, 208, 215, 135, 5, 248, 131, 82, 116, 201, 31, 159, 53, 80, 184, 225, 198, 95, 236, 2, 240, 147, 220, 248, 179, 32, 243, 104, 68, 185, 1, 15, 88, 227, 79, 223, 130, 47, 250, 151, 111, 36, 193, 141, 55, 202, 21, 126, 183, 103, 195, 27, 24, 204, 62, 20, 138, 10, 82, 147, 129, 137, 32, 237, 250, 237, 171, 57, 30, 73, 51, 108, 11, 116, 219, 102, 157, 16, 71, 3, 66, 75, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 28, 93, 243, 113, 106, 118, 124, 29, 94, 205, 38, 194, 235, 5, 148, 37, 179, 98, 119, 9, 113, 206, 219, 131, 76, 219, 44, 227, 175, 199, 22, 189, 116, 235, 174, 247, 254, 13, 195, 90, 171, 13, 244, 110, 2, 65, 58, 174, 203, 197, 197, 222, 179, 199, 159, 186, 249, 24, 233, 203, 208, 43, 166, 206, 6, 221, 246, 225, 215, 101, 161, 147, 217, 203, 225, 70, 206, 235, 121, 172, 28, 180, 133, 237, 95, 91, 55, 145, 58, 140, 245, 133, 126, 255, 0, 169, 6, 167, 213, 23, 25, 44, 92, 81, 33, 140, 201, 76, 61, 74, 241, 127, 88, 218, 238, 8, 155, 161, 253, 68, 227, 219, 217, 138, 0, 0, 0, 0, 140, 151, 37, 143, 78, 36, 137, 241, 187, 61, 16, 41, 20, 142, 13, 131, 11, 90, 19, 153, 218, 255, 16, 132, 4, 142, 123, 216, 219, 233, 248, 89, 0, 11, 227, 225, 235, 161, 122, 71, 63, 137, 176, 247, 232, 226, 73, 64, 242, 10, 235, 142, 188, 167, 26, 136, 253, 233, 93, 75, 131, 183, 26, 9, 5, 33, 159, 137, 154, 129, 212, 255, 132, 251, 89, 61, 46, 223, 138, 144, 172, 27, 58, 179, 66, 88, 247, 223, 35, 62, 165, 3, 2, 177, 189, 46, 25, 81, 161, 120, 205, 221, 148, 12, 81, 228, 109, 193, 138, 66, 240, 124, 244, 131, 160, 152, 232, 136, 137, 76, 110, 42, 15, 170, 244, 59, 99, 147, 3, 20, 6, 0, 1, 2, 3, 12, 13, 17, 242, 35, 198, 137, 82, 225, 242, 182, 255, 0, 0, 0, 0, 0, 0, 0, 0, 20, 12, 0, 1, 14, 15, 2, 3, 12, 4, 3, 16, 13, 17, 34, 102, 6, 61, 18, 1, 218, 235, 234, 252, 255, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 22, 0, 5, 1, 6, 14, 15, 2, 7, 3, 12, 8, 4, 3, 9, 3, 16, 13, 18, 19, 17, 10, 11, 42, 37, 74, 217, 157, 79, 49, 35, 6, 255, 250, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255 };

var deserialized = Message.Deserialize(data);
var transaction = Transaction.Populate(deserialized);

I get this exception on the Populate instruction

Exception has occurred: CLR/System.ArgumentOutOfRangeException
An exception of type 'System.ArgumentOutOfRangeException' occurred in System.Private.CoreLib.dll but was not handled in user code: 'Index was out of range. Must be non-negative and less than the size of the collection.'
   at System.ThrowHelper.ThrowArgumentOutOfRange_IndexException()
   at System.Collections.Generic.List`1.get_Item(Int32 index)
   at Solnet.Rpc.Models.Transaction.Populate(Message message, IList`1 signatures) in /Users/bouh/Development/Solnet/src/Solnet.Rpc/Models/Transaction.cs:line 303
   at Solnet.Rpc.Test.TransactionTest.PartialSignME3Test() in /Users/bouh/Development/Solnet/test/Solnet.Rpc.Test/TransactionTest.cs:line 425

But the problem is inside the Message.Deserialize as the result is quite empty

Capture d’écran 2022-06-17 à 23 09 50

nazbrok avatar Jun 17 '22 21:06 nazbrok

Let me know if I am doing something wrong or want me to do more tests.

nazbrok avatar Jun 17 '22 21:06 nazbrok

Ahhh, thats looking better.

So, it goes back to my previous comment.

The "tx" object in that json is the Message contents, and you deserialize with Message.Deserialize(). The txSigned contains signatures and is an actual Transaction object, and you deserialize with var tx = Transaction.Deserialize(data).

Now the tricky part is that you need to look into the resulting transaction signatures, figure which one is supposed to be yours and replace with a valid signature. We could probably do some improvement here in the future, but for the given problem, you need to fill the first with the signature from the expected PK tx.Signatures[0].PublicKey.

This should work:

var tx = Transaction.Deserialize(data);

tx.Signatures[0] = new SignaturePubKeyPair() // first signature has to pay transaction fees, so its the reason they fill the second and yours needs to be first
{
        PublicKey = MY_PK, // tx.Signatures[0].PublicKey
        Signature = MY_SIGNATURE
};

var res = tx.Serialize();

Note: you only sign the stuff inside the "tx" object, not the "txSigned".

tiago18c avatar Jun 18 '22 22:06 tiago18c

I still can't get it working.

in both case (below), I get "Transaction signature verification failure"

            var txUnsigned = Transaction.Populate(Message.Deserialize(data.Tx));
            var txSigned = Transaction.Deserialize(data.TxSigned);

            txSigned.Signatures[0] = new SignaturePubKeyPair() // first signature has to pay transaction fees, so its the reason they fill the second and yours needs to be first
            {
                PublicKey = buyerAccount.PublicKey, // tx.Signatures[0].PublicKey
                Signature = buyerAccount.Sign(txUnsigned.CompileMessage())
            };

            var res = rpcClient.SendTransaction(txSigned.Serialize());

            txSigned.Signatures[0] = new SignaturePubKeyPair() // first signature has to pay transaction fees, so its the reason they fill the second and yours needs to be first
            {
                PublicKey = buyerAccount.PublicKey, // tx.Signatures[0].PublicKey
                Signature = buyerAccount.Sign(unsignedData)
            };

            res = rpcClient.SendTransaction(txSigned.Serialize());

What is weird is if I try to verify the 2nd signature it return false. I read in a discord someone had to use SendRawTransaction to make it works but this method isn't available on SolNet. Not sure if it would help though.

nazbrok avatar Jun 19 '22 21:06 nazbrok

This goes back to the problem of the keys orders! I'm going to implement this fix and ME aren't even following it.

If they use that in the future, you should be good to go. In the meantime, I suggest you hack them together (its even more performant than decoding and encoding things together):

            byte[] txSigned = data;
            byte[] txMessage = data[(1 + 64 * 2)..]; // advance sig count byte + signature bytes, or simply use the original object from the json

            var mySig = buyerAccount.Sign(txMessage);

            Array.Copy(mySig, 0, txSigned, 1, mySig.Length);

Then you can just send the txSigned array!

Heres the confirmation that the signatures now match:

            // verify signatures
            var tx = Transaction.Deserialize(txSigned);

            var s1 = tx.Signatures[0].PublicKey.Verify(txMessage, tx.Signatures[0].Signature); // true
            var s2 = tx.Signatures[1].PublicKey.Verify(txMessage, tx.Signatures[1].Signature); // true

            var badKeyOrdering = tx.VerifySignatures(); // returns false

tiago18c avatar Jun 20 '22 18:06 tiago18c

This trick did it. Many thanks

Capture d’écran 2022-06-20 à 22 21 02

nazbrok avatar Jun 20 '22 20:06 nazbrok

@nazbrok Hi Can You Send Your code ? Because i don't Create partially signed transaction

Mehrdadgame avatar Jan 25 '23 12:01 Mehrdadgame