@@ -13,6 +13,7 @@ import { cidFromBytes, buildUnixFSDagPB } from "./cid_dag_metadata.js";
1313export const WS_ENDPOINT = 'ws://127.0.0.1:10000' ; // Bulletin node
1414export const IPFS_API = 'http://127.0.0.1:5001' ; // Local IPFS daemon
1515export const HTTP_IPFS_API = 'http://127.0.0.1:8080' ; // Local IPFS HTTP gateway
16+ export const CHUNK_SIZE = 1 * 1024 * 1024 ; // 1 MB
1617// -----------------
1718
1819function to_hex ( input ) {
@@ -51,7 +52,7 @@ export async function storeChunkedFile(api, pair, filePath, nonceMgr) {
5152 const tx = api . tx . transactionStorage . store ( bytes ) ;
5253 const result = await tx . signAndSend ( pair , { nonce : nonceMgr . getAndIncrement ( ) } ) ;
5354 console . log ( `✅ Stored chunk #${ i + 1 } , result:` , result . toHuman ?. ( ) ) ;
54- } catch ( err ) {
55+ } catch ( err ) {
5556 if ( err . stack . includes ( "Immediately Dropped: The transaction couldn't enter the pool because of the limit" ) ) {
5657 await waitForNewBlock ( ) ;
5758 -- i ;
@@ -147,11 +148,11 @@ export async function storeMetadata(api, pair, chunks, nonceMgr) {
147148 * @returns {Promise<{ rootCid: CID, dagBytes: Uint8Array }> }
148149 */
149150export async function buildUnixFSDag ( metadataJson , mhCode = 0x12 ) {
150- // Extract chunk info
151- const chunks = metadataJson . chunks || [ ]
152- if ( ! chunks . length ) throw new Error ( '❌ metadataJson.chunks is empty' )
151+ // Extract chunk info
152+ const chunks = metadataJson . chunks || [ ]
153+ if ( ! chunks . length ) throw new Error ( '❌ metadataJson.chunks is empty' )
153154
154- return await buildUnixFSDagPB ( chunks , mhCode ) ;
155+ return await buildUnixFSDagPB ( chunks , mhCode ) ;
155156}
156157
157158/**
@@ -202,6 +203,30 @@ export async function storeProof(api, sudoPair, pair, rootCID, dagFileBytes, non
202203 return { rawDagCid }
203204}
204205
206+ export async function authorizeStorage ( api , sudoPair , pair , nonceMgr ) {
207+ // Ensure enough quota.
208+ const auth = await api . query . transactionStorage . authorizations ( { "Account" : pair . address } ) ;
209+ console . log ( 'Authorization info:' , auth . toHuman ( ) ) ;
210+
211+ if ( ! auth . isSome ) {
212+ console . log ( 'ℹ️ No existing authorization found — requesting new one...' ) ;
213+ } else {
214+ const authValue = auth . unwrap ( ) . extent ;
215+ const transactions = authValue . transactions . toNumber ( ) ;
216+ const bytes = authValue . bytes . toNumber ( ) ;
217+
218+ if ( transactions > 10 && bytes > 24 * CHUNK_SIZE ) {
219+ console . log ( '✅ Account authorization is sufficient.' ) ;
220+ return ;
221+ }
222+ }
223+
224+ const transactions = 128 ;
225+ const bytes = 64 * 1024 * 1024 ; // 64 MB
226+ await authorizeAccount ( api , sudoPair , pair . address , transactions , bytes , nonceMgr ) ;
227+ await waitForNewBlock ( ) ;
228+ }
229+
205230export async function waitForNewBlock ( ) {
206231 // TODO: wait for a new block.
207232 console . log ( '🛰 Waiting for new block...' )
@@ -212,86 +237,86 @@ export async function waitForNewBlock() {
212237 * Creates a PAPI-compatible signer from a Keyring account
213238 */
214239export function createSigner ( account ) {
215- return getPolkadotSigner (
216- account . publicKey ,
217- 'Sr25519' ,
218- ( input ) => account . sign ( input )
219- ) ;
240+ return getPolkadotSigner (
241+ account . publicKey ,
242+ 'Sr25519' ,
243+ ( input ) => account . sign ( input )
244+ ) ;
220245}
221246
222247export function setupKeyringAndSigners ( sudoSeed , accountSeed ) {
223- const keyring = new Keyring ( { type : 'sr25519' } ) ;
224- const sudoAccount = keyring . addFromUri ( sudoSeed ) ;
225- const whoAccount = keyring . addFromUri ( accountSeed ) ;
226-
227- const sudoSigner = createSigner ( sudoAccount ) ;
228- const whoSigner = createSigner ( whoAccount ) ;
229-
230- return {
231- sudoSigner,
232- whoSigner,
233- whoAddress : whoAccount . address
234- } ;
248+ const keyring = new Keyring ( { type : 'sr25519' } ) ;
249+ const sudoAccount = keyring . addFromUri ( sudoSeed ) ;
250+ const whoAccount = keyring . addFromUri ( accountSeed ) ;
251+
252+ const sudoSigner = createSigner ( sudoAccount ) ;
253+ const whoSigner = createSigner ( whoAccount ) ;
254+
255+ return {
256+ sudoSigner,
257+ whoSigner,
258+ whoAddress : whoAccount . address
259+ } ;
235260}
236261
237262/**
238263 * Generates (dynamic) images based on the input text.
239264 */
240265export function generateTextImage ( file , text , width = 800 , height = 600 ) {
241- const canvas = createCanvas ( width , height ) ;
242- const ctx = canvas . getContext ( "2d" ) ;
266+ const canvas = createCanvas ( width , height ) ;
267+ const ctx = canvas . getContext ( "2d" ) ;
243268
244- // 🎨 Background
269+ // 🎨 Background
270+ ctx . fillStyle = randomColor ( ) ;
271+ ctx . fillRect ( 0 , 0 , width , height ) ;
272+
273+ // 🟠 Random shapes
274+ for ( let i = 0 ; i < 15 ; i ++ ) {
275+ ctx . beginPath ( ) ;
245276 ctx . fillStyle = randomColor ( ) ;
246- ctx . fillRect ( 0 , 0 , width , height ) ;
247-
248- // 🟠 Random shapes
249- for ( let i = 0 ; i < 15 ; i ++ ) {
250- ctx . beginPath ( ) ;
251- ctx . fillStyle = randomColor ( ) ;
252- ctx . arc (
253- Math . random ( ) * width ,
254- Math . random ( ) * height ,
255- Math . random ( ) * 120 ,
256- 0 ,
257- Math . PI * 2
258- ) ;
259- ctx . fill ( ) ;
260- }
277+ ctx . arc (
278+ Math . random ( ) * width ,
279+ Math . random ( ) * height ,
280+ Math . random ( ) * 120 ,
281+ 0 ,
282+ Math . PI * 2
283+ ) ;
284+ ctx . fill ( ) ;
285+ }
261286
262- // ✍️ Draw your text
263- ctx . font = "bold 40px Sans" ;
264- ctx . fillStyle = "white" ;
265- ctx . textAlign = "center" ;
266- ctx . textBaseline = "middle" ;
287+ // ✍️ Draw your text
288+ ctx . font = "bold 40px Sans" ;
289+ ctx . fillStyle = "white" ;
290+ ctx . textAlign = "center" ;
291+ ctx . textBaseline = "middle" ;
267292
268- // Add text with shadow for readability
269- ctx . shadowColor = "black" ;
270- ctx . shadowBlur = 8 ;
293+ // Add text with shadow for readability
294+ ctx . shadowColor = "black" ;
295+ ctx . shadowBlur = 8 ;
271296
272- ctx . fillText ( text , width / 2 , height / 2 ) ;
297+ ctx . fillText ( text , width / 2 , height / 2 ) ;
273298
274- let jpegBytes = canvas . toBuffer ( "image/jpeg" ) ;
275- fs . writeFileSync ( file , jpegBytes ) ;
276- console . log ( "Saved to file:" , file ) ;
299+ let jpegBytes = canvas . toBuffer ( "image/jpeg" ) ;
300+ fs . writeFileSync ( file , jpegBytes ) ;
301+ console . log ( "Saved to file:" , file ) ;
277302}
278303
279304function randomColor ( ) {
280- return `rgb(${ rand255 ( ) } , ${ rand255 ( ) } , ${ rand255 ( ) } )` ;
305+ return `rgb(${ rand255 ( ) } , ${ rand255 ( ) } , ${ rand255 ( ) } )` ;
281306}
282307
283308function rand255 ( ) {
284- return Math . floor ( Math . random ( ) * 256 ) ;
309+ return Math . floor ( Math . random ( ) * 256 ) ;
285310}
286311
287312export function filesAreEqual ( path1 , path2 ) {
288- const data1 = fs . readFileSync ( path1 ) ;
289- const data2 = fs . readFileSync ( path2 ) ;
290- assert . deepStrictEqual ( data1 . length , data2 . length )
313+ const data1 = fs . readFileSync ( path1 ) ;
314+ const data2 = fs . readFileSync ( path2 ) ;
315+ assert . deepStrictEqual ( data1 . length , data2 . length )
291316
292- for ( let i = 0 ; i < data1 . length ; i ++ ) {
293- assert . deepStrictEqual ( data1 [ i ] , data2 [ i ] )
294- }
317+ for ( let i = 0 ; i < data1 . length ; i ++ ) {
318+ assert . deepStrictEqual ( data1 [ i ] , data2 [ i ] )
319+ }
295320}
296321
297322export async function fileToDisk ( outputPath , fullBuffer ) {
0 commit comments