Skip to content

Commit

Permalink
ResourcePopulator
Browse files Browse the repository at this point in the history
  • Loading branch information
joe-p committed Jun 5, 2024
1 parent 5ac3edc commit 5ba0a9a
Show file tree
Hide file tree
Showing 2 changed files with 266 additions and 0 deletions.
227 changes: 227 additions & 0 deletions ledger/simulation/resources.go
Original file line number Diff line number Diff line change
Expand Up @@ -605,3 +605,230 @@ func (p *resourcePolicy) AvailableBox(app basics.AppIndex, name string, operatio
}
return p.tracker.addBox(app, name, readSize, *p.initialBoxSurplusReadBudget, p.ep.Proto.BytesPerBoxReference)
}

type TxnResources struct {

Check failure on line 609 in ledger/simulation/resources.go

View workflow job for this annotation

GitHub Actions / reviewdog-errors

[Lint Errors] reported by reviewdog 🐶 exported: exported type TxnResources should have comment or be unexported (revive) Raw Output: ledger/simulation/resources.go:609:6: exported: exported type TxnResources should have comment or be unexported (revive) type TxnResources struct { ^
// The static fields are resource arrays that were given in the transaciton group and thus cannot be removed

Check failure on line 610 in ledger/simulation/resources.go

View workflow job for this annotation

GitHub Actions / reviewdog-errors

[Lint Errors] reported by reviewdog 🐶 `transaciton` is a misspelling of `transactions` (misspell) Raw Output: ledger/simulation/resources.go:610:66: `transaciton` is a misspelling of `transactions` (misspell) // The static fields are resource arrays that were given in the transaciton group and thus cannot be removed ^
// The assumption is that these are prefilled because of one of the following reaons:
// - This transaction has already been signed
// - One of the foreign arrays is accessed on-chain
StaticAssets map[basics.AssetIndex]struct{}
StaticApps map[basics.AppIndex]struct{}
StaticAccounts map[basics.Address]struct{}
StaticBoxes map[logic.BoxRef]struct{}

// The following fields are fields that are implicitly available to the transaction group from transaction fields
AssetFromField basics.AssetIndex
AppFromField basics.AppIndex
AccountsFromFields map[basics.Address]struct{}

// These are the fields currently being populated, thus we can mutate them however we'd like
Assets map[basics.AssetIndex]struct{}
Apps map[basics.AppIndex]struct{}
Boxes map[logic.BoxRef]struct{}
Accounts map[basics.Address]struct{}

MaxTotalRefs int
MaxAccounts int
}

func (r *TxnResources) getTotalRefs() int {

Check failure on line 634 in ledger/simulation/resources.go

View workflow job for this annotation

GitHub Actions / reviewdog-warnings

[Lint Warnings] reported by reviewdog 🐶 func `(*TxnResources).getTotalRefs` is unused (unused) Raw Output: ledger/simulation/resources.go:634:24: func `(*TxnResources).getTotalRefs` is unused (unused) func (r *TxnResources) getTotalRefs() int { ^
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)
}

// Methods for determining room for specific references

func (r *TxnResources) hasRoom() bool {

Check failure on line 640 in ledger/simulation/resources.go

View workflow job for this annotation

GitHub Actions / reviewdog-warnings

[Lint Warnings] reported by reviewdog 🐶 func `(*TxnResources).hasRoom` is unused (unused) Raw Output: ledger/simulation/resources.go:640:24: func `(*TxnResources).hasRoom` is unused (unused) func (r *TxnResources) hasRoom() bool { ^
return r.getTotalRefs() < r.MaxTotalRefs
}

func (r *TxnResources) hasRoomForAccount() bool {

Check failure on line 644 in ledger/simulation/resources.go

View workflow job for this annotation

GitHub Actions / reviewdog-warnings

[Lint Warnings] reported by reviewdog 🐶 func `(*TxnResources).hasRoomForAccount` is unused (unused) Raw Output: ledger/simulation/resources.go:644:24: func `(*TxnResources).hasRoomForAccount` is unused (unused) func (r *TxnResources) hasRoomForAccount() bool { ^
return r.hasRoom() && (len(r.Accounts)+len(r.StaticAccounts)) < r.MaxAccounts
}

func (r *TxnResources) hasRoomForCrossRef() bool {

Check failure on line 648 in ledger/simulation/resources.go

View workflow job for this annotation

GitHub Actions / reviewdog-warnings

[Lint Warnings] reported by reviewdog 🐶 func `(*TxnResources).hasRoomForCrossRef` is unused (unused) Raw Output: ledger/simulation/resources.go:648:24: func `(*TxnResources).hasRoomForCrossRef` is unused (unused) func (r *TxnResources) hasRoomForCrossRef() bool { ^
return r.hasRoomForAccount() && r.getTotalRefs() < r.MaxTotalRefs-1
}

func (r *TxnResources) hasRoomForBoxWithApp() bool {

Check failure on line 652 in ledger/simulation/resources.go

View workflow job for this annotation

GitHub Actions / reviewdog-warnings

[Lint Warnings] reported by reviewdog 🐶 func `(*TxnResources).hasRoomForBoxWithApp` is unused (unused) Raw Output: ledger/simulation/resources.go:652:24: func `(*TxnResources).hasRoomForBoxWithApp` is unused (unused) func (r *TxnResources) hasRoomForBoxWithApp() bool { ^
return r.getTotalRefs() < r.MaxTotalRefs-1
}

// Methods for determining if a resource is available

func (r *TxnResources) hasApp(app basics.AppIndex) bool {

Check failure on line 658 in ledger/simulation/resources.go

View workflow job for this annotation

GitHub Actions / reviewdog-warnings

[Lint Warnings] reported by reviewdog 🐶 func `(*TxnResources).hasApp` is unused (unused) Raw Output: ledger/simulation/resources.go:658:24: func `(*TxnResources).hasApp` is unused (unused) func (r *TxnResources) hasApp(app basics.AppIndex) bool { ^
_, hasStatic := r.StaticApps[app]
_, hasRef := r.Apps[app]
return r.AppFromField == app || hasStatic || hasRef
}

func (r *TxnResources) hasAsset(aid basics.AssetIndex) bool {

Check failure on line 664 in ledger/simulation/resources.go

View workflow job for this annotation

GitHub Actions / reviewdog-warnings

[Lint Warnings] reported by reviewdog 🐶 func `(*TxnResources).hasAsset` is unused (unused) Raw Output: ledger/simulation/resources.go:664:24: func `(*TxnResources).hasAsset` is unused (unused) func (r *TxnResources) hasAsset(aid basics.AssetIndex) bool { ^
_, hasStatic := r.StaticAssets[aid]
_, hasRef := r.Assets[aid]
return r.AssetFromField == aid || hasStatic || hasRef
}

func (r *TxnResources) hasAccount(addr basics.Address) bool {

Check failure on line 670 in ledger/simulation/resources.go

View workflow job for this annotation

GitHub Actions / reviewdog-warnings

[Lint Warnings] reported by reviewdog 🐶 func `(*TxnResources).hasAccount` is unused (unused) Raw Output: ledger/simulation/resources.go:670:24: func `(*TxnResources).hasAccount` is unused (unused) func (r *TxnResources) hasAccount(addr basics.Address) bool { ^
_, hasStatic := r.StaticAccounts[addr]
_, hasRef := r.Accounts[addr]
_, hasField := r.AccountsFromFields[addr]

return hasField || hasStatic || hasRef
}

func (r *TxnResources) addAccount(addr basics.Address) {
r.Accounts[addr] = struct{}{}
}

func (r *TxnResources) addAsset(aid basics.AssetIndex) {
r.Assets[aid] = struct{}{}
}

func (r *TxnResources) addApp(aid basics.AppIndex) {
r.Apps[aid] = struct{}{}
}

func (r *TxnResources) addBox(app basics.AppIndex, name string) {

Check failure on line 690 in ledger/simulation/resources.go

View workflow job for this annotation

GitHub Actions / reviewdog-warnings

[Lint Warnings] reported by reviewdog 🐶 func `(*TxnResources).addBox` is unused (unused) Raw Output: ledger/simulation/resources.go:690:24: func `(*TxnResources).addBox` is unused (unused) func (r *TxnResources) addBox(app basics.AppIndex, name string) { ^
r.Boxes[logic.BoxRef{App: app, Name: name}] = struct{}{}
}

type PopulatedArrays struct {

Check failure on line 694 in ledger/simulation/resources.go

View workflow job for this annotation

GitHub Actions / reviewdog-errors

[Lint Errors] reported by reviewdog 🐶 exported: exported type PopulatedArrays should have comment or be unexported (revive) Raw Output: ledger/simulation/resources.go:694:6: exported: exported type PopulatedArrays should have comment or be unexported (revive) type PopulatedArrays struct { ^
Accounts []basics.Address
Assets []basics.AssetIndex
Apps []basics.AppIndex
Boxes []logic.BoxRef
}

func (r *TxnResources) getPopulatedArrays() PopulatedArrays {
accounts := make([]basics.Address, 0, len(r.Accounts)+len(r.StaticAccounts))
for account := range r.Accounts {
accounts = append(accounts, account)
}

assets := make([]basics.AssetIndex, 0, len(r.Assets)+len(r.StaticAssets))
for asset := range r.Assets {
assets = append(assets, asset)
}

apps := make([]basics.AppIndex, 0, len(r.Apps)+len(r.StaticApps))
for app := range r.Apps {
apps = append(apps, app)
}

boxes := make([]logic.BoxRef, 0, len(r.Boxes)+len(r.StaticBoxes))
for box := range r.Boxes {
boxes = append(boxes, box)
}

return PopulatedArrays{
Accounts: accounts,
Assets: assets,
Apps: apps,
Boxes: boxes,
}
}

type ResourcePopulator struct {

Check failure on line 730 in ledger/simulation/resources.go

View workflow job for this annotation

GitHub Actions / reviewdog-errors

[Lint Errors] reported by reviewdog 🐶 exported: exported type ResourcePopulator should have comment or be unexported (revive) Raw Output: ledger/simulation/resources.go:730:6: exported: exported type ResourcePopulator should have comment or be unexported (revive) type ResourcePopulator struct { ^
TxnResources []TxnResources
}

func (p *ResourcePopulator) addTransaction(txn transactions.Transaction, groupIndex int) {
p.TxnResources[groupIndex] = TxnResources{
StaticAssets: make(map[basics.AssetIndex]struct{}),
StaticApps: make(map[basics.AppIndex]struct{}),
StaticAccounts: make(map[basics.Address]struct{}),
StaticBoxes: make(map[logic.BoxRef]struct{}),
AccountsFromFields: make(map[basics.Address]struct{}),
Assets: make(map[basics.AssetIndex]struct{}),
Apps: make(map[basics.AppIndex]struct{}),
Accounts: make(map[basics.Address]struct{}),
Boxes: make(map[logic.BoxRef]struct{}),
// TODO: Get these values from the consensus params
MaxTotalRefs: 8,
MaxAccounts: 4,
}

// The Sender and RekeyTo will always be implicitly available for every transaction type
p.TxnResources[groupIndex].AccountsFromFields[txn.Sender] = struct{}{}
p.TxnResources[groupIndex].StaticAccounts[txn.RekeyTo] = struct{}{}

if txn.Type == protocol.ApplicationCallTx {
for _, asset := range txn.ForeignAssets {
p.TxnResources[groupIndex].StaticAssets[asset] = struct{}{}
}

for _, app := range txn.ForeignApps {
p.TxnResources[groupIndex].StaticApps[app] = struct{}{}
}

for _, account := range txn.Accounts {
p.TxnResources[groupIndex].StaticAccounts[account] = struct{}{}
}

for _, box := range txn.Boxes {
ref := logic.BoxRef{App: txn.ForeignApps[box.Index], Name: string(box.Name)}
p.TxnResources[groupIndex].StaticBoxes[ref] = struct{}{}
}

p.TxnResources[groupIndex].AppFromField = txn.ApplicationID

return
}

if txn.Type == protocol.AssetTransferTx {
p.TxnResources[groupIndex].AssetFromField = txn.XferAsset

p.TxnResources[groupIndex].AccountsFromFields[txn.AssetReceiver] = struct{}{}
p.TxnResources[groupIndex].AccountsFromFields[txn.AssetCloseTo] = struct{}{}
p.TxnResources[groupIndex].AccountsFromFields[txn.AssetSender] = struct{}{}

return
}

if txn.Type == protocol.PaymentTx {
p.TxnResources[groupIndex].AccountsFromFields[txn.Receiver] = struct{}{}
p.TxnResources[groupIndex].AccountsFromFields[txn.CloseRemainderTo] = struct{}{}

return
}

if txn.Type == protocol.AssetConfigTx {
p.TxnResources[groupIndex].AssetFromField = txn.ConfigAsset

return
}

if txn.Type == protocol.AssetFreezeTx {
p.TxnResources[groupIndex].AssetFromField = txn.FreezeAsset
p.TxnResources[groupIndex].AccountsFromFields[txn.FreezeAccount] = struct{}{}

return
}
}

func (p *ResourcePopulator) populateResources(groupResourceTracker groupResourceTracker) {
for i, tracker := range groupResourceTracker.localTxnResources {
for asset := range tracker.Assets {
p.TxnResources[i].addAsset(asset)
}

for app := range tracker.Apps {
p.TxnResources[i].addApp(app)
}

for account := range tracker.Accounts {
p.TxnResources[i].addAccount(account)
}
}
}

func MakeResourcePopulator(txnGroup []transactions.SignedTxnWithAD) ResourcePopulator {

Check failure on line 824 in ledger/simulation/resources.go

View workflow job for this annotation

GitHub Actions / reviewdog-errors

[Lint Errors] reported by reviewdog 🐶 exported: exported function MakeResourcePopulator should have comment or be unexported (revive) Raw Output: ledger/simulation/resources.go:824:1: exported: exported function MakeResourcePopulator should have comment or be unexported (revive) func MakeResourcePopulator(txnGroup []transactions.SignedTxnWithAD) ResourcePopulator { ^
populator := ResourcePopulator{
TxnResources: make([]TxnResources, len(txnGroup)),
}

for i, txn := range txnGroup {
populator.addTransaction(txn.Txn, i)
}

return populator
}
39 changes: 39 additions & 0 deletions ledger/simulation/resources_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -296,3 +296,42 @@ func TestGlobalVsLocalResources(t *testing.T) {
}, groupAssignment.localTxnResources[2].Apps)
})
}

func TestPopulatorWithLocalResources(t *testing.T) {
partitiontest.PartitionTest(t)
t.Parallel()

txns := make([]transactions.SignedTxnWithAD, 1)
txns[0].Txn.Type = protocol.ApplicationCallTx

populator := MakeResourcePopulator(txns)

proto := config.Consensus[protocol.ConsensusFuture]
groupTracker := makeGroupResourceTracker(txns, &proto)

// Note we don't need to test a box here since it will never be a local txn resource
addr := basics.Address{1, 1, 1}
app := basics.AppIndex(12345)
asset := basics.AssetIndex(12345)

groupTracker.localTxnResources[0].Accounts = make(map[basics.Address]struct{})
groupTracker.localTxnResources[0].Assets = make(map[basics.AssetIndex]struct{})
groupTracker.localTxnResources[0].Apps = make(map[basics.AppIndex]struct{})

groupTracker.localTxnResources[0].Accounts[addr] = struct{}{}
groupTracker.localTxnResources[0].Assets[asset] = struct{}{}
groupTracker.localTxnResources[0].Apps[app] = struct{}{}

populator.populateResources(groupTracker)

require.Equal(
t,
PopulatedArrays{
Assets: []basics.AssetIndex{asset},
Apps: []basics.AppIndex{app},
Accounts: []basics.Address{addr},
Boxes: []logic.BoxRef{},
},
populator.TxnResources[0].getPopulatedArrays(),
)
}

0 comments on commit 5ba0a9a

Please sign in to comment.