-
Notifications
You must be signed in to change notification settings - Fork 45
docs: new Q&A questions and answers section #543
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
sentientforest
wants to merge
15
commits into
GalaChain:main
Choose a base branch
from
sentientforest:docs/new-questions
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 6 commits
Commits
Show all changes
15 commits
Select commit
Hold shift + click to select a range
d2d0a52
docs: new Q&A questions and answers section
sentientforest a75bc58
chore: add copyright header
sentientforest 8590203
chore: lint
sentientforest 43a569c
docs: additional Q&A content
sentientforest bcf531d
docs: Q&A questions on swaps, large files, errors
sentientforest c87de04
docs: Q&A content for token burns
sentientforest 4b0ce68
Merge branch 'main' into docs/new-questions
sentientforest 9bcfea3
Update docs/questions/burning-NFTs-vs-fungibles.md
sentientforest 14b4781
Update docs/questions/composite-keys-for-complex-queries.md
sentientforest a4f56b1
Update docs/questions/burn-errors-handling.md
sentientforest 42e1756
fix: documentation Q&A feedback, edits
sentientforest 1b03e3f
Merge branch 'docs/new-questions' of github.com:sentientforest/galach…
sentientforest 41d2ff2
fix: correct links, revise Q&A
sentientforest f5edbcc
fix: add caveat about range reads to Q&A
sentientforest 4c38c31
Merge branch 'main' into docs/new-questions
sentientforest File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,72 @@ | ||
| ### Question | ||
|
|
||
|
|
||
| How can I implement asynchronous operations in chaincode? | ||
|
|
||
|
|
||
| ### Answer | ||
|
|
||
|
|
||
| In GalaChain, chaincode operations are inherently asynchronous. Here's how to work with async operations effectively: | ||
|
|
||
| 1. Basic Async Pattern: | ||
| ```typescript | ||
| class GameContract extends Contract { | ||
| @Submit() | ||
| async processGameAction( | ||
| ctx: GalaChainContext, | ||
| params: { gameId: string } | ||
| ): Promise<void> { | ||
| // Async state operations | ||
| const game = await getObjectByKey(ctx, Game, params.gameId); | ||
| const player = await getObjectByKey(ctx, Player, ctx.callingUser.id); | ||
|
|
||
| // Process game logic | ||
| await this.updateGameState(ctx, game, player); | ||
| } | ||
|
|
||
| private async updateGameState( | ||
| ctx: GalaChainContext, | ||
| game: Game, | ||
| player: Player | ||
| ): Promise<void> { | ||
| // Multiple async operations | ||
| await this.updatePlayerStats(ctx, player); | ||
| await this.updateGameProgress(ctx, game); | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| 2. Best Practices: | ||
| - Prefer `async/await` syntax for simplicity and readability | ||
| - Handle errors with try/catch blocks | ||
| - Avoid using Promise.all for parallel operations! It can have non-deterministic ordering or outcomes when run across multiple peers that can fail in hard-to-troubleshoot ways | ||
| - Keep transaction duration reasonable | ||
| - Log async operation progress | ||
|
|
||
| 3. Error Handling: | ||
| ```typescript | ||
| @Submit() | ||
| async function processWithRetry( | ||
| ctx: GalaChainContext, | ||
| params: any | ||
| ): Promise<void> { | ||
| try { | ||
| await this.performAsyncOperation(ctx, params); | ||
| } catch (error) { | ||
| ctx.logger.error('Operation failed', { | ||
| error: error.message, | ||
| params | ||
| }); | ||
| throw error; // Rollback transaction | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| 4. Important Considerations: | ||
| - All chaincode operations must complete within transaction timeout | ||
| - External async calls (HTTP, etc.) are not allowed | ||
| - State changes are only committed at transaction end | ||
| - Use proper error handling for rollbacks | ||
|
|
||
| Note: While chaincode operations are async, they must be deterministic and complete within the transaction boundary. Long-running operations should be broken into multiple transactions. | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,76 @@ | ||
| ### Question | ||
|
|
||
|
|
||
| How can I implement batch token burns? | ||
|
|
||
|
|
||
| ### Answer | ||
|
|
||
|
|
||
| GalaChain's built-in `burnTokens` function already supports batch operations through its array parameter. Here's how to use it: | ||
|
|
||
| 1. Using the Built-in Batch Support: | ||
| ```typescript | ||
| import { burnTokens, BurnTokenQuantity, TokenInstanceKey } from '@gala-chain/chaincode'; | ||
| import { UserAlias } from '@gala-chain/api'; | ||
| import { BigNumber } from 'bignumber.js'; | ||
|
|
||
| // Example batch burn in your chaincode | ||
| async function batchBurnTokens(ctx: GalaChainContext, params: { | ||
| owner: UserAlias, | ||
| burns: Array<{ | ||
| collection: string, | ||
| category: string, | ||
| type: string, | ||
| instance: string, | ||
| quantity: BigNumber | ||
| }> | ||
| }) { | ||
| // Create array of burn quantities | ||
| const toBurn: BurnTokenQuantity[] = params.burns.map(burn => ({ | ||
| tokenInstanceKey: new TokenInstanceKey({ | ||
|
sentientforest marked this conversation as resolved.
Outdated
|
||
| collection: burn.collection, | ||
| category: burn.category, | ||
| type: burn.type, | ||
| additionalKey: '', | ||
| instance: burn.instance | ||
| }), | ||
| quantity: burn.quantity | ||
| })); | ||
|
|
||
| // Execute batch burn using the built-in function | ||
| const burns = await burnTokens(ctx, { | ||
| owner: params.owner, | ||
| toBurn, | ||
| preValidated: false | ||
| }); | ||
|
|
||
| return burns; // Returns array of TokenBurn objects | ||
| } | ||
| ``` | ||
|
|
||
| 2. Key Features: | ||
| - The `burnTokens` function accepts an array of `BurnTokenQuantity` objects | ||
| - Each `BurnTokenQuantity` specifies a token instance and amount to burn | ||
| - All burns in the batch are processed in a single transaction | ||
| - The function automatically handles: | ||
| * Allowance validation | ||
| * Balance checks | ||
| * Burn tracking | ||
| * Counter updates | ||
|
|
||
| 3. Best Practices: | ||
| - Group related burns together in a batch | ||
| - Keep batch sizes reasonable (avoid extremely large batches) | ||
| - Ensure all token instances exist before burning | ||
| - Verify sufficient balances for all burns | ||
| - Handle any validation errors appropriately | ||
|
|
||
| Key Points: | ||
| - No custom implementation needed - use the built-in batch support | ||
| - All burns in a batch are atomic - they all succeed or all fail | ||
| - Batch burns are automatically tracked in burn history | ||
| - The SDK handles all validation and state updates | ||
| - Burns are processed sequentially for deterministic results | ||
|
|
||
| Note: All operations in GalaChain must be executed sequentially to ensure deterministic behavior. Never use Promise.all or other parallel execution methods, as they can lead to non-deterministic results across multiple chaincode executions. | ||
60 changes: 60 additions & 0 deletions
60
docs/questions/best-practices-for-securing-sensitive-data-in-chaincode.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,60 @@ | ||
| ### Question | ||
|
|
||
|
|
||
| What are the best practices for securing sensitive data in chaincode? | ||
|
|
||
|
|
||
| ### Answer | ||
|
|
||
|
|
||
| When working with sensitive data in GalaChain, it's crucial to understand that all data stored on the blockchain is immutable and visible to all network participants. Here are the key principles and practices: | ||
|
|
||
| 1. Data Storage Guidelines: | ||
| - Never store private keys, passwords, or API keys on chain | ||
| - Avoid storing personally identifiable information (PII) | ||
| - Store only hashes of sensitive documents, not the documents themselves | ||
| - Use off-chain storage for sensitive data with only references on chain | ||
|
|
||
| 2. Data Privacy: | ||
| - Use private data collections for data that should only be accessible to specific organizations | ||
| - Implement proper access controls using `ctx.callingUser` checks | ||
| - Consider using encryption for sensitive fields that must be stored on chain | ||
| - Remember that encrypted data on chain is still visible and immutable | ||
|
|
||
| 3. Example Implementation: | ||
| ```typescript | ||
| class SecureContract extends Contract { | ||
| @Submit() | ||
| async storeDocumentReference( | ||
| ctx: GalaChainContext, | ||
| params: { | ||
| documentHash: string, // Hash of the actual document | ||
| storageReference: string // Reference to off-chain storage | ||
| } | ||
| ): Promise<void> { | ||
| // Verify caller has permission | ||
| if (!ctx.callingUser.hasRole('DOCUMENT_MANAGER')) { | ||
| throw new Error('Insufficient permissions'); | ||
| } | ||
|
|
||
| // Store only the hash and reference | ||
| const documentRef = new DocumentReference({ | ||
| hash: params.documentHash, | ||
| reference: params.storageReference, | ||
| owner: ctx.callingUser.id, | ||
| timestamp: Date.now() | ||
| }); | ||
|
|
||
| await putChainObject(ctx, documentRef); | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| 4. Security Best Practices: | ||
| - Validate all input data thoroughly | ||
| - Log access to sensitive data for audit purposes | ||
| - Use secure off-chain storage solutions for sensitive data | ||
| - Implement proper key management for any encryption keys | ||
| - Regular security audits of chaincode | ||
|
|
||
| Remember: Once data is written to the blockchain, it cannot be removed or modified. Always carefully consider what data should be stored on chain versus off chain. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,116 @@ | ||
| ### Question | ||
|
|
||
|
|
||
| How do I handle burn allowances in GalaChain? | ||
|
|
||
|
|
||
| ### Answer | ||
|
|
||
|
|
||
| GalaChain provides built-in mechanisms for managing burn allowances through the `TokenAllowance` class and `grantAllowance` function. Here's how to use them: | ||
|
|
||
| 1. The `TokenAllowance` Class: | ||
| GalaChain provides a built-in `TokenAllowance` class in `@gala-chain/api` that tracks token allowances, including burn permissions: | ||
|
|
||
| ```typescript | ||
| import { TokenAllowance, AllowanceType } from '@gala-chain/api'; | ||
|
|
||
| // TokenAllowance class structure | ||
| export class TokenAllowance extends ChainObject { | ||
| @ChainKey({ position: 0 }) | ||
| public grantedTo: UserAlias; // Who received the allowance | ||
|
|
||
| @ChainKey({ position: 1 }) | ||
| public collection: string; // Token collection | ||
|
|
||
| @ChainKey({ position: 2 }) | ||
| public category: string; // Token category | ||
|
|
||
| @ChainKey({ position: 3 }) | ||
| public type: string; // Token type | ||
|
|
||
| @ChainKey({ position: 4 }) | ||
| public additionalKey: string; // Additional identifier | ||
|
|
||
| @ChainKey({ position: 5 }) | ||
| public instance: string; // Token instance | ||
|
|
||
| public allowanceType: AllowanceType; // BURN, TRANSFER, etc. | ||
| public quantity: BigNumber; // Amount allowed | ||
| public uses: BigNumber; // Number of times allowance can be used | ||
| public expires: number; // When the allowance expires | ||
| } | ||
| ``` | ||
|
|
||
| 2. Using the `grantAllowance` Function: | ||
| GalaChain provides a `grantAllowance` function in the chaincode library to create allowances: | ||
|
|
||
| ```typescript | ||
| import { grantAllowance, GrantAllowanceQuantity, AllowanceType } from '@gala-chain/chaincode'; | ||
|
|
||
| // Example usage in your chaincode | ||
| async function createBurnAllowance(ctx: GalaChainContext, params: { | ||
| tokenInstance: TokenInstanceQueryKey, | ||
| grantedTo: UserAlias, | ||
| quantity: BigNumber, | ||
| uses?: BigNumber, | ||
| expires?: number | ||
| }) { | ||
| const allowances = await grantAllowance(ctx, { | ||
| tokenInstance: params.tokenInstance, | ||
| allowanceType: AllowanceType.BURN, | ||
| quantities: [{ | ||
| grantedTo: params.grantedTo, | ||
| quantity: params.quantity | ||
| }], | ||
| uses: params.uses ?? new BigNumber(1), | ||
| expires: params.expires ?? inverseTime(Date.now() + 24 * 60 * 60 * 1000) // 24 hours | ||
| }); | ||
| return allowances; | ||
| } | ||
| ``` | ||
|
|
||
| 3. Contract Implementation Example: | ||
| The GalaChain token contract provides built-in methods for managing burn allowances: | ||
|
|
||
| ```typescript | ||
| import { GrantAllowanceDto, TokenAllowance, AllowanceType } from '@gala-chain/api'; | ||
|
|
||
| @Submit({ | ||
| in: GrantAllowanceDto, | ||
| out: { arrayOf: TokenAllowance } | ||
| }) | ||
| public async GrantBurnAllowance(ctx: GalaChainContext, dto: GrantAllowanceDto): Promise<TokenAllowance[]> { | ||
| return grantAllowance(ctx, { | ||
| tokenInstance: dto.tokenInstance, | ||
| allowanceType: AllowanceType.BURN, | ||
| quantities: dto.quantities, | ||
| uses: dto.uses, | ||
| expires: dto.expires | ||
| }); | ||
| } | ||
|
|
||
| ``` | ||
|
|
||
| Best Practices: | ||
| - Use the built-in `TokenAllowance` class for consistent allowance tracking | ||
| - Leverage the `grantAllowance` function for standardized allowance creation | ||
| - Set appropriate expiration times | ||
| - Specify the number of uses allowed | ||
| - Track allowance usage | ||
|
|
||
| Key Points: | ||
| - Allowances are managed through the standard `TokenAllowance` class | ||
| - The `AllowanceType.BURN` type specifically enables burn permissions | ||
| - Allowances can be time-limited through the `expires` field | ||
| - Usage can be limited through the `uses` field | ||
| - Allowances are tracked and validated automatically | ||
|
|
||
| Allowance Tips: | ||
| - Always set an expiration time | ||
| - Consider limiting the number of uses | ||
| - Use the built-in validation | ||
| - Monitor allowance events | ||
| - Keep allowance records | ||
|
|
||
| Note: All operations in GalaChain must be executed sequentially to ensure deterministic behavior. Never use Promise.all or other parallel execution methods, as they can lead to non-deterministic results across multiple chaincode executions. |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.