Skip to content

Commit

Permalink
Merge pull request onflow#6328 from onflow/supun/improve-reporting
Browse files Browse the repository at this point in the history
Report the stored path of the untyped-capability
  • Loading branch information
SupunS authored Aug 13, 2024
2 parents 3a2217d + 30bc437 commit 67d5beb
Show file tree
Hide file tree
Showing 8 changed files with 114 additions and 50 deletions.
52 changes: 28 additions & 24 deletions cmd/util/ledger/migrations/cadence_values_migration.go
Original file line number Diff line number Diff line change
Expand Up @@ -535,24 +535,24 @@ func (t *cadenceValueMigrationReporter) MissingCapabilityID(
}

func (t *cadenceValueMigrationReporter) MissingBorrowType(
accountAddress common.Address,
addressPath interpreter.AddressPath,
targetPath interpreter.AddressPath,
storedPath interpreter.AddressPath,
) {
t.reportWriter.Write(storageCapConsMissingBorrowTypeEntry{
AccountAddress: accountAddress,
AddressPath: addressPath,
TargetPath: targetPath,
StoredPath: storedPath,
})
}

func (t *cadenceValueMigrationReporter) InferredMissingBorrowType(
accountAddress common.Address,
addressPath interpreter.AddressPath,
targetPath interpreter.AddressPath,
borrowType *interpreter.ReferenceStaticType,
storedPath interpreter.AddressPath,
) {
t.reportWriter.Write(storageCapConsInferredBorrowTypeEntry{
AccountAddress: accountAddress,
AddressPath: addressPath,
BorrowType: borrowType,
TargetPath: targetPath,
BorrowType: borrowType,
StoredPath: storedPath,
})
}

Expand Down Expand Up @@ -880,14 +880,14 @@ func (e storageCapConIssuedEntry) MarshalJSON() ([]byte, error) {
// StorageCapConMissingBorrowType

type storageCapConsMissingBorrowTypeEntry struct {
AccountAddress common.Address
AddressPath interpreter.AddressPath
TargetPath interpreter.AddressPath
StoredPath interpreter.AddressPath
}

var _ valueMigrationReportEntry = storageCapConsMissingBorrowTypeEntry{}

func (e storageCapConsMissingBorrowTypeEntry) accountAddress() common.Address {
return e.AccountAddress
return e.StoredPath.Address
}

var _ json.Marshaler = storageCapConsMissingBorrowTypeEntry{}
Expand All @@ -897,42 +897,46 @@ func (e storageCapConsMissingBorrowTypeEntry) MarshalJSON() ([]byte, error) {
Kind string `json:"kind"`
AccountAddress string `json:"account_address"`
Address string `json:"address"`
Path string `json:"path"`
TargetPath string `json:"target_path"`
StoredPath string `json:"stored_path"`
}{
Kind: "storage-capcon-missing-borrow-type",
AccountAddress: e.AccountAddress.HexWithPrefix(),
Address: e.AddressPath.Address.HexWithPrefix(),
Path: e.AddressPath.Path.String(),
AccountAddress: e.StoredPath.Address.HexWithPrefix(),
Address: e.TargetPath.Address.HexWithPrefix(),
TargetPath: e.TargetPath.Path.String(),
StoredPath: e.StoredPath.Path.String(),
})
}

// StorageCapConMissingBorrowType

type storageCapConsInferredBorrowTypeEntry struct {
AccountAddress common.Address
AddressPath interpreter.AddressPath
BorrowType *interpreter.ReferenceStaticType
TargetPath interpreter.AddressPath
BorrowType *interpreter.ReferenceStaticType
StoredPath interpreter.AddressPath
}

var _ valueMigrationReportEntry = storageCapConsInferredBorrowTypeEntry{}
var _ json.Marshaler = storageCapConsInferredBorrowTypeEntry{}

func (e storageCapConsInferredBorrowTypeEntry) accountAddress() common.Address {
return e.AccountAddress
return e.StoredPath.Address
}

