1- import { Constr , Data , fromHex , toHex , TxComplete , TxHash , UTxO } from "lucid-cardano" ;
1+ import {
2+ Constr ,
3+ Data ,
4+ fromHex ,
5+ toHex ,
6+ TxComplete ,
7+ TxHash ,
8+ UTxO ,
9+ } from "lucid-cardano" ;
210import { Hydra } from "./hydra" ;
311
412import * as ed25519 from "@noble/ed25519" ;
@@ -8,103 +16,107 @@ import { Keys } from "../hooks/useKeys";
816ed25519 . etc . sha512Sync = ( ...m ) => sha512 ( ed25519 . etc . concatBytes ( ...m ) ) ;
917
1018export class HydraMultiplayer {
11- keys : Keys ;
12- hydra : Hydra ;
13- myIP : number = 0 ;
14- latestUTxO : UTxO | null = null ;
15- packetQueue : Packet [ ] = [ ] ;
16-
17- constructor ( keys : Keys , url : string ) {
18- this . keys = keys ;
19- this . hydra = new Hydra ( url , 100 ) ;
20- this . hydra . onTxSeen = this . onTxSeen . bind ( this ) ;
21-
22- this . SendPacket = this . SendPacket . bind ( this ) ;
23- this . setIP = this . setIP . bind ( this ) ;
24- }
19+ keys : Keys ;
20+ hydra : Hydra ;
21+ myIP : number = 0 ;
22+ latestUTxO : UTxO | null = null ;
23+ packetQueue : Packet [ ] = [ ] ;
24+
25+ constructor ( keys : Keys , url : string ) {
26+ this . keys = keys ;
27+ this . hydra = new Hydra ( url , 100 ) ;
28+ this . hydra . onTxSeen = this . onTxSeen . bind ( this ) ;
29+
30+ this . SendPacket = this . SendPacket . bind ( this ) ;
31+ this . setIP = this . setIP . bind ( this ) ;
32+ }
2533
26- public setIP ( ip : number ) {
27- this . myIP = ip ;
28- }
34+ public setIP ( ip : number ) {
35+ this . myIP = ip ;
36+ }
2937
30- public async selectUTxO ( ) : Promise < void > {
31- if ( ! ! this . latestUTxO ) {
32- return ;
33- }
34- await this . hydra . populateUTxO ( ) ;
35- let utxos = await this . hydra . getUtxos ( this . keys . address ! ) ;
36- // TODO: robust
37- if ( this . myIP === 1 ) {
38- this . latestUTxO = utxos . find ( u => u . outputIndex === 1 ) ! ;
39- } else {
40- this . latestUTxO = utxos . find ( u => u . outputIndex === 0 ) ! ;
41- }
38+ public async selectUTxO ( ) : Promise < void > {
39+ if ( this . latestUTxO ) {
40+ return ;
4241 }
43-
44- public async SendPacket ( to : number , from : number , data : Uint8Array ) : Promise < void > {
45- this . packetQueue . push ( { to, from, data } ) ;
46- await this . sendPacketQueue ( ) ;
42+ await this . hydra . populateUTxO ( ) ;
43+ const utxos = await this . hydra . getUtxos ( this . keys . address ! ) ;
44+ // TODO: robust
45+ if ( this . myIP === 1 ) {
46+ this . latestUTxO = utxos . find ( ( u ) => u . outputIndex === 1 ) ! ;
47+ } else {
48+ this . latestUTxO = utxos . find ( ( u ) => u . outputIndex === 0 ) ! ;
4749 }
50+ }
51+
52+ public async SendPacket (
53+ to : number ,
54+ from : number ,
55+ data : Uint8Array ,
56+ ) : Promise < void > {
57+ this . packetQueue . push ( { to, from, data } ) ;
58+ await this . sendPacketQueue ( ) ;
59+ }
4860
49- public async sendPacketQueue ( ) : Promise < void > {
50- if ( this . packetQueue . length == 0 ) {
51- return ;
52- }
53- await this . selectUTxO ( ) ;
54- let datum = encodePackets ( this . packetQueue ) ;
55-
56- let [ newUTxO , tx ] = buildTx ( this . latestUTxO ! , this . keys , datum ) ;
57- await this . hydra . submitTx ( tx ) ;
58- this . latestUTxO = newUTxO ;
59- this . packetQueue = [ ] ;
61+ public async sendPacketQueue ( ) : Promise < void > {
62+ if ( this . packetQueue . length == 0 ) {
63+ return ;
6064 }
65+ await this . selectUTxO ( ) ;
66+ const datum = encodePackets ( this . packetQueue ) ;
6167
62- public onTxSeen ( _txId : TxHash , tx : TxComplete ) : void {
63- // TODO: tolerate other txs here
64- const output = tx . txComplete . body ( ) . outputs ( ) . get ( 0 ) ;
65- const packetsRaw = output ?. datum ( ) ?. as_data ( ) ?. get ( ) . to_bytes ( ) ;
66- if ( ! packetsRaw ) {
67- return ;
68- }
69- const packets = decodePackets ( packetsRaw ) ;
70- for ( const packet of packets ) {
71- if ( packet . to == this . myIP ) {
72- let buf = window . Module . _malloc ! ( packet . data . length ) ;
73- window . Module . HEAPU8 ! . set ( packet . data , buf ) ;
74- window . Module . _ReceivePacket ! ( packet . from , buf , packet . data . length ) ;
75- window . Module . _free ! ( buf ) ;
76- }
77- }
68+ const [ newUTxO , tx ] = buildTx ( this . latestUTxO ! , this . keys , datum ) ;
69+ await this . hydra . submitTx ( tx ) ;
70+ this . latestUTxO = newUTxO ;
71+ this . packetQueue = [ ] ;
72+ }
73+
74+ public onTxSeen ( _txId : TxHash , tx : TxComplete ) : void {
75+ // TODO: tolerate other txs here
76+ const output = tx . txComplete . body ( ) . outputs ( ) . get ( 0 ) ;
77+ const packetsRaw = output ?. datum ( ) ?. as_data ( ) ?. get ( ) . to_bytes ( ) ;
78+ if ( ! packetsRaw ) {
79+ return ;
80+ }
81+ const packets = decodePackets ( packetsRaw ) ;
82+ for ( const packet of packets ) {
83+ if ( packet . to == this . myIP ) {
84+ const buf = window . Module . _malloc ! ( packet . data . length ) ;
85+ window . Module . HEAPU8 ! . set ( packet . data , buf ) ;
86+ window . Module . _ReceivePacket ! ( packet . from , buf , packet . data . length ) ;
87+ window . Module . _free ! ( buf ) ;
88+ }
7889 }
90+ }
7991}
8092
8193interface Packet {
82- to : number ,
83- from : number ,
84- data : Uint8Array ,
94+ to : number ;
95+ from : number ;
96+ data : Uint8Array ;
8597}
8698
8799function encodePackets ( packets : Packet [ ] ) : string {
88100 return Data . to (
89101 packets . map (
90- ( { to, from, data } ) => new Constr ( 0 , [ BigInt ( to ) , BigInt ( from ) , toHex ( data ) ] )
91- )
102+ ( { to, from, data } ) =>
103+ new Constr ( 0 , [ BigInt ( to ) , BigInt ( from ) , toHex ( data ) ] ) ,
104+ ) ,
92105 ) ;
93106}
94107
95108function decodePackets ( raw : Uint8Array ) : Packet [ ] {
96109 const packets = Data . from ( toHex ( raw ) ) as Constr < Data > [ ] ;
97110 return packets . map ( ( packet ) => {
98- let [ to , from , data ] = packet . fields ;
111+ const [ to , from , data ] = packet . fields ;
99112 return {
100113 to : Number ( to ) ,
101114 from : Number ( from ) ,
102115 data : fromHex ( data as string ) ,
103- }
116+ } ;
104117 } ) ;
105118}
106119
107-
108120const buildTx = (
109121 inputUtxo : UTxO ,
110122 keys : Keys ,
@@ -123,9 +135,7 @@ const buildTx = (
123135 `0181a300581d60${ keys . publicKeyHashHex ! } 018200a0028201d818${ lengthLengthTag } ${ datumLengthHex } ${ datum } ` + // Output to users PKH
124136 `0200` ; // No fee
125137
126- const txId = toHex (
127- blake2b ( fromHex ( txBodyByHand ) , { dkLen : 256 / 8 } ) ,
128- ) ;
138+ const txId = toHex ( blake2b ( fromHex ( txBodyByHand ) , { dkLen : 256 / 8 } ) ) ;
129139 const signature = toHex ( ed25519 . sign ( txId , keys . privateKeyBytes ! ) ) ;
130140
131141 const witnessSetByHand = `a10081825820${ keys . publicKeyHex ! } 5840${ signature } ` ; // just signed by the user
@@ -142,4 +152,4 @@ const buildTx = (
142152 } ;
143153
144154 return [ newUtxo , txByHand ] ;
145- } ;
155+ } ;
0 commit comments