@@ -29,6 +29,7 @@ import (
2929 "github.com/gagliardetto/treeout"
3030 "github.com/mr-tron/base58"
3131 "go.uber.org/zap"
32+ "golang.org/x/sync/errgroup"
3233)
3334
3435type Transaction struct {
@@ -284,24 +285,25 @@ func NewTransaction(instructions []Instruction, recentBlockHash Hash, opts ...Tr
284285 }
285286 }
286287
287- programIDs := make (PublicKeySlice , 0 )
288- accounts := []* AccountMeta {}
288+ programIDsMap := make (map [PublicKey ]struct {}, len (instructions ))
289+
290+ total := 0
291+ for _ , instruction := range instructions {
292+ total += len (instruction .Accounts ())
293+ programIDsMap [instruction .ProgramID ()] = struct {}{}
294+ }
295+ accounts := make ([]* AccountMeta , 0 , total + len (programIDsMap ))
296+
289297 for _ , instruction := range instructions {
290298 accounts = append (accounts , instruction .Accounts ()... )
291- programIDs .UniqueAppend (instruction .ProgramID ())
292299 }
293300
294- // for IsInvoked check
295- programIDsMap := make (map [PublicKey ]struct {}, len (programIDs ))
296- // Add programID to the account list
297- for _ , programID := range programIDs {
301+ for programID := range programIDsMap {
298302 accounts = append (accounts , & AccountMeta {
299303 PublicKey : programID ,
300304 IsSigner : false ,
301305 IsWritable : false ,
302306 })
303-
304- programIDsMap [programID ] = struct {}{}
305307 }
306308
307309 // Sort. Prioritizing first by signer, then by writable
@@ -315,8 +317,8 @@ func NewTransaction(instructions []Instruction, recentBlockHash Hash, opts ...Tr
315317 return 0
316318 })
317319
318- uniqAccountsMap := map [PublicKey ]uint64 {}
319- uniqAccounts := []* AccountMeta {}
320+ uniqAccountsMap := make ( map [PublicKey ]uint64 , len ( accounts ))
321+ uniqAccounts := make ( []* AccountMeta , 0 , len ( accounts ))
320322 for _ , acc := range accounts {
321323 if index , found := uniqAccountsMap [acc .PublicKey ]; found {
322324 uniqAccounts [index ].IsWritable = uniqAccounts [index ].IsWritable || acc .IsWritable
@@ -334,6 +336,7 @@ func NewTransaction(instructions []Instruction, recentBlockHash Hash, opts ...Tr
334336 for idx , acc := range uniqAccounts {
335337 if acc .PublicKey .Equals (feePayer ) {
336338 feePayerIndex = idx
339+ break
337340 }
338341 }
339342 if debugNewTransaction {
@@ -379,6 +382,8 @@ func NewTransaction(instructions []Instruction, recentBlockHash Hash, opts ...Tr
379382 ReadonlyIndexes []uint8
380383 Readonly []PublicKey
381384 })
385+
386+ message .AccountKeys = make ([]PublicKey , 0 , len (allKeys ))
382387 for idx , acc := range allKeys {
383388
384389 if debugNewTransaction {
@@ -423,6 +428,14 @@ func NewTransaction(instructions []Instruction, recentBlockHash Hash, opts ...Tr
423428 var lookupsWritableKeys []PublicKey
424429 var lookupsReadOnlyKeys []PublicKey
425430 if len (lookupsMap ) > 0 {
431+ totalWritable , totalReadonly := 0 , 0
432+ for _ , l := range lookupsMap {
433+ totalWritable += len (l .Writable )
434+ totalReadonly += len (l .Readonly )
435+ }
436+ lookupsWritableKeys = make ([]PublicKey , 0 , totalWritable )
437+ lookupsReadOnlyKeys = make ([]PublicKey , 0 , totalReadonly )
438+
426439 lookups := make ([]MessageAddressTableLookup , 0 , len (lookupsMap ))
427440
428441 sortedLookupKeys := make (PublicKeySlice , 0 , len (lookupsMap ))
@@ -453,17 +466,17 @@ func NewTransaction(instructions []Instruction, recentBlockHash Hash, opts ...Tr
453466 }
454467
455468 var idx uint16
456- accountKeyIndex := make (map [string ]uint16 , len (message .AccountKeys )+ len (lookupsWritableKeys )+ len (lookupsReadOnlyKeys ))
469+ accountKeyIndex := make (map [PublicKey ]uint16 , len (message .AccountKeys )+ len (lookupsWritableKeys )+ len (lookupsReadOnlyKeys ))
457470 for _ , acc := range message .AccountKeys {
458- accountKeyIndex [acc . String () ] = idx
471+ accountKeyIndex [acc ] = idx
459472 idx ++
460473 }
461474 for _ , acc := range lookupsWritableKeys {
462- accountKeyIndex [acc . String () ] = idx
475+ accountKeyIndex [acc ] = idx
463476 idx ++
464477 }
465478 for _ , acc := range lookupsReadOnlyKeys {
466- accountKeyIndex [acc . String () ] = idx
479+ accountKeyIndex [acc ] = idx
467480 idx ++
468481 }
469482
@@ -479,14 +492,14 @@ func NewTransaction(instructions []Instruction, recentBlockHash Hash, opts ...Tr
479492 accounts = instruction .Accounts ()
480493 accountIndex := make ([]uint16 , len (accounts ))
481494 for idx , acc := range accounts {
482- accountIndex [idx ] = accountKeyIndex [acc .PublicKey . String () ]
495+ accountIndex [idx ] = accountKeyIndex [acc .PublicKey ]
483496 }
484497 data , err := instruction .Data ()
485498 if err != nil {
486499 return nil , fmt .Errorf ("unable to encode instructions [%d]: %w" , txIdx , err )
487500 }
488501 message .Instructions = append (message .Instructions , CompiledInstruction {
489- ProgramIDIndex : accountKeyIndex [instruction .ProgramID (). String () ],
502+ ProgramIDIndex : accountKeyIndex [instruction .ProgramID ()],
490503 Accounts : accountIndex ,
491504 Data : data ,
492505 })
@@ -576,15 +589,38 @@ func (tx *Transaction) PartialSign(getter privateKeyGetter) (out []Signature, er
576589 return nil , fmt .Errorf ("invalid signatures length, expected %d, actual %d" , len (signerKeys ), len (tx .Signatures ))
577590 }
578591
579- for i , key := range signerKeys {
580- privateKey := getter (key )
581- if privateKey != nil {
582- s , err := privateKey .Sign (messageContent )
583- if err != nil {
584- return nil , fmt .Errorf ("failed to signed with key %q: %w" , key .String (), err )
592+ // if signerKeys is len 1, spawning a goroutine is needless work
593+ if len (signerKeys ) > 1 {
594+ var g errgroup.Group
595+ for i , key := range signerKeys {
596+ privateKey := getter (key )
597+ if privateKey == nil {
598+ continue
599+ }
600+ g .Go (func () error {
601+ s , err := privateKey .Sign (messageContent )
602+ if err != nil {
603+ return fmt .Errorf ("failed to sign with key %q: %w" , key .String (), err )
604+ }
605+ // Directly assign the signature to the corresponding position in the transaction's signature slice
606+ tx .Signatures [i ] = s
607+ return nil
608+ })
609+ }
610+ if err := g .Wait (); err != nil {
611+ return nil , err
612+ }
613+ } else {
614+ for i , key := range signerKeys {
615+ privateKey := getter (key )
616+ if privateKey != nil {
617+ s , err := privateKey .Sign (messageContent )
618+ if err != nil {
619+ return nil , fmt .Errorf ("failed to signed with key %q: %w" , key .String (), err )
620+ }
621+ // Directly assign the signature to the corresponding position in the transaction's signature slice
622+ tx .Signatures [i ] = s
585623 }
586- // Directly assign the signature to the corresponding position in the transaction's signature slice
587- tx .Signatures [i ] = s
588624 }
589625 }
590626 return tx .Signatures , nil
0 commit comments