1
+ using Solnet . Rpc . Models ;
2
+ using Solnet . Rpc . Utilities ;
3
+ using Solnet . Wallet ;
4
+ using Solnet . Wallet . Utilities ;
5
+ using System ;
6
+ using System . Collections . Generic ;
7
+ using System . IO ;
8
+ using System . Linq ;
9
+ using static Solnet . Rpc . Models . Message ;
10
+
11
+ namespace Solnet . Rpc . Builders
12
+ {
13
+ /// <summary>
14
+ /// A compiled instruction within the message.
15
+ /// </summary>
16
+ public class VersionedMessageBuilder : MessageBuilder
17
+ {
18
+
19
+ /// <summary>
20
+ /// Address Table Lookups
21
+ /// </summary>
22
+ public List < MessageAddressTableLookup > AddressTableLookups { get ; set ; }
23
+ public IList < PublicKey > AccountKeys { get ; internal set ; }
24
+
25
+ /// <summary>
26
+ /// Builds the message into the wire format.
27
+ /// </summary>
28
+ /// <returns>The encoded message.</returns>
29
+ internal override byte [ ] Build ( )
30
+ {
31
+ if ( RecentBlockHash == null && NonceInformation == null )
32
+ throw new Exception ( "recent block hash or nonce information is required" ) ;
33
+ if ( Instructions == null )
34
+ throw new Exception ( "no instructions provided in the transaction" ) ;
35
+
36
+ // In case the user specified nonce information, we'll use it.
37
+ if ( NonceInformation != null )
38
+ {
39
+ RecentBlockHash = NonceInformation . Nonce ;
40
+ _accountKeysList . Add ( NonceInformation . Instruction . Keys ) ;
41
+ _accountKeysList . Add ( AccountMeta . ReadOnly ( new PublicKey ( NonceInformation . Instruction . ProgramId ) ,
42
+ false ) ) ;
43
+ List < TransactionInstruction > newInstructions = new ( ) { NonceInformation . Instruction } ;
44
+ newInstructions . AddRange ( Instructions ) ;
45
+ Instructions = newInstructions ;
46
+ }
47
+
48
+ _messageHeader = new MessageHeader ( ) ;
49
+
50
+ List < AccountMeta > keysList = GetAccountKeys ( ) ;
51
+ byte [ ] accountAddressesLength = ShortVectorEncoding . EncodeLength ( keysList . Count ) ;
52
+ int compiledInstructionsLength = 0 ;
53
+ List < CompiledInstruction > compiledInstructions = new ( ) ;
54
+
55
+ foreach ( TransactionInstruction instruction in Instructions )
56
+ {
57
+ int keyCount = instruction . Keys . Count ;
58
+ byte [ ] keyIndices = new byte [ keyCount ] ;
59
+
60
+ if ( instruction . GetType ( ) == typeof ( VersionedTransactionInstruction ) )
61
+ {
62
+ keyIndices = ( ( VersionedTransactionInstruction ) instruction ) . KeyIndices ;
63
+ }
64
+ else
65
+ {
66
+ for ( int i = 0 ; i < keyCount ; i ++ )
67
+ {
68
+ keyIndices [ i ] = FindAccountIndex ( keysList , instruction . Keys [ i ] . PublicKey ) ;
69
+ }
70
+ }
71
+
72
+ CompiledInstruction compiledInstruction = new ( )
73
+ {
74
+ ProgramIdIndex = FindAccountIndex ( keysList , instruction . ProgramId ) ,
75
+ KeyIndicesCount = ShortVectorEncoding . EncodeLength ( keyIndices . Length ) ,
76
+ KeyIndices = keyIndices ,
77
+ DataLength = ShortVectorEncoding . EncodeLength ( instruction . Data . Length ) ,
78
+ Data = instruction . Data
79
+ } ;
80
+ compiledInstructions . Add ( compiledInstruction ) ;
81
+ compiledInstructionsLength += compiledInstruction . Length ( ) ;
82
+ }
83
+
84
+ int accountKeysBufferSize = _accountKeysList . AccountList . Count * 32 ;
85
+ MemoryStream accountKeysBuffer = new MemoryStream ( accountKeysBufferSize ) ;
86
+ byte [ ] instructionsLength = ShortVectorEncoding . EncodeLength ( compiledInstructions . Count ) ;
87
+
88
+ foreach ( AccountMeta accountMeta in keysList )
89
+ {
90
+ accountKeysBuffer . Write ( accountMeta . PublicKeyBytes , 0 , accountMeta . PublicKeyBytes . Length ) ;
91
+ if ( accountMeta . IsSigner )
92
+ {
93
+ _messageHeader . RequiredSignatures += 1 ;
94
+ if ( ! accountMeta . IsWritable )
95
+ _messageHeader . ReadOnlySignedAccounts += 1 ;
96
+ }
97
+ else
98
+ {
99
+ if ( ! accountMeta . IsWritable )
100
+ _messageHeader . ReadOnlyUnsignedAccounts += 1 ;
101
+ }
102
+ }
103
+
104
+ #region Build Message Body
105
+
106
+ int messageBufferSize = MessageHeader . Layout . HeaderLength + BlockHashLength +
107
+ accountAddressesLength . Length +
108
+ + instructionsLength . Length + compiledInstructionsLength + accountKeysBufferSize ;
109
+ MemoryStream buffer = new MemoryStream ( messageBufferSize ) ;
110
+ byte [ ] messageHeaderBytes = _messageHeader . ToBytes ( ) ;
111
+
112
+ buffer . Write ( new byte [ ] { 128 } , 0 , 1 ) ;
113
+ buffer . Write ( messageHeaderBytes , 0 , messageHeaderBytes . Length ) ;
114
+ buffer . Write ( accountAddressesLength , 0 , accountAddressesLength . Length ) ;
115
+ buffer . Write ( accountKeysBuffer . ToArray ( ) , 0 , accountKeysBuffer . ToArray ( ) . Length ) ;
116
+ var encodedRecentBlockHash = Encoders . Base58 . DecodeData ( RecentBlockHash ) ;
117
+ buffer . Write ( encodedRecentBlockHash , 0 , encodedRecentBlockHash . Length ) ;
118
+ buffer . Write ( instructionsLength , 0 , instructionsLength . Length ) ;
119
+
120
+ foreach ( CompiledInstruction compiledInstruction in compiledInstructions )
121
+ {
122
+ buffer . WriteByte ( compiledInstruction . ProgramIdIndex ) ;
123
+ buffer . Write ( compiledInstruction . KeyIndicesCount , 0 , compiledInstruction . KeyIndicesCount . Length ) ;
124
+ buffer . Write ( compiledInstruction . KeyIndices , 0 , compiledInstruction . KeyIndices . Length ) ;
125
+ buffer . Write ( compiledInstruction . DataLength , 0 , compiledInstruction . DataLength . Length ) ;
126
+ buffer . Write ( compiledInstruction . Data , 0 , compiledInstruction . Data . Length ) ;
127
+ }
128
+
129
+ #endregion
130
+
131
+ var serializeAddressTableLookups = AddressTableLookupUtils . SerializeAddressTableLookups ( AddressTableLookups ) ;
132
+ buffer . Write ( serializeAddressTableLookups , 0 , serializeAddressTableLookups . Length ) ;
133
+
134
+ return buffer . ToArray ( ) ;
135
+ }
136
+ }
137
+ }
0 commit comments