@@ -605,3 +605,230 @@ func (p *resourcePolicy) AvailableBox(app basics.AppIndex, name string, operatio
605
605
}
606
606
return p .tracker .addBox (app , name , readSize , * p .initialBoxSurplusReadBudget , p .ep .Proto .BytesPerBoxReference )
607
607
}
608
+
609
+ type TxnResources struct {
610
+ // The static fields are resource arrays that were given in the transaciton group and thus cannot be removed
611
+ // The assumption is that these are prefilled because of one of the following reaons:
612
+ // - This transaction has already been signed
613
+ // - One of the foreign arrays is accessed on-chain
614
+ StaticAssets map [basics.AssetIndex ]struct {}
615
+ StaticApps map [basics.AppIndex ]struct {}
616
+ StaticAccounts map [basics.Address ]struct {}
617
+ StaticBoxes map [logic.BoxRef ]struct {}
618
+
619
+ // The following fields are fields that are implicitly available to the transaction group from transaction fields
620
+ AssetFromField basics.AssetIndex
621
+ AppFromField basics.AppIndex
622
+ AccountsFromFields map [basics.Address ]struct {}
623
+
624
+ // These are the fields currently being populated, thus we can mutate them however we'd like
625
+ Assets map [basics.AssetIndex ]struct {}
626
+ Apps map [basics.AppIndex ]struct {}
627
+ Boxes map [logic.BoxRef ]struct {}
628
+ Accounts map [basics.Address ]struct {}
629
+
630
+ MaxTotalRefs int
631
+ MaxAccounts int
632
+ }
633
+
634
+ func (r * TxnResources ) getTotalRefs () int {
635
+ return len (r .Accounts ) + len (r .Assets ) + len (r .Apps ) + len (r .Boxes ) + len (r .StaticAccounts ) + len (r .StaticAssets ) + len (r .StaticApps ) + len (r .StaticBoxes )
636
+ }
637
+
638
+ // Methods for determining room for specific references
639
+
640
+ func (r * TxnResources ) hasRoom () bool {
641
+ return r .getTotalRefs () < r .MaxTotalRefs
642
+ }
643
+
644
+ func (r * TxnResources ) hasRoomForAccount () bool {
645
+ return r .hasRoom () && (len (r .Accounts )+ len (r .StaticAccounts )) < r .MaxAccounts
646
+ }
647
+
648
+ func (r * TxnResources ) hasRoomForCrossRef () bool {
649
+ return r .hasRoomForAccount () && r .getTotalRefs () < r .MaxTotalRefs - 1
650
+ }
651
+
652
+ func (r * TxnResources ) hasRoomForBoxWithApp () bool {
653
+ return r .getTotalRefs () < r .MaxTotalRefs - 1
654
+ }
655
+
656
+ // Methods for determining if a resource is available
657
+
658
+ func (r * TxnResources ) hasApp (app basics.AppIndex ) bool {
659
+ _ , hasStatic := r .StaticApps [app ]
660
+ _ , hasRef := r .Apps [app ]
661
+ return r .AppFromField == app || hasStatic || hasRef
662
+ }
663
+
664
+ func (r * TxnResources ) hasAsset (aid basics.AssetIndex ) bool {
665
+ _ , hasStatic := r .StaticAssets [aid ]
666
+ _ , hasRef := r .Assets [aid ]
667
+ return r .AssetFromField == aid || hasStatic || hasRef
668
+ }
669
+
670
+ func (r * TxnResources ) hasAccount (addr basics.Address ) bool {
671
+ _ , hasStatic := r .StaticAccounts [addr ]
672
+ _ , hasRef := r .Accounts [addr ]
673
+ _ , hasField := r .AccountsFromFields [addr ]
674
+
675
+ return hasField || hasStatic || hasRef
676
+ }
677
+
678
+ func (r * TxnResources ) addAccount (addr basics.Address ) {
679
+ r .Accounts [addr ] = struct {}{}
680
+ }
681
+
682
+ func (r * TxnResources ) addAsset (aid basics.AssetIndex ) {
683
+ r .Assets [aid ] = struct {}{}
684
+ }
685
+
686
+ func (r * TxnResources ) addApp (aid basics.AppIndex ) {
687
+ r .Apps [aid ] = struct {}{}
688
+ }
689
+
690
+ func (r * TxnResources ) addBox (app basics.AppIndex , name string ) {
691
+ r .Boxes [logic.BoxRef {App : app , Name : name }] = struct {}{}
692
+ }
693
+
694
+ type PopulatedArrays struct {
695
+ Accounts []basics.Address
696
+ Assets []basics.AssetIndex
697
+ Apps []basics.AppIndex
698
+ Boxes []logic.BoxRef
699
+ }
700
+
701
+ func (r * TxnResources ) getPopulatedArrays () PopulatedArrays {
702
+ accounts := make ([]basics.Address , 0 , len (r .Accounts )+ len (r .StaticAccounts ))
703
+ for account := range r .Accounts {
704
+ accounts = append (accounts , account )
705
+ }
706
+
707
+ assets := make ([]basics.AssetIndex , 0 , len (r .Assets )+ len (r .StaticAssets ))
708
+ for asset := range r .Assets {
709
+ assets = append (assets , asset )
710
+ }
711
+
712
+ apps := make ([]basics.AppIndex , 0 , len (r .Apps )+ len (r .StaticApps ))
713
+ for app := range r .Apps {
714
+ apps = append (apps , app )
715
+ }
716
+
717
+ boxes := make ([]logic.BoxRef , 0 , len (r .Boxes )+ len (r .StaticBoxes ))
718
+ for box := range r .Boxes {
719
+ boxes = append (boxes , box )
720
+ }
721
+
722
+ return PopulatedArrays {
723
+ Accounts : accounts ,
724
+ Assets : assets ,
725
+ Apps : apps ,
726
+ Boxes : boxes ,
727
+ }
728
+ }
729
+
730
+ type ResourcePopulator struct {
731
+ TxnResources []TxnResources
732
+ }
733
+
734
+ func (p * ResourcePopulator ) addTransaction (txn transactions.Transaction , groupIndex int ) {
735
+ p .TxnResources [groupIndex ] = TxnResources {
736
+ StaticAssets : make (map [basics.AssetIndex ]struct {}),
737
+ StaticApps : make (map [basics.AppIndex ]struct {}),
738
+ StaticAccounts : make (map [basics.Address ]struct {}),
739
+ StaticBoxes : make (map [logic.BoxRef ]struct {}),
740
+ AccountsFromFields : make (map [basics.Address ]struct {}),
741
+ Assets : make (map [basics.AssetIndex ]struct {}),
742
+ Apps : make (map [basics.AppIndex ]struct {}),
743
+ Accounts : make (map [basics.Address ]struct {}),
744
+ Boxes : make (map [logic.BoxRef ]struct {}),
745
+ // TODO: Get these values from the consensus params
746
+ MaxTotalRefs : 8 ,
747
+ MaxAccounts : 4 ,
748
+ }
749
+
750
+ // The Sender and RekeyTo will always be implicitly available for every transaction type
751
+ p .TxnResources [groupIndex ].AccountsFromFields [txn .Sender ] = struct {}{}
752
+ p .TxnResources [groupIndex ].StaticAccounts [txn .RekeyTo ] = struct {}{}
753
+
754
+ if txn .Type == protocol .ApplicationCallTx {
755
+ for _ , asset := range txn .ForeignAssets {
756
+ p .TxnResources [groupIndex ].StaticAssets [asset ] = struct {}{}
757
+ }
758
+
759
+ for _ , app := range txn .ForeignApps {
760
+ p .TxnResources [groupIndex ].StaticApps [app ] = struct {}{}
761
+ }
762
+
763
+ for _ , account := range txn .Accounts {
764
+ p .TxnResources [groupIndex ].StaticAccounts [account ] = struct {}{}
765
+ }
766
+
767
+ for _ , box := range txn .Boxes {
768
+ ref := logic.BoxRef {App : txn .ForeignApps [box .Index ], Name : string (box .Name )}
769
+ p .TxnResources [groupIndex ].StaticBoxes [ref ] = struct {}{}
770
+ }
771
+
772
+ p .TxnResources [groupIndex ].AppFromField = txn .ApplicationID
773
+
774
+ return
775
+ }
776
+
777
+ if txn .Type == protocol .AssetTransferTx {
778
+ p .TxnResources [groupIndex ].AssetFromField = txn .XferAsset
779
+
780
+ p .TxnResources [groupIndex ].AccountsFromFields [txn .AssetReceiver ] = struct {}{}
781
+ p .TxnResources [groupIndex ].AccountsFromFields [txn .AssetCloseTo ] = struct {}{}
782
+ p .TxnResources [groupIndex ].AccountsFromFields [txn .AssetSender ] = struct {}{}
783
+
784
+ return
785
+ }
786
+
787
+ if txn .Type == protocol .PaymentTx {
788
+ p .TxnResources [groupIndex ].AccountsFromFields [txn .Receiver ] = struct {}{}
789
+ p .TxnResources [groupIndex ].AccountsFromFields [txn .CloseRemainderTo ] = struct {}{}
790
+
791
+ return
792
+ }
793
+
794
+ if txn .Type == protocol .AssetConfigTx {
795
+ p .TxnResources [groupIndex ].AssetFromField = txn .ConfigAsset
796
+
797
+ return
798
+ }
799
+
800
+ if txn .Type == protocol .AssetFreezeTx {
801
+ p .TxnResources [groupIndex ].AssetFromField = txn .FreezeAsset
802
+ p .TxnResources [groupIndex ].AccountsFromFields [txn .FreezeAccount ] = struct {}{}
803
+
804
+ return
805
+ }
806
+ }
807
+
808
+ func (p * ResourcePopulator ) populateResources (groupResourceTracker groupResourceTracker ) {
809
+ for i , tracker := range groupResourceTracker .localTxnResources {
810
+ for asset := range tracker .Assets {
811
+ p .TxnResources [i ].addAsset (asset )
812
+ }
813
+
814
+ for app := range tracker .Apps {
815
+ p .TxnResources [i ].addApp (app )
816
+ }
817
+
818
+ for account := range tracker .Accounts {
819
+ p .TxnResources [i ].addAccount (account )
820
+ }
821
+ }
822
+ }
823
+
824
+ func MakeResourcePopulator (txnGroup []transactions.SignedTxnWithAD ) ResourcePopulator {
825
+ populator := ResourcePopulator {
826
+ TxnResources : make ([]TxnResources , len (txnGroup )),
827
+ }
828
+
829
+ for i , txn := range txnGroup {
830
+ populator .addTransaction (txn .Txn , i )
831
+ }
832
+
833
+ return populator
834
+ }
0 commit comments