Complément du SDK de jetons avec des rapports personnalisés hors livre
Préface
Il s’agit de la première partie d’une série sur l’ajout de rapports personnalisés au SDK de jetons. Ici, nous démontrons une hors registre approche, la sur le grand livre Cette approche peut être explorée dans la deuxième partie.
Ci-dessous, une comparaison rapide entre les 2 méthodes pour vous aider à décider de l’approche à utiliser avant de vous plonger dans la lecture:
introduction
R3 a introduit le SDK Tokens dans Corda 4.3; c’est un excellent ajout à un produit déjà génial, et si vous lisez cet article; alors je suppose que vous le connaissez déjà (sinon, veuillez d’abord le lire).
Le SDK expose à la fois FungibleToken
et NonFugibleToken
dans des tableaux personnalisés (fungible_token
et non_fungible_token
respectivement), ce qui vous donne plus de liberté pour interroger ces états depuis l’intérieur de vos flux, services ou même de votre outil SQL préféré (par ex. pgAdmin
pour PostgreSQL
).
Mais malheureusement, vous êtes limité aux requêtes basées sur les attributs de ces états, et si vous utilisez un outil SQL; la plupart du temps, vous devrez créer des jointures avec d’autres tables de nœuds. Par exemple, pour exclure les jetons consommés de votre jeu de résultats, vous devez joindre votre requête à vault_states
vérifier la state_status
valeur.
Mais que se passe-t-il si nous voulons un autre type de requêtes? Par exemple:
- Combien de jetons ont été émis entre 2 dates?
- Quelle est la quantité moyenne
HolderA
se déplace versHolderB
? - À quelle fréquence
HolderC
racheter leurs jetons?
Pour ce faire, nous allons créer un tableau avec les colonnes suivantes:
Comme vous pouvez le voir, le tableau ci-dessus contient tout ce dont nous avons besoin pour créer des requêtes élaborées; alors commençons à construire ce truc!
la mise en oeuvre
- Créer une classe
TokenTransactionSchema
:
/**
* The family of schemas for TokenTransaction.
*/
public class TokenTransactionSchema {}
- Créer une classe
TokenTransactionSchemaV1
:
public class TokenTransactionSchemaV1 extends MappedSchema { public TokenTransactionSchemaV1() {
super(TokenTransactionSchema.class, 1,
Collections.singletonList(
PersistentTokenTransaction.class));
} /*
* Notice that it "implements Serializable" unlike state
* custom schemas which "extends PersistentState".
* */
@Entity
@Table(name = "token_transactions")
public static class PersistentTokenTransaction
implements Serializable { // @Id column is required by Hibernate.
@Id
@Column(name = "id", nullable = false)
private final String id;
@Column(name = "tx_hash", nullable = false)
private final String txHash;
@Column(name = "tx_timestamp", nullable = false)
private final Instant txTimestamp;
@Column(name = "tx_type", nullable = false)
private final String txType;
@Column(name = "from_holder")
private final String fromHolder;
@Column(name = "to_holder")
private final String toHolder;
/*
* Tokens SDK uses "Amount.quantity" of type "long",
* so we'll use the same.
* */
@Column(name = "quantity", nullable = false)
private final long quantity; public PersistentTokenTransaction(String id, String txHash,
Instant txTimestamp, String txType,
String fromHolder, String toHolder,
long quantity) {
this.id = id;
this.txHash = txHash;
this.txTimestamp = txTimestamp;
this.txType = txType;
this.fromHolder = fromHolder;
this.toHolder = toHolder;
this.quantity = quantity;
} // Default constructor is required by hibernate.
public PersistentTokenTransaction() {
this.id = null;
this.txHash = null;
this.txTimestamp = null;
this.txType = null;
this.fromHolder = null;
this.toHolder = null;
this.quantity = 0;
} public String getId() {
return id;
} public String getTxHash() {
return txHash;
} public Instant getTxTimestamp() {
return txTimestamp;
} public String getTxType() {
return txType;
} public String getFromHolder() {
return fromHolder;
} public String getToHolder() {
return toHolder;
} public long getQuantity() {
return quantity;
}
}
}
Veuillez noter dans le code ci-dessus:
- j’ai utilisé
long
pourquantity
, mais tout dépend de vos besoins; vous pourriez utiliser autre chose commedouble
ouBigDecimal
. - Vous pouvez transmettre n’importe quelle valeur pour
txType
, par exemple:ISSUE
,MOVE
, ouREDEEM
.
Vous devriez vous retrouver avec un code ressemblant à ceci:
- Maintenant, nous pouvons conserver l’entité à l’intérieur de nos flux, et c’est à vous de décider ce que vous voulez passer comme valeurs pour
from_holder
etto_holder
; il pourrait êtreParty.name
,AccountInfo.name
ouAccountInfo.identifier
:
SignedTransaction moveTokensTx = subFlow(new MoveFungibleTokens(
Collections.singletonList(partyAndAmount),
Collections.emptyList(),
heldByMint, mint));// Persist token-transaction.
PersistentTokenTransaction tokenTransaction =
new PersistentTokenTransaction(
new UniqueIdentifier().getId().toString(),
moveTokensTx.getId().toString(), Instant.now(),
"MOVE",
"Mint",
"HolderA",
100);getServiceHub().withEntityManager(entityManager -> {
entityManager.persist(tokenTransaction);
return null;
});
Résultats
En utilisant l’approche illustrée dans cet article, vous pourrez obtenir de meilleurs résultats de rapport sur les transactions liées aux jetons en interrogeant le token_transactions
table.
Évidemment, mon travail n’est qu’un modèle avec lequel vous pouvez commencer et le modifier selon vos besoins.
Avis de non-responsabilité sur les données hors livre!
- Les données stockées dans la table personnalisée sont prises en compte hors registre.
Même si nous insérons ces données de l’intérieur de nos flux, elles ne sont pas suivies et protégées contre la falsification par le DLT de Corda; car ce n’est pas comme un État qui résulte d’une transaction signée par un quorum de parties et finalisée par un notaire.
Contrairement aux données du grand livre (c’est-à-dire les états de Corda); n’importe qui peut se connecter à la base de données du nœud et falsifier les données de la table personnalisée sans laisser de trace d’audit ni provoquer d’erreur.
Cette approche est donc bonne pour une mise en œuvre simple et rapide, mais elle ne garantit pas les données vérifiables immuables sécurisées cryptographiquement. - Vous devez assurer l’enregistrement atomique des données au registre (jeton) et des données hors registre (rapport).
Cela signifie que vous devez vous assurer que lorsque le flux du SDK Tokens se termine avec succès; un enregistrement est également inséré avec succès dans votre table personnalisée. Cette séquence d’événements peut être interrompue entre les deux par une défaillance de nœud ou une exception de base de données, vous laissant avec une divergence (c’est-à-dire que les données de jeton existent, mais les données de rapport n’existent pas).
Références
– – – – – – – – –
Académie B9lab a un Cours Corda qui peut vous faire passer de la connaissance de la blockchain à la création de cordapps qui fonctionnent avec de l’argent, de la dette et d’autres contrats, et facilite des accords de règlement flexibles et potentiellement complexes sur plusieurs devises et instruments.
Toujours pas sûr? Jetez un oeil à notre libre Cours Corda 101