55 "encoding/base64"
66 "errors"
77 "fmt"
8+ "slices"
89 "sort"
910 "strconv"
1011 "strings"
@@ -34,19 +35,6 @@ func decodeDigest(str *string, field string, errorArr []string) (string, []strin
3435 return "" , errorArr
3536}
3637
37- // decodeAddress returns the byte representation of the input string, or appends an error to errorArr
38- func decodeAddress (str * string , field string , errorArr []string ) ([]byte , []string ) {
39- if str != nil {
40- addr , err := sdk .DecodeAddress (* str )
41- if err != nil {
42- return nil , append (errorArr , fmt .Sprintf ("%s '%s': %v" , errUnableToParseAddress , field , err ))
43- }
44- return addr [:], errorArr
45- }
46- // Pass through
47- return nil , errorArr
48- }
49-
5038// decodeAddress converts the role information into a bitmask, or appends an error to errorArr
5139func decodeAddressRole (role * string , excludeCloseTo * bool , errorArr []string ) (idb.AddressRole , []string ) {
5240 // If the string is nil, return early.
@@ -298,6 +286,94 @@ func txnRowToTransaction(row idb.TxnRow) (generated.Transaction, error) {
298286 return txn , nil
299287}
300288
289+ func hdrRowToBlock (row idb.BlockRow ) generated.Block {
290+
291+ rewards := generated.BlockRewards {
292+ FeeSink : row .BlockHeader .FeeSink .String (),
293+ RewardsCalculationRound : uint64 (row .BlockHeader .RewardsRecalculationRound ),
294+ RewardsLevel : row .BlockHeader .RewardsLevel ,
295+ RewardsPool : row .BlockHeader .RewardsPool .String (),
296+ RewardsRate : row .BlockHeader .RewardsRate ,
297+ RewardsResidue : row .BlockHeader .RewardsResidue ,
298+ }
299+
300+ upgradeState := generated.BlockUpgradeState {
301+ CurrentProtocol : string (row .BlockHeader .CurrentProtocol ),
302+ NextProtocol : strPtr (string (row .BlockHeader .NextProtocol )),
303+ NextProtocolApprovals : uint64Ptr (row .BlockHeader .NextProtocolApprovals ),
304+ NextProtocolSwitchOn : uint64Ptr (uint64 (row .BlockHeader .NextProtocolSwitchOn )),
305+ NextProtocolVoteBefore : uint64Ptr (uint64 (row .BlockHeader .NextProtocolVoteBefore )),
306+ }
307+
308+ upgradeVote := generated.BlockUpgradeVote {
309+ UpgradeApprove : boolPtr (row .BlockHeader .UpgradeApprove ),
310+ UpgradeDelay : uint64Ptr (uint64 (row .BlockHeader .UpgradeDelay )),
311+ UpgradePropose : strPtr (string (row .BlockHeader .UpgradePropose )),
312+ }
313+
314+ var partUpdates * generated.ParticipationUpdates = & generated.ParticipationUpdates {}
315+ if len (row .BlockHeader .ExpiredParticipationAccounts ) > 0 {
316+ addrs := make ([]string , len (row .BlockHeader .ExpiredParticipationAccounts ))
317+ for i := 0 ; i < len (addrs ); i ++ {
318+ addrs [i ] = row .BlockHeader .ExpiredParticipationAccounts [i ].String ()
319+ }
320+ partUpdates .ExpiredParticipationAccounts = strArrayPtr (addrs )
321+ }
322+ if len (row .BlockHeader .AbsentParticipationAccounts ) > 0 {
323+ addrs := make ([]string , len (row .BlockHeader .AbsentParticipationAccounts ))
324+ for i := 0 ; i < len (addrs ); i ++ {
325+ addrs [i ] = row .BlockHeader .AbsentParticipationAccounts [i ].String ()
326+ }
327+ partUpdates .AbsentParticipationAccounts = strArrayPtr (addrs )
328+ }
329+ if * partUpdates == (generated.ParticipationUpdates {}) {
330+ partUpdates = nil
331+ }
332+
333+ // order these so they're deterministic
334+ orderedTrackingTypes := make ([]sdk.StateProofType , len (row .BlockHeader .StateProofTracking ))
335+ trackingArray := make ([]generated.StateProofTracking , len (row .BlockHeader .StateProofTracking ))
336+ elems := 0
337+ for key := range row .BlockHeader .StateProofTracking {
338+ orderedTrackingTypes [elems ] = key
339+ elems ++
340+ }
341+ slices .Sort (orderedTrackingTypes )
342+ for i := 0 ; i < len (orderedTrackingTypes ); i ++ {
343+ stpfTracking := row .BlockHeader .StateProofTracking [orderedTrackingTypes [i ]]
344+ thing1 := generated.StateProofTracking {
345+ NextRound : uint64Ptr (uint64 (stpfTracking .StateProofNextRound )),
346+ Type : uint64Ptr (uint64 (orderedTrackingTypes [i ])),
347+ VotersCommitment : byteSliceOmitZeroPtr (stpfTracking .StateProofVotersCommitment ),
348+ OnlineTotalWeight : uint64Ptr (uint64 (stpfTracking .StateProofOnlineTotalWeight )),
349+ }
350+ trackingArray [orderedTrackingTypes [i ]] = thing1
351+ }
352+
353+ ret := generated.Block {
354+ Bonus : uint64PtrOrNil (uint64 (row .BlockHeader .Bonus )),
355+ FeesCollected : uint64PtrOrNil (uint64 (row .BlockHeader .FeesCollected )),
356+ GenesisHash : row .BlockHeader .GenesisHash [:],
357+ GenesisId : row .BlockHeader .GenesisID ,
358+ ParticipationUpdates : partUpdates ,
359+ PreviousBlockHash : row .BlockHeader .Branch [:],
360+ Proposer : addrPtr (row .BlockHeader .Proposer ),
361+ ProposerPayout : uint64PtrOrNil (uint64 (row .BlockHeader .ProposerPayout )),
362+ Rewards : & rewards ,
363+ Round : uint64 (row .BlockHeader .Round ),
364+ Seed : row .BlockHeader .Seed [:],
365+ StateProofTracking : & trackingArray ,
366+ Timestamp : uint64 (row .BlockHeader .TimeStamp ),
367+ Transactions : nil ,
368+ TransactionsRoot : row .BlockHeader .TxnCommitments .NativeSha512_256Commitment [:],
369+ TransactionsRootSha256 : row .BlockHeader .TxnCommitments .Sha256Commitment [:],
370+ TxnCounter : uint64Ptr (row .BlockHeader .TxnCounter ),
371+ UpgradeState : & upgradeState ,
372+ UpgradeVote : & upgradeVote ,
373+ }
374+ return ret
375+ }
376+
301377func signedTxnWithAdToTransaction (stxn * sdk.SignedTxnWithAD , extra rowData ) (generated.Transaction , error ) {
302378 var payment * generated.TransactionPayment
303379 var keyreg * generated.TransactionKeyreg
@@ -640,9 +716,14 @@ func edIndexToAddress(index uint64, txn sdk.Transaction, shared []sdk.Address) (
640716}
641717
642718func (si * ServerImplementation ) assetParamsToAssetQuery (params generated.SearchForAssetsParams ) (idb.AssetsQuery , error ) {
643- creator , errorArr := decodeAddress (params .Creator , "creator" , make ([]string , 0 ))
644- if len (errorArr ) != 0 {
645- return idb.AssetsQuery {}, errors .New (errUnableToParseAddress )
719+
720+ var creatorAddressBytes []byte
721+ if params .Creator != nil {
722+ creator , err := sdk .DecodeAddress (* params .Creator )
723+ if err != nil {
724+ return idb.AssetsQuery {}, fmt .Errorf ("unable to parse creator address: %w" , err )
725+ }
726+ creatorAddressBytes = creator [:]
646727 }
647728
648729 var assetGreaterThan * uint64
@@ -657,7 +738,7 @@ func (si *ServerImplementation) assetParamsToAssetQuery(params generated.SearchF
657738 query := idb.AssetsQuery {
658739 AssetID : params .AssetId ,
659740 AssetIDGreaterThan : assetGreaterThan ,
660- Creator : creator ,
741+ Creator : creatorAddressBytes ,
661742 Name : strOrDefault (params .Name ),
662743 Unit : strOrDefault (params .Unit ),
663744 Query : "" ,
@@ -669,9 +750,14 @@ func (si *ServerImplementation) assetParamsToAssetQuery(params generated.SearchF
669750}
670751
671752func (si * ServerImplementation ) appParamsToApplicationQuery (params generated.SearchForApplicationsParams ) (idb.ApplicationQuery , error ) {
672- addr , errorArr := decodeAddress (params .Creator , "creator" , make ([]string , 0 ))
673- if len (errorArr ) != 0 {
674- return idb.ApplicationQuery {}, errors .New (errUnableToParseAddress )
753+
754+ var creatorAddressBytes []byte
755+ if params .Creator != nil {
756+ addr , err := sdk .DecodeAddress (* params .Creator )
757+ if err != nil {
758+ return idb.ApplicationQuery {}, fmt .Errorf ("unable to parse creator address: %w" , err )
759+ }
760+ creatorAddressBytes = addr [:]
675761 }
676762
677763 var appGreaterThan * uint64
@@ -686,7 +772,7 @@ func (si *ServerImplementation) appParamsToApplicationQuery(params generated.Sea
686772 return idb.ApplicationQuery {
687773 ApplicationID : params .ApplicationId ,
688774 ApplicationIDGreaterThan : appGreaterThan ,
689- Address : addr ,
775+ Address : creatorAddressBytes ,
690776 IncludeDeleted : boolOrDefault (params .IncludeAll ),
691777 Limit : min (uintOrDefaultValue (params .Limit , si .opts .DefaultApplicationsLimit ), si .opts .MaxApplicationsLimit ),
692778 }, nil
@@ -708,7 +794,15 @@ func (si *ServerImplementation) transactionParamsToTransactionFilter(params gene
708794 filter .NextToken = strOrDefault (params .Next )
709795
710796 // Address
711- filter .Address , errorArr = decodeAddress (params .Address , "address" , errorArr )
797+ if params .Address != nil {
798+ addr , err := sdk .DecodeAddress (* params .Address )
799+ if err != nil {
800+ errorArr = append (errorArr , fmt .Sprintf ("%s: %v" , errUnableToParseAddress , err ))
801+ }
802+ filter .Address = addr [:]
803+ }
804+
805+ // Txid
712806 filter .Txid , errorArr = decodeDigest (params .Txid , "txid" , errorArr )
713807
714808 // Byte array
@@ -749,6 +843,112 @@ func (si *ServerImplementation) transactionParamsToTransactionFilter(params gene
749843 return
750844}
751845
846+ func (si * ServerImplementation ) blockParamsToBlockFilter (params generated.SearchForBlockHeadersParams ) (filter idb.BlockHeaderFilter , err error ) {
847+
848+ var errs []error
849+
850+ // Integer
851+ filter .Limit = min (uintOrDefaultValue (params .Limit , si .opts .DefaultBlocksLimit ), si .opts .MaxBlocksLimit )
852+ // If min/max are mixed up
853+ //
854+ // This check is performed here instead of in validateBlockFilter because
855+ // when converting params into a filter, the next token is merged with params.MinRound.
856+ if params .MinRound != nil && params .MaxRound != nil && * params .MinRound > * params .MaxRound {
857+ errs = append (errs , errors .New (errInvalidRoundMinMax ))
858+ }
859+ filter .MaxRound = params .MaxRound
860+ filter .MinRound = params .MinRound
861+
862+ // String
863+ if params .Next != nil {
864+ n , err := idb .DecodeBlockRowNext (* params .Next )
865+ if err != nil {
866+ errs = append (errs , fmt .Errorf ("%s: %w" , errUnableToParseNext , err ))
867+ }
868+ // Set the MinRound
869+ if filter .MinRound == nil {
870+ filter .MinRound = uint64Ptr (n + 1 )
871+ } else {
872+ filter .MinRound = uint64Ptr (max (* filter .MinRound , n + 1 ))
873+ }
874+ }
875+
876+ // Time
877+ if params .AfterTime != nil {
878+ filter .AfterTime = * params .AfterTime
879+ }
880+ if params .BeforeTime != nil {
881+ filter .BeforeTime = * params .BeforeTime
882+ }
883+
884+ // Address list
885+ {
886+ // Make sure at most one of the participation parameters is set
887+ numParticipationFilters := 0
888+ if params .Proposers != nil {
889+ numParticipationFilters ++
890+ }
891+ if params .Expired != nil {
892+ numParticipationFilters ++
893+ }
894+ if params .Absent != nil {
895+ numParticipationFilters ++
896+ }
897+ if numParticipationFilters > 1 {
898+ errs = append (errs , errors .New ("only one of `proposer`, `expired`, or `absent` can be specified" ))
899+ }
900+
901+ // Validate the number of items in the participation account lists
902+ if params .Proposers != nil && uint64 (len (* params .Proposers )) > si .opts .MaxAccountListSize {
903+ errs = append (errs , fmt .Errorf ("proposers list too long, max size is %d" , si .opts .MaxAccountListSize ))
904+ }
905+ if params .Expired != nil && uint64 (len (* params .Expired )) > si .opts .MaxAccountListSize {
906+ errs = append (errs , fmt .Errorf ("expired list too long, max size is %d" , si .opts .MaxAccountListSize ))
907+ }
908+ if params .Absent != nil && uint64 (len (* params .Absent )) > si .opts .MaxAccountListSize {
909+ errs = append (errs , fmt .Errorf ("absent list too long, max size is %d" , si .opts .MaxAccountListSize ))
910+ }
911+
912+ filter .Proposers = make (map [sdk.Address ]struct {}, 0 )
913+ if params .Proposers != nil {
914+ for _ , s := range * params .Proposers {
915+ addr , err := sdk .DecodeAddress (s )
916+ if err != nil {
917+ errs = append (errs , fmt .Errorf ("unable to parse proposer address `%s`: %w" , s , err ))
918+ } else {
919+ filter .Proposers [addr ] = struct {}{}
920+ }
921+ }
922+ }
923+
924+ filter .ExpiredParticipationAccounts = make (map [sdk.Address ]struct {}, 0 )
925+ if params .Expired != nil {
926+ for _ , s := range * params .Expired {
927+ addr , err := sdk .DecodeAddress (s )
928+ if err != nil {
929+ errs = append (errs , fmt .Errorf ("unable to parse expired address `%s`: %w" , s , err ))
930+ } else {
931+ filter .ExpiredParticipationAccounts [addr ] = struct {}{}
932+ }
933+ }
934+ }
935+
936+ filter .AbsentParticipationAccounts = make (map [sdk.Address ]struct {}, 0 )
937+ if params .Absent != nil {
938+ for _ , s := range * params .Absent {
939+ addr , err := sdk .DecodeAddress (s )
940+ if err != nil {
941+ errs = append (errs , fmt .Errorf ("unable to parse absent address `%s`: %w" , s , err ))
942+ } else {
943+ filter .AbsentParticipationAccounts [addr ] = struct {}{}
944+ }
945+ }
946+ }
947+ }
948+
949+ return filter , errors .Join (errs ... )
950+ }
951+
752952func (si * ServerImplementation ) maxAccountsErrorToAccountsErrorResponse (maxErr idb.MaxAPIResourcesPerAccountError ) generated.ErrorResponse {
753953 addr := maxErr .Address .String ()
754954 max := uint64 (si .opts .MaxAPIResourcesPerAccount )
0 commit comments