func (e storageCapConsInferredBorrowTypeEntry) MarshalJSON() ([]byte, error) {
return json.Marshal(struct {
Kind string `json:"kind"`
AccountAddress string `json:"account_address"`
Address string `json:"address"`
Path string `json:"path"`
TargetPath string `json:"target_path"`
BorrowType string `json:"borrow_type"`
StoredPath string `json:"stored_path"`
}{
Kind: "storage-capcon-inferred-borrow-type",
AccountAddress: e.AccountAddress.HexWithPrefix(),
Address: e.AddressPath.Address.HexWithPrefix(),
Path: e.AddressPath.Path.String(),
AccountAddress: e.StoredPath.Address.HexWithPrefix(),
Address: e.TargetPath.Address.HexWithPrefix(),
TargetPath: e.TargetPath.Path.String(),
BorrowType: string(e.BorrowType.ID()),
StoredPath: e.StoredPath.Path.String(),
})
}
76 changes: 68 additions & 8 deletions cmd/util/ledger/migrations/cadence_values_migration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2447,17 +2447,30 @@ func TestStoragePathCapabilityMigration(t *testing.T) {

issueStorageCapConReporter := rwf.reportWriters[issueStorageCapConMigrationReporterName]
require.NotNil(t, issueStorageCapConReporter)
require.Len(t, issueStorageCapConReporter.entries, 5)
require.Len(t, issueStorageCapConReporter.entries, 6)
require.Equal(
t,
[]any{
storageCapConsMissingBorrowTypeEntry{
TargetPath: interpreter.AddressPath{
Address: addressB,
Path: interpreter.NewUnmeteredPathValue(common.PathDomainStorage, "c"),
},
StoredPath: interpreter.AddressPath{
Address: addressB,
Path: interpreter.NewUnmeteredPathValue(common.PathDomainStorage, "cCap"),
},
},
storageCapConsInferredBorrowTypeEntry{
AccountAddress: addressB,
AddressPath: interpreter.AddressPath{
TargetPath: interpreter.AddressPath{
Address: addressB,
Path: interpreter.NewUnmeteredPathValue(common.PathDomainStorage, "c"),
},
BorrowType: inferredBorrowType,
StoredPath: interpreter.AddressPath{
Address: addressB,
Path: interpreter.NewUnmeteredPathValue(common.PathDomainStorage, "cCap"),
},
},
storageCapConIssuedEntry{
AccountAddress: addressB,
Expand Down Expand Up @@ -2487,11 +2500,14 @@ func TestStoragePathCapabilityMigration(t *testing.T) {
CapabilityID: 5,
},
storageCapConsMissingBorrowTypeEntry{
AccountAddress: addressB,
AddressPath: interpreter.AddressPath{
TargetPath: interpreter.AddressPath{
Address: addressB,
Path: interpreter.NewUnmeteredPathValue(common.PathDomainStorage, "b"),
},
StoredPath: interpreter.AddressPath{
Address: addressB,
Path: interpreter.NewUnmeteredPathValue(common.PathDomainStorage, "bCap"),
},
},
},
issueStorageCapConReporter.entries,
Expand Down Expand Up @@ -2607,14 +2623,17 @@ func TestStorageCapConsMissingBorrowTypeEntry_MarshalJSON(t *testing.T) {
t.Parallel()

e := storageCapConsMissingBorrowTypeEntry{
AccountAddress: common.MustBytesToAddress([]byte{0x2}),
AddressPath: interpreter.AddressPath{
TargetPath: interpreter.AddressPath{
Address: common.MustBytesToAddress([]byte{0x1}),
Path: interpreter.PathValue{
Domain: common.PathDomainStorage,
Identifier: "test",
},
},
StoredPath: interpreter.AddressPath{
Address: common.MustBytesToAddress([]byte{0x2}),
Path: interpreter.NewUnmeteredPathValue(common.PathDomainStorage, "storedCap"),
},
}

actual, err := e.MarshalJSON()
Expand All @@ -2626,7 +2645,48 @@ func TestStorageCapConsMissingBorrowTypeEntry_MarshalJSON(t *testing.T) {
"kind": "storage-capcon-missing-borrow-type",
"account_address": "0x0000000000000002",
"address": "0x0000000000000001",
"path": "/storage/test"
"target_path": "/storage/test",
"stored_path": "/storage/storedCap"
}`,
string(actual),
)
}

func TestStorageCapConsInferredBorrowTypeEntry_MarshalJSON(t *testing.T) {

t.Parallel()

e := storageCapConsInferredBorrowTypeEntry{
TargetPath: interpreter.AddressPath{
Address: common.MustBytesToAddress([]byte{0x1}),
Path: interpreter.PathValue{
Domain: common.PathDomainStorage,
Identifier: "test",
},
},
StoredPath: interpreter.AddressPath{
Address: common.MustBytesToAddress([]byte{0x2}),
Path: interpreter.NewUnmeteredPathValue(common.PathDomainStorage, "storedCap"),
},
BorrowType: interpreter.NewReferenceStaticType(
nil,
interpreter.UnauthorizedAccess,
interpreter.PrimitiveStaticTypeInt,
),
}

actual, err := e.MarshalJSON()
require.NoError(t, err)

require.JSONEq(t,
//language=JSON
`{
"kind": "storage-capcon-inferred-borrow-type",
"account_address": "0x0000000000000002",
"address": "0x0000000000000001",
"borrow_type":"&Int",
"target_path": "/storage/test",
"stored_path": "/storage/storedCap"
}`,
string(actual),
)
Expand Down
4 changes: 2 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -48,12 +48,12 @@ require (
github.com/multiformats/go-multiaddr-dns v0.3.1
github.com/multiformats/go-multihash v0.2.3
github.com/onflow/atree v0.8.0-rc.5
github.com/onflow/cadence v1.0.0-preview.47
github.com/onflow/cadence v1.0.0-preview.48
github.com/onflow/crypto v0.25.1
github.com/onflow/flow v0.3.4
github.com/onflow/flow-core-contracts/lib/go/contracts v1.3.1
github.com/onflow/flow-core-contracts/lib/go/templates v1.3.1
github.com/onflow/flow-go-sdk v1.0.0-preview.49
github.com/onflow/flow-go-sdk v1.0.0-preview.50
github.com/onflow/flow/protobuf/go/flow v0.4.5
github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58
github.com/pierrec/lz4 v2.6.1+incompatible
Expand Down
8 changes: 4 additions & 4 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -2167,8 +2167,8 @@ github.com/onflow/atree v0.8.0-rc.5/go.mod h1:yccR+LR7xc1Jdic0mrjocbHvUD7lnVvg8/
github.com/onflow/boxo v0.0.0-20240201202436-f2477b92f483 h1:LpiQhTAfM9CAmNVEs0n//cBBgCg+vJSiIxTHYUklZ84=
github.com/onflow/boxo v0.0.0-20240201202436-f2477b92f483/go.mod h1:pIZgTWdm3k3pLF9Uq6MB8JEcW07UDwNJjlXW1HELW80=
github.com/onflow/cadence v1.0.0-M3/go.mod h1:odXGZZ/wGNA5mwT8bC9v8u8EXACHllB2ABSZK65TGL8=
github.com/onflow/cadence v1.0.0-preview.47 h1:RpYee9m2A3BmEIe8FmIO4XuL7j8lQD+8R4Qo5MQkIQ4=
github.com/onflow/cadence v1.0.0-preview.47/go.mod h1:BCoenp1TYp+SmG7FGWStjehvvzcvNQ3xvpK5rkthq3Y=
github.com/onflow/cadence v1.0.0-preview.48 h1:WkgU0z6H/oRe44kLL6OO+wkGeKULWChoCT8i7sgiWdg=
github.com/onflow/cadence v1.0.0-preview.48/go.mod h1:BCoenp1TYp+SmG7FGWStjehvvzcvNQ3xvpK5rkthq3Y=
github.com/onflow/crypto v0.25.0/go.mod h1:C8FbaX0x8y+FxWjbkHy0Q4EASCDR9bSPWZqlpCLYyVI=
github.com/onflow/crypto v0.25.1 h1:0txy2PKPMM873JbpxQNbJmuOJtD56bfs48RQfm0ts5A=
github.com/onflow/crypto v0.25.1/go.mod h1:C8FbaX0x8y+FxWjbkHy0Q4EASCDR9bSPWZqlpCLYyVI=
Expand All @@ -2183,8 +2183,8 @@ github.com/onflow/flow-ft/lib/go/contracts v1.0.0/go.mod h1:PwsL8fC81cjnUnTfmyL/
github.com/onflow/flow-ft/lib/go/templates v1.0.0 h1:6cMS/lUJJ17HjKBfMO/eh0GGvnpElPgBXx7h5aoWJhs=
github.com/onflow/flow-ft/lib/go/templates v1.0.0/go.mod h1:uQ8XFqmMK2jxyBSVrmyuwdWjTEb+6zGjRYotfDJ5pAE=
github.com/onflow/flow-go-sdk v1.0.0-M1/go.mod h1:TDW0MNuCs4SvqYRUzkbRnRmHQL1h4X8wURsCw9P9beo=
github.com/onflow/flow-go-sdk v1.0.0-preview.49 h1:nR+m3MJOsnpjjyzpODErUhM02hDCTrwh1CTphwiTqKo=
github.com/onflow/flow-go-sdk v1.0.0-preview.49/go.mod h1:cZlefeoP71Vr69rKX1BGQsyl3pL63OrKDsrbf2Kxw1E=
github.com/onflow/flow-go-sdk v1.0.0-preview.50 h1:j5HotrV/ieo5JckmMxR2dMxO3x1j7YO8SP2EuGMEwRQ=
github.com/onflow/flow-go-sdk v1.0.0-preview.50/go.mod h1:Ykk4PS7fgWuc6BB073tdzHu/VtzOd0CVNIoDjaqFHLg=
github.com/onflow/flow-nft/lib/go/contracts v1.2.1 h1:woAAS5z651sDpi7ihAHll8NvRS9uFXIXkL6xR+bKFZY=
github.com/onflow/flow-nft/lib/go/contracts v1.2.1/go.mod h1:2gpbza+uzs1k7x31hkpBPlggIRkI53Suo0n2AyA2HcE=
github.com/onflow/flow-nft/lib/go/templates v1.2.0 h1:JSQyh9rg0RC+D1930BiRXN8lrtMs+ubVMK6aQPon6Yc=
Expand Down
4 changes: 2 additions & 2 deletions insecure/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -202,12 +202,12 @@ require (
github.com/multiformats/go-varint v0.0.7 // indirect
github.com/olekukonko/tablewriter v0.0.5 // indirect
github.com/onflow/atree v0.8.0-rc.5 // indirect
github.com/onflow/cadence v1.0.0-preview.47 // indirect
github.com/onflow/cadence v1.0.0-preview.48 // indirect
github.com/onflow/flow-core-contracts/lib/go/contracts v1.3.1 // indirect
github.com/onflow/flow-core-contracts/lib/go/templates v1.3.1 // indirect
github.com/onflow/flow-ft/lib/go/contracts v1.0.0 // indirect
github.com/onflow/flow-ft/lib/go/templates v1.0.0 // indirect
github.com/onflow/flow-go-sdk v1.0.0-preview.49 // indirect
github.com/onflow/flow-go-sdk v1.0.0-preview.50 // indirect
github.com/onflow/flow-nft/lib/go/contracts v1.2.1 // indirect
github.com/onflow/flow-nft/lib/go/templates v1.2.0 // indirect
github.com/onflow/flow/protobuf/go/flow v0.4.5 // indirect
Expand Down
8 changes: 4 additions & 4 deletions insecure/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -2157,8 +2157,8 @@ github.com/onflow/atree v0.6.1-0.20230711151834-86040b30171f/go.mod h1:xvP61FoOs
github.com/onflow/atree v0.8.0-rc.5 h1:1sU+c6UfDzq/EjM8nTw4EI8GvEMarcxkWkJKy6piFSY=
github.com/onflow/atree v0.8.0-rc.5/go.mod h1:yccR+LR7xc1Jdic0mrjocbHvUD7lnVvg8/Ct1AA5zBo=
github.com/onflow/cadence v1.0.0-M3/go.mod h1:odXGZZ/wGNA5mwT8bC9v8u8EXACHllB2ABSZK65TGL8=
github.com/onflow/cadence v1.0.0-preview.47 h1:RpYee9m2A3BmEIe8FmIO4XuL7j8lQD+8R4Qo5MQkIQ4=
github.com/onflow/cadence v1.0.0-preview.47/go.mod h1:BCoenp1TYp+SmG7FGWStjehvvzcvNQ3xvpK5rkthq3Y=
github.com/onflow/cadence v1.0.0-preview.48 h1:WkgU0z6H/oRe44kLL6OO+wkGeKULWChoCT8i7sgiWdg=
github.com/onflow/cadence v1.0.0-preview.48/go.mod h1:BCoenp1TYp+SmG7FGWStjehvvzcvNQ3xvpK5rkthq3Y=
github.com/onflow/crypto v0.25.0/go.mod h1:C8FbaX0x8y+FxWjbkHy0Q4EASCDR9bSPWZqlpCLYyVI=
github.com/onflow/crypto v0.25.1 h1:0txy2PKPMM873JbpxQNbJmuOJtD56bfs48RQfm0ts5A=
github.com/onflow/crypto v0.25.1/go.mod h1:C8FbaX0x8y+FxWjbkHy0Q4EASCDR9bSPWZqlpCLYyVI=
Expand All @@ -2171,8 +2171,8 @@ github.com/onflow/flow-ft/lib/go/contracts v1.0.0/go.mod h1:PwsL8fC81cjnUnTfmyL/
github.com/onflow/flow-ft/lib/go/templates v1.0.0 h1:6cMS/lUJJ17HjKBfMO/eh0GGvnpElPgBXx7h5aoWJhs=
github.com/onflow/flow-ft/lib/go/templates v1.0.0/go.mod h1:uQ8XFqmMK2jxyBSVrmyuwdWjTEb+6zGjRYotfDJ5pAE=
github.com/onflow/flow-go-sdk v1.0.0-M1/go.mod h1:TDW0MNuCs4SvqYRUzkbRnRmHQL1h4X8wURsCw9P9beo=
github.com/onflow/flow-go-sdk v1.0.0-preview.49 h1:nR+m3MJOsnpjjyzpODErUhM02hDCTrwh1CTphwiTqKo=
github.com/onflow/flow-go-sdk v1.0.0-preview.49/go.mod h1:cZlefeoP71Vr69rKX1BGQsyl3pL63OrKDsrbf2Kxw1E=
github.com/onflow/flow-go-sdk v1.0.0-preview.50 h1:j5HotrV/ieo5JckmMxR2dMxO3x1j7YO8SP2EuGMEwRQ=
github.com/onflow/flow-go-sdk v1.0.0-preview.50/go.mod h1:Ykk4PS7fgWuc6BB073tdzHu/VtzOd0CVNIoDjaqFHLg=
github.com/onflow/flow-nft/lib/go/contracts v1.2.1 h1:woAAS5z651sDpi7ihAHll8NvRS9uFXIXkL6xR+bKFZY=
github.com/onflow/flow-nft/lib/go/contracts v1.2.1/go.mod h1:2gpbza+uzs1k7x31hkpBPlggIRkI53Suo0n2AyA2HcE=
github.com/onflow/flow-nft/lib/go/templates v1.2.0 h1:JSQyh9rg0RC+D1930BiRXN8lrtMs+ubVMK6aQPon6Yc=
Expand Down
4 changes: 2 additions & 2 deletions integration/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,13 @@ require (
github.com/ipfs/go-ds-badger2 v0.1.3
github.com/ipfs/go-ds-pebble v0.3.1
github.com/libp2p/go-libp2p v0.32.2
github.com/onflow/cadence v1.0.0-preview.47
github.com/onflow/cadence v1.0.0-preview.48
github.com/onflow/crypto v0.25.1
github.com/onflow/flow-core-contracts/lib/go/contracts v1.3.1
github.com/onflow/flow-core-contracts/lib/go/templates v1.3.1
github.com/onflow/flow-emulator v1.0.0-preview.36.0.20240729195722-d4eb1c30eb9f
github.com/onflow/flow-go v0.36.8-0.20240729193633-433a32eeb0cd
github.com/onflow/flow-go-sdk v1.0.0-preview.49
github.com/onflow/flow-go-sdk v1.0.0-preview.50
github.com/onflow/flow-go/insecure v0.0.0-00010101000000-000000000000
github.com/onflow/flow/protobuf/go/flow v0.4.5
github.com/onflow/go-ethereum v1.14.7
Expand Down
8 changes: 4 additions & 4 deletions integration/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -2141,8 +2141,8 @@ github.com/onflow/atree v0.6.1-0.20230711151834-86040b30171f/go.mod h1:xvP61FoOs
github.com/onflow/atree v0.8.0-rc.5 h1:1sU+c6UfDzq/EjM8nTw4EI8GvEMarcxkWkJKy6piFSY=
github.com/onflow/atree v0.8.0-rc.5/go.mod h1:yccR+LR7xc1Jdic0mrjocbHvUD7lnVvg8/Ct1AA5zBo=
github.com/onflow/cadence v1.0.0-M3/go.mod h1:odXGZZ/wGNA5mwT8bC9v8u8EXACHllB2ABSZK65TGL8=
github.com/onflow/cadence v1.0.0-preview.47 h1:RpYee9m2A3BmEIe8FmIO4XuL7j8lQD+8R4Qo5MQkIQ4=
github.com/onflow/cadence v1.0.0-preview.47/go.mod h1:BCoenp1TYp+SmG7FGWStjehvvzcvNQ3xvpK5rkthq3Y=
github.com/onflow/cadence v1.0.0-preview.48 h1:WkgU0z6H/oRe44kLL6OO+wkGeKULWChoCT8i7sgiWdg=
github.com/onflow/cadence v1.0.0-preview.48/go.mod h1:BCoenp1TYp+SmG7FGWStjehvvzcvNQ3xvpK5rkthq3Y=
github.com/onflow/crypto v0.25.0/go.mod h1:C8FbaX0x8y+FxWjbkHy0Q4EASCDR9bSPWZqlpCLYyVI=
github.com/onflow/crypto v0.25.1 h1:0txy2PKPMM873JbpxQNbJmuOJtD56bfs48RQfm0ts5A=
github.com/onflow/crypto v0.25.1/go.mod h1:C8FbaX0x8y+FxWjbkHy0Q4EASCDR9bSPWZqlpCLYyVI=
Expand All @@ -2157,8 +2157,8 @@ github.com/onflow/flow-ft/lib/go/contracts v1.0.0/go.mod h1:PwsL8fC81cjnUnTfmyL/
github.com/onflow/flow-ft/lib/go/templates v1.0.0 h1:6cMS/lUJJ17HjKBfMO/eh0GGvnpElPgBXx7h5aoWJhs=
github.com/onflow/flow-ft/lib/go/templates v1.0.0/go.mod h1:uQ8XFqmMK2jxyBSVrmyuwdWjTEb+6zGjRYotfDJ5pAE=
github.com/onflow/flow-go-sdk v1.0.0-M1/go.mod h1:TDW0MNuCs4SvqYRUzkbRnRmHQL1h4X8wURsCw9P9beo=
github.com/onflow/flow-go-sdk v1.0.0-preview.49 h1:nR+m3MJOsnpjjyzpODErUhM02hDCTrwh1CTphwiTqKo=
github.com/onflow/flow-go-sdk v1.0.0-preview.49/go.mod h1:cZlefeoP71Vr69rKX1BGQsyl3pL63OrKDsrbf2Kxw1E=
github.com/onflow/flow-go-sdk v1.0.0-preview.50 h1:j5HotrV/ieo5JckmMxR2dMxO3x1j7YO8SP2EuGMEwRQ=
github.com/onflow/flow-go-sdk v1.0.0-preview.50/go.mod h1:Ykk4PS7fgWuc6BB073tdzHu/VtzOd0CVNIoDjaqFHLg=
github.com/onflow/flow-nft/lib/go/contracts v1.2.1 h1:woAAS5z651sDpi7ihAHll8NvRS9uFXIXkL6xR+bKFZY=
github.com/onflow/flow-nft/lib/go/contracts v1.2.1/go.mod h1:2gpbza+uzs1k7x31hkpBPlggIRkI53Suo0n2AyA2HcE=
github.com/onflow/flow-nft/lib/go/templates v1.2.0 h1:JSQyh9rg0RC+D1930BiRXN8lrtMs+ubVMK6aQPon6Yc=
Expand Down

0 comments on commit 67d5beb

Please sign in to comment.