@@ -3,12 +3,23 @@ access(all) contract TopShotIPFSResolver {
33 access (all ) event CIDSet (setID : UInt32 , playID : UInt32 , subeditionID : UInt32 , mediaType : String , cid : String )
44 access (all ) event GatewayUpdated (gateway : String )
55
6- // Number of buckets to split CID entries across
76 access (all ) let numBuckets : UInt64
87
9- // Sharded storage: bucket index -> composite key -> { mediaType: CID }
10- // Let's us store 32 * 100k = 32M CID entries
11- access (contract ) let shards : {UInt64 : {String : {String : String }}}
8+ // Each shard is a resource stored at its own path so writes
9+ // borrow a reference and mutate in place — no dict copy.
10+ access (all ) resource Shard {
11+ access (all ) let entries : {String : {String : String }}
12+
13+ init () {
14+ self .entries = {}
15+ }
16+
17+ access (contract ) fun setCID (key : String , mediaType : String , cid : String ) {
18+ var inner = self .entries [key ] ?? {}
19+ inner [mediaType ] = cid
20+ self .entries [key ] = inner
21+ }
22+ }
1223
1324 // IPFS gateway base URL (e.g., "https://ipfs.dapperlabs.com/ipfs/")
1425 access (all ) var gateway : String
@@ -19,25 +30,56 @@ access(all) contract TopShotIPFSResolver {
1930 access (all ) fun setCID (setID : UInt32 , playID : UInt32 , subeditionID : UInt32 , mediaType : String , cid : String ) {
2031 let key = TopShotIPFSResolver .buildKey (setID : setID , playID : playID , subeditionID : subeditionID )
2132 let bucket = TopShotIPFSResolver .getBucket (setID : setID , playID : playID , subeditionID : subeditionID )
22- var shard = TopShotIPFSResolver .shards [bucket ] ?? {}
23- var inner = shard [key ] ?? {}
24- inner [mediaType ] = cid
25- shard [key ] = inner
26- TopShotIPFSResolver .shards [bucket ] = shard
33+ let shard = TopShotIPFSResolver .borrowShard (bucket )
34+ shard .setCID (key : key , mediaType : mediaType , cid : cid )
2735 emit CIDSet (setID : setID , playID : playID , subeditionID : subeditionID , mediaType : mediaType , cid : cid )
2836 }
2937
3038 access (all ) fun setGateway (gateway : String ) {
3139 TopShotIPFSResolver .gateway = gateway
3240 emit GatewayUpdated (gateway : gateway )
3341 }
42+
43+ access (all ) fun clearAllCIDs () {
44+ var i : UInt64 = 0
45+ while i < TopShotIPFSResolver .numBuckets {
46+ let path = TopShotIPFSResolver .shardPath (i )
47+ if let existing <- TopShotIPFSResolver .account .storage .load <@Shard >(from : path ) {
48+ destroy existing
49+ }
50+ i = i + 1
51+ }
52+ }
3453 }
3554
3655 access (all ) view fun getCIDs (setID : UInt32 , playID : UInt32 , subeditionID : UInt32 ): {String : String }? {
3756 let key = self .buildKey (setID : setID , playID : playID , subeditionID : subeditionID )
3857 let bucket = self .getBucket (setID : setID , playID : playID , subeditionID : subeditionID )
39- let shard = self .shards [bucket ] ?? {}
40- return shard [key ]
58+ let path = self .shardPath (bucket )
59+ if let shard = self .account .storage .borrow <&Shard >(from : path ) {
60+ if let entry = shard .entries [key ] {
61+ // Return a copy, not a reference
62+ let result : {String : String } = {}
63+ for mediaType in entry .keys {
64+ result [mediaType ] = entry [mediaType ]
65+ }
66+ return result
67+ }
68+ }
69+ return nil
70+ }
71+
72+ access (contract ) fun borrowShard (_ bucket : UInt64 ): &Shard {
73+ let path = self .shardPath (bucket )
74+ if let shard = self .account .storage .borrow <&Shard >(from : path ) {
75+ return shard
76+ }
77+ self .account .storage .save (<- create Shard (), to : path )
78+ return self .account .storage .borrow <&Shard >(from : path )!
79+ }
80+
81+ access (all ) view fun shardPath (_ bucket : UInt64 ): StoragePath {
82+ return StoragePath (identifier : " TopShotIPFSShard_" .concat (bucket .toString ()))!
4183 }
4284
4385 access (all ) view fun getBucket (setID : UInt32 , playID : UInt32 , subeditionID : UInt32 ): UInt64 {
@@ -53,8 +95,7 @@ access(all) contract TopShotIPFSResolver {
5395 }
5496
5597 init () {
56- self .numBuckets = 32
57- self .shards = {}
98+ self .numBuckets = 31
5899 self .gateway = " https://ipfs.dapperlabs.com/ipfs/"
59100 self .AdminStoragePath = /storage/TopShotIPFSResolverAdmin
60101 self .account .storage .save <@Admin >(<- create Admin (), to : self .AdminStoragePath )
0 commit comments