@alephium/web3 0.2.0-rc.15 → 0.2.0-rc.17

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -119,11 +119,13 @@ class Compiled<T extends Artifact> {
119
119
  }
120
120
  }
121
121
 
122
+ type CodeInfo = { sourceCodeHash: string; bytecodeDebugPatch: string; codeHashDebug: string; warnings: string[] }
123
+
122
124
  class ProjectArtifact {
123
125
  static readonly artifactFileName = '.project.json'
124
126
 
125
127
  compilerOptionsUsed: node.CompilerOptions
126
- infos: Map<string, { sourceCodeHash: string; warnings: string[] }>
128
+ infos: Map<string, CodeInfo>
127
129
 
128
130
  static checkCompilerOptionsParameter(compilerOptions: node.CompilerOptions): void {
129
131
  if (Object.keys(compilerOptions).length != Object.keys(DEFAULT_NODE_COMPILER_OPTIONS).length) {
@@ -136,10 +138,7 @@ class ProjectArtifact {
136
138
  }
137
139
  }
138
140
 
139
- constructor(
140
- compilerOptionsUsed: node.CompilerOptions,
141
- infos: Map<string, { sourceCodeHash: string; warnings: string[] }>
142
- ) {
141
+ constructor(compilerOptionsUsed: node.CompilerOptions, infos: Map<string, CodeInfo>) {
143
142
  ProjectArtifact.checkCompilerOptionsParameter(compilerOptionsUsed)
144
143
  this.compilerOptionsUsed = compilerOptionsUsed
145
144
  this.infos = infos
@@ -184,7 +183,7 @@ class ProjectArtifact {
184
183
  const content = await fsPromises.readFile(filepath)
185
184
  const json = JSON.parse(content.toString())
186
185
  const compilerOptionsUsed = json.compilerOptionsUsed as node.CompilerOptions
187
- const files = new Map(Object.entries<{ sourceCodeHash: string; warnings: string[] }>(json.infos))
186
+ const files = new Map(Object.entries<CodeInfo>(json.infos))
188
187
  return new ProjectArtifact(compilerOptionsUsed, files)
189
188
  }
190
189
  }
@@ -221,16 +220,20 @@ export class Project {
221
220
  scripts: Compiled<Script>[],
222
221
  compilerOptions: node.CompilerOptions
223
222
  ): ProjectArtifact {
224
- const files: Map<string, { sourceCodeHash: string; warnings: string[] }> = new Map()
223
+ const files: Map<string, CodeInfo> = new Map()
225
224
  contracts.forEach((c) => {
226
225
  files.set(c.sourceFile.contractPath, {
227
226
  sourceCodeHash: c.sourceFile.sourceCodeHash,
227
+ bytecodeDebugPatch: c.artifact.bytecodeDebugPatch,
228
+ codeHashDebug: c.artifact.codeHashDebug,
228
229
  warnings: c.warnings
229
230
  })
230
231
  })
231
232
  scripts.forEach((s) => {
232
233
  files.set(s.sourceFile.contractPath, {
233
234
  sourceCodeHash: s.sourceFile.sourceCodeHash,
235
+ bytecodeDebugPatch: s.artifact.bytecodeDebugPatch,
236
+ codeHashDebug: '',
234
237
  warnings: s.warnings
235
238
  })
236
239
  })
@@ -238,6 +241,8 @@ export class Project {
238
241
  sourceFiles.slice(compiledSize).forEach((c) => {
239
242
  files.set(c.contractPath, {
240
243
  sourceCodeHash: c.sourceCodeHash,
244
+ bytecodeDebugPatch: '',
245
+ codeHashDebug: '',
241
246
  warnings: []
242
247
  })
243
248
  })
@@ -327,7 +332,9 @@ export class Project {
327
332
  }
328
333
 
329
334
  contractByCodeHash(codeHash: string): Contract {
330
- const contract = this.contracts.find((c) => c.artifact.codeHash === codeHash)
335
+ const contract = this.contracts.find(
336
+ (c) => c.artifact.codeHash === codeHash || c.artifact.codeHashDebug == codeHash
337
+ )
331
338
  if (typeof contract === 'undefined') {
332
339
  throw new Error(`Unknown code with code hash: ${codeHash}`)
333
340
  }
@@ -394,10 +401,10 @@ export class Project {
394
401
  const warnings = info.warnings
395
402
  const artifactDir = file.getArtifactPath(artifactsRootDir)
396
403
  if (file.type === SourceType.Contract) {
397
- const artifact = await Contract.fromArtifactFile(artifactDir)
404
+ const artifact = await Contract.fromArtifactFile(artifactDir, info.bytecodeDebugPatch, info.codeHashDebug)
398
405
  contracts.push(new Compiled(file, artifact, warnings))
399
406
  } else if (file.type === SourceType.Script) {
400
- const artifact = await Script.fromArtifactFile(artifactDir)
407
+ const artifact = await Script.fromArtifactFile(artifactDir, info.bytecodeDebugPatch)
401
408
  scripts.push(new Compiled(file, artifact, warnings))
402
409
  }
403
410
  }
@@ -476,7 +483,7 @@ export class Project {
476
483
  const { errorOnWarnings, ...nodeCompilerOptions } = { ...DEFAULT_COMPILER_OPTIONS, ...compilerOptionsPartial }
477
484
  const projectArtifact = await ProjectArtifact.from(artifactsRootDir)
478
485
  if (typeof projectArtifact === 'undefined' || projectArtifact.needToReCompile(nodeCompilerOptions, sourceFiles)) {
479
- console.log(`Compile contracts in folder "${contractsRootDir}"`)
486
+ console.log(`Compiling contracts in folder "${contractsRootDir}"`)
480
487
  Project.currentProject = await Project.compile(
481
488
  provider,
482
489
  sourceFiles,
@@ -486,7 +493,7 @@ export class Project {
486
493
  nodeCompilerOptions
487
494
  )
488
495
  } else {
489
- console.log(`Load compiled contracts from folder "${artifactsRootDir}"`)
496
+ console.log(`Contracts are compiled already. Loading them from folder "${artifactsRootDir}"`)
490
497
  Project.currentProject = await Project.loadArtifacts(
491
498
  provider,
492
499
  sourceFiles,
@@ -526,27 +533,37 @@ export abstract class Artifact {
526
533
 
527
534
  export class Contract extends Artifact {
528
535
  readonly bytecode: string
536
+ readonly bytecodeDebugPatch: string
529
537
  readonly codeHash: string
530
538
  readonly fieldsSig: FieldsSig
531
539
  readonly eventsSig: EventSig[]
532
540
 
541
+ readonly bytecodeDebug: string
542
+ readonly codeHashDebug: string
543
+
533
544
  constructor(
534
545
  name: string,
535
546
  bytecode: string,
547
+ bytecodeDebugPatch: string,
536
548
  codeHash: string,
549
+ codeHashDebug: string,
537
550
  fieldsSig: FieldsSig,
538
551
  eventsSig: EventSig[],
539
552
  functions: FunctionSig[]
540
553
  ) {
541
554
  super(name, functions)
542
555
  this.bytecode = bytecode
556
+ this.bytecodeDebugPatch = bytecodeDebugPatch
543
557
  this.codeHash = codeHash
544
558
  this.fieldsSig = fieldsSig
545
559
  this.eventsSig = eventsSig
560
+
561
+ this.bytecodeDebug = ralph.buildDebugBytecode(this.bytecode, this.bytecodeDebugPatch)
562
+ this.codeHashDebug = codeHashDebug
546
563
  }
547
564
 
548
565
  // TODO: safely parse json
549
- static fromJson(artifact: any): Contract {
566
+ static fromJson(artifact: any, bytecodeDebugPatch = '', codeHashDebug = ''): Contract {
550
567
  if (
551
568
  artifact.name == null ||
552
569
  artifact.bytecode == null ||
@@ -560,7 +577,9 @@ export class Contract extends Artifact {
560
577
  const contract = new Contract(
561
578
  artifact.name,
562
579
  artifact.bytecode,
580
+ bytecodeDebugPatch,
563
581
  artifact.codeHash,
582
+ codeHashDebug ? codeHashDebug : artifact.codeHash,
564
583
  artifact.fieldsSig,
565
584
  artifact.eventsSig,
566
585
  artifact.functions
@@ -569,14 +588,23 @@ export class Contract extends Artifact {
569
588
  }
570
589
 
571
590
  static fromCompileResult(result: node.CompileContractResult): Contract {
572
- return new Contract(result.name, result.bytecode, result.codeHash, result.fields, result.events, result.functions)
591
+ return new Contract(
592
+ result.name,
593
+ result.bytecode,
594
+ result.bytecodeDebugPatch,
595
+ result.codeHash,
596
+ result.codeHashDebug,
597
+ result.fields,
598
+ result.events,
599
+ result.functions
600
+ )
573
601
  }
574
602
 
575
603
  // support both 'code.ral' and 'code.ral.json'
576
- static async fromArtifactFile(path: string): Promise<Contract> {
604
+ static async fromArtifactFile(path: string, bytecodeDebugPatch: string, codeHashDebug: string): Promise<Contract> {
577
605
  const content = await fsPromises.readFile(path)
578
606
  const artifact = JSON.parse(content.toString())
579
- return Contract.fromJson(artifact)
607
+ return Contract.fromJson(artifact, bytecodeDebugPatch, codeHashDebug)
580
608
  }
581
609
 
582
610
  async fetchState(address: string, group: number): Promise<ContractState> {
@@ -619,11 +647,19 @@ export class Contract extends Artifact {
619
647
  return bs58.encode(bytes)
620
648
  }
621
649
 
650
+ private _printDebugMessages(funcName: string, messages: DebugMessage[]) {
651
+ if (messages.length != 0) {
652
+ console.log(`Testing ${this.name}.${funcName}:`)
653
+ messages.forEach((m) => console.log(`Debug - ${m.contractAddress} - ${m.message}`))
654
+ }
655
+ }
656
+
622
657
  private async _test(
623
658
  funcName: string,
624
659
  params: TestContractParams,
625
660
  expectPublic: boolean,
626
- accessType: string
661
+ accessType: string,
662
+ printDebugMessages: boolean
627
663
  ): Promise<TestContractResult> {
628
664
  const apiParams: node.TestContract = this.toTestContract(funcName, params)
629
665
  const apiResult = await Project.currentProject.nodeProvider.contracts.postContractsTestContract(apiParams)
@@ -631,6 +667,9 @@ export class Contract extends Artifact {
631
667
  const methodIndex =
632
668
  typeof params.testMethodIndex !== 'undefined' ? params.testMethodIndex : this.getMethodIndex(funcName)
633
669
  const isPublic = this.functions[`${methodIndex}`].isPublic
670
+ if (printDebugMessages) {
671
+ this._printDebugMessages(funcName, apiResult.debugMessages)
672
+ }
634
673
  if (isPublic === expectPublic) {
635
674
  const result = await this.fromTestContractResult(methodIndex, apiResult)
636
675
  return result
@@ -639,12 +678,20 @@ export class Contract extends Artifact {
639
678
  }
640
679
  }
641
680
 
642
- async testPublicMethod(funcName: string, params: TestContractParams): Promise<TestContractResult> {
643
- return this._test(funcName, params, true, 'public')
681
+ async testPublicMethod(
682
+ funcName: string,
683
+ params: TestContractParams,
684
+ printDebugMessages = true
685
+ ): Promise<TestContractResult> {
686
+ return this._test(funcName, params, true, 'public', printDebugMessages)
644
687
  }
645
688
 
646
- async testPrivateMethod(funcName: string, params: TestContractParams): Promise<TestContractResult> {
647
- return this._test(funcName, params, false, 'private')
689
+ async testPrivateMethod(
690
+ funcName: string,
691
+ params: TestContractParams,
692
+ printDebugMessages = true
693
+ ): Promise<TestContractResult> {
694
+ return this._test(funcName, params, false, 'private', printDebugMessages)
648
695
  }
649
696
 
650
697
  toApiFields(fields?: Fields): node.Val[] {
@@ -680,7 +727,7 @@ export class Contract extends Artifact {
680
727
  return {
681
728
  group: params.group,
682
729
  address: params.address,
683
- bytecode: this.bytecode,
730
+ bytecode: this.bytecodeDebug,
684
731
  initialFields: this.toApiFields(params.initialFields),
685
732
  initialAsset: typeof params.initialAsset !== 'undefined' ? toApiAsset(params.initialAsset) : undefined,
686
733
  methodIndex: this.getMethodIndex(funcName),
@@ -746,6 +793,7 @@ export class Contract extends Artifact {
746
793
  return {
747
794
  address: result.address,
748
795
  contractId: binToHex(contractIdFromAddress(result.address)),
796
+ contractAddress: result.address,
749
797
  returns: fromApiArray(result.returns, this.functions[`${methodIndex}`].returnTypes),
750
798
  gasUsed: result.gasUsed,
751
799
  contracts: await Promise.all(result.contracts.map((contract) => this.fromApiContractState(contract))),
@@ -760,7 +808,8 @@ export class Contract extends Artifact {
760
808
  throw Error(`Cannot find codeHash for the contract address: ${contractAddress}`)
761
809
  }
762
810
  })
763
- )
811
+ ),
812
+ debugMessages: result.debugMessages
764
813
  }
765
814
  }
766
815
 
@@ -797,20 +846,28 @@ export class Contract extends Artifact {
797
846
 
798
847
  export class Script extends Artifact {
799
848
  readonly bytecodeTemplate: string
849
+ readonly bytecodeDebugPatch: string
800
850
  readonly fieldsSig: FieldsSig
801
851
 
802
- constructor(name: string, bytecodeTemplate: string, fieldsSig: FieldsSig, functions: FunctionSig[]) {
852
+ constructor(
853
+ name: string,
854
+ bytecodeTemplate: string,
855
+ bytecodeDebugPatch: string,
856
+ fieldsSig: FieldsSig,
857
+ functions: FunctionSig[]
858
+ ) {
803
859
  super(name, functions)
804
860
  this.bytecodeTemplate = bytecodeTemplate
861
+ this.bytecodeDebugPatch = bytecodeDebugPatch
805
862
  this.fieldsSig = fieldsSig
806
863
  }
807
864
 
808
865
  static fromCompileResult(result: node.CompileScriptResult): Script {
809
- return new Script(result.name, result.bytecodeTemplate, result.fields, result.functions)
866
+ return new Script(result.name, result.bytecodeTemplate, result.bytecodeDebugPatch, result.fields, result.functions)
810
867
  }
811
868
 
812
869
  // TODO: safely parse json
813
- static fromJson(artifact: any): Script {
870
+ static fromJson(artifact: any, bytecodeDebugPatch = ''): Script {
814
871
  if (
815
872
  artifact.name == null ||
816
873
  artifact.bytecodeTemplate == null ||
@@ -819,13 +876,19 @@ export class Script extends Artifact {
819
876
  ) {
820
877
  throw Error('The artifact JSON for script is incomplete')
821
878
  }
822
- return new Script(artifact.name, artifact.bytecodeTemplate, artifact.fieldsSig, artifact.functions)
879
+ return new Script(
880
+ artifact.name,
881
+ artifact.bytecodeTemplate,
882
+ bytecodeDebugPatch,
883
+ artifact.fieldsSig,
884
+ artifact.functions
885
+ )
823
886
  }
824
887
 
825
- static async fromArtifactFile(path: string): Promise<Script> {
888
+ static async fromArtifactFile(path: string, bytecodeDebugPatch: string): Promise<Script> {
826
889
  const content = await fsPromises.readFile(path)
827
890
  const artifact = JSON.parse(content.toString())
828
- return this.fromJson(artifact)
891
+ return this.fromJson(artifact, bytecodeDebugPatch)
829
892
  }
830
893
 
831
894
  override toString(): string {
@@ -981,14 +1044,18 @@ export interface ContractEventByTxId {
981
1044
  fields: Fields
982
1045
  }
983
1046
 
1047
+ export type DebugMessage = node.DebugMessage
1048
+
984
1049
  export interface TestContractResult {
985
1050
  address: string
986
1051
  contractId: string
1052
+ contractAddress: string
987
1053
  returns: Val[]
988
1054
  gasUsed: number
989
1055
  contracts: ContractState[]
990
1056
  txOutputs: Output[]
991
1057
  events: ContractEventByTxId[]
1058
+ debugMessages: DebugMessage[]
992
1059
  }
993
1060
  export declare type Output = AssetOutput | ContractOutput
994
1061
  export interface AssetOutput extends Asset {
@@ -343,6 +343,31 @@ function invalidVal(tpe: string, value: Val): Error {
343
343
  return Error(`Invalid API value ${value} for type ${tpe}`)
344
344
  }
345
345
 
346
+ export function buildDebugBytecode(bytecode: string, bytecodePatch: string): string {
347
+ if (bytecodePatch === '') {
348
+ return bytecode
349
+ }
350
+
351
+ const pattern = /[=+-][0-9a-f]*/g
352
+ let result = ''
353
+ let index = 0
354
+ for (const parts of bytecodePatch.matchAll(pattern)) {
355
+ const part = parts[0]
356
+ const diffType = part[0]
357
+ if (diffType === '=') {
358
+ const length = parseInt(part.substring(1))
359
+ result = result + bytecode.slice(index, index + length)
360
+ index = index + length
361
+ } else if (diffType === '+') {
362
+ result = result + part.substring(1)
363
+ } else {
364
+ const length = parseInt(part.substring(1))
365
+ index = index + length
366
+ }
367
+ }
368
+ return result
369
+ }
370
+
346
371
  // export function buildContractByteCode(
347
372
  // compiled: node.TemplateContractByteCode,
348
373
  // templateVariables: TemplateVariables
@@ -1 +0,0 @@
1
- export {};
@@ -1,24 +0,0 @@
1
- "use strict";
2
- /*
3
- Copyright 2018 - 2022 The Alephium Authors
4
- This file is part of the alephium project.
5
-
6
- The library is free software: you can redistribute it and/or modify
7
- it under the terms of the GNU Lesser General Public License as published by
8
- the Free Software Foundation, either version 3 of the License, or
9
- (at your option) any later version.
10
-
11
- The library is distributed in the hope that it will be useful,
12
- but WITHOUT ANY WARRANTY; without even the implied warranty of
13
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
- GNU Lesser General Public License for more details.
15
-
16
- You should have received a copy of the GNU Lesser General Public License
17
- along with the library. If not, see <http://www.gnu.org/licenses/>.
18
- */
19
- const { rename } = require('fs');
20
- rename(process.argv[2], process.argv[3], function (error) {
21
- if (error)
22
- console.log(error);
23
- console.log(`Renamed ${process.argv[2]} to ${process.argv[3]}.`);
24
- });
@@ -1,24 +0,0 @@
1
- /*
2
- Copyright 2018 - 2022 The Alephium Authors
3
- This file is part of the alephium project.
4
-
5
- The library is free software: you can redistribute it and/or modify
6
- it under the terms of the GNU Lesser General Public License as published by
7
- the Free Software Foundation, either version 3 of the License, or
8
- (at your option) any later version.
9
-
10
- The library is distributed in the hope that it will be useful,
11
- but WITHOUT ANY WARRANTY; without even the implied warranty of
12
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
- GNU Lesser General Public License for more details.
14
-
15
- You should have received a copy of the GNU Lesser General Public License
16
- along with the library. If not, see <http://www.gnu.org/licenses/>.
17
- */
18
-
19
- const { rename } = require('fs')
20
-
21
- rename(process.argv[2], process.argv[3], function (error) {
22
- if (error) console.log(error)
23
- console.log(`Renamed ${process.argv[2]} to ${process.argv[3]}.`)
24
- })