You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

208 lines
5.8 KiB

5 years ago
5 years ago
  1. // Copyright (c) 2018 Jordi Baylina
  2. // License: LGPL-3.0+
  3. //
  4. const Web3Utils = require("web3-utils");
  5. class Contract {
  6. constructor() {
  7. this.code = [];
  8. this.labels = {};
  9. this.pendingLabels = {};
  10. }
  11. createTxData() {
  12. let C;
  13. // Check all labels are defined
  14. const pendingLabels = Object.keys(this.pendingLabels);
  15. if (pendingLabels.length>0) {
  16. throw new Error("Lables not defined: "+ pendingLabels.join(", "));
  17. }
  18. let setLoaderLength = 0;
  19. let genLoadedLength = -1;
  20. while (genLoadedLength!=setLoaderLength) {
  21. setLoaderLength = genLoadedLength;
  22. C = new module.exports();
  23. C.codesize();
  24. C.push(setLoaderLength);
  25. C.push(0);
  26. C.codecopy();
  27. C.push(this.code.length);
  28. C.push(0);
  29. C.return();
  30. genLoadedLength = C.code.length;
  31. }
  32. return Web3Utils.bytesToHex(C.code.concat(this.code));
  33. }
  34. stop() { this.code.push(0x00); }
  35. add() { this.code.push(0x01); }
  36. mul() { this.code.push(0x02); }
  37. sub() { this.code.push(0x03); }
  38. div() { this.code.push(0x04); }
  39. sdiv() { this.code.push(0x05); }
  40. mod() { this.code.push(0x06); }
  41. smod() { this.code.push(0x07); }
  42. addmod() { this.code.push(0x08); }
  43. mulmod() { this.code.push(0x09); }
  44. exp() { this.code.push(0x0a); }
  45. signextend() { this.code.push(0x0b); }
  46. lt() { this.code.push(0x10); }
  47. gt() { this.code.push(0x11); }
  48. slt() { this.code.push(0x12); }
  49. sgt() { this.code.push(0x13); }
  50. eq() { this.code.push(0x14); }
  51. iszero() { this.code.push(0x15); }
  52. and() { this.code.push(0x16); }
  53. or() { this.code.push(0x17); }
  54. shor() { this.code.push(0x18); }
  55. not() { this.code.push(0x19); }
  56. byte() { this.code.push(0x1a); }
  57. keccak() { this.code.push(0x20); }
  58. sha3() { this.code.push(0x20); } // alias
  59. address() { this.code.push(0x30); }
  60. balance() { this.code.push(0x31); }
  61. origin() { this.code.push(0x32); }
  62. caller() { this.code.push(0x33); }
  63. callvalue() { this.code.push(0x34); }
  64. calldataload() { this.code.push(0x35); }
  65. calldatasize() { this.code.push(0x36); }
  66. calldatacopy() { this.code.push(0x37); }
  67. codesize() { this.code.push(0x38); }
  68. codecopy() { this.code.push(0x39); }
  69. gasprice() { this.code.push(0x3a); }
  70. extcodesize() { this.code.push(0x3b); }
  71. extcodecopy() { this.code.push(0x3c); }
  72. returndatasize() { this.code.push(0x3d); }
  73. returndatacopy() { this.code.push(0x3e); }
  74. blockhash() { this.code.push(0x40); }
  75. coinbase() { this.code.push(0x41); }
  76. timestamp() { this.code.push(0x42); }
  77. number() { this.code.push(0x43); }
  78. difficulty() { this.code.push(0x44); }
  79. gaslimit() { this.code.push(0x45); }
  80. pop() { this.code.push(0x50); }
  81. mload() { this.code.push(0x51); }
  82. mstore() { this.code.push(0x52); }
  83. mstore8() { this.code.push(0x53); }
  84. sload() { this.code.push(0x54); }
  85. sstore() { this.code.push(0x55); }
  86. _pushLabel(label) {
  87. if (typeof this.labels[label] != "undefined") {
  88. this.push(this.labels[label]);
  89. } else {
  90. this.pendingLabels[label] = this.pendingLabels[label] || [];
  91. this.pendingLabels[label].push(this.code.length);
  92. this.push("0x000000");
  93. }
  94. }
  95. _fillLabel(label) {
  96. if (!this.pendingLabels[label]) return;
  97. let dst = this.labels[label];
  98. const dst3 = [dst >> 16, (dst >> 8) & 0xFF, dst & 0xFF];
  99. this.pendingLabels[label].forEach((p) => {
  100. for (let i=0; i<3; i++) {
  101. this.code[p+i+1] = dst3[i];
  102. }
  103. });
  104. delete this.pendingLabels[label];
  105. }
  106. jmp(label) {
  107. if (typeof label !== "undefined") {
  108. this._pushLabel(label);
  109. }
  110. this.code.push(0x56);
  111. }
  112. jmpi(label) {
  113. if (typeof label !== "undefined") {
  114. this._pushLabel(label);
  115. }
  116. this.code.push(0x57);
  117. }
  118. pc() { this.code.push(0x58); }
  119. msize() { this.code.push(0x59); }
  120. gas() { this.code.push(0x5a); }
  121. label(name) {
  122. if (typeof this.labels[name] != "undefined") {
  123. throw new Error("Label already defined");
  124. }
  125. this.labels[name] = this.code.length;
  126. this.code.push(0x5b);
  127. this._fillLabel(name);
  128. }
  129. push(data) {
  130. if (typeof data === "number") {
  131. let isNeg;
  132. if (data<0) {
  133. isNeg = true;
  134. data = -data;
  135. }
  136. data = data.toString(16);
  137. if (data.length % 2 == 1) data = "0" + data;
  138. data = "0x" + data;
  139. if (isNeg) data = "-"+data;
  140. }
  141. const d = Web3Utils.hexToBytes(Web3Utils.toHex(data));
  142. if (d.length == 0 || d.length > 32) {
  143. throw new Error("Assertion failed");
  144. }
  145. this.code = this.code.concat([0x5F + d.length], d);
  146. }
  147. dup(n) {
  148. if (n < 0 || n >= 16) {
  149. throw new Error("Assertion failed");
  150. }
  151. this.code.push(0x80 + n);
  152. }
  153. swap(n) {
  154. if (n < 1 || n > 16) {
  155. throw new Error("Assertion failed");
  156. }
  157. this.code.push(0x8f + n);
  158. }
  159. log0() { this.code.push(0xa0); }
  160. log1() { this.code.push(0xa1); }
  161. log2() { this.code.push(0xa2); }
  162. log3() { this.code.push(0xa3); }
  163. log4() { this.code.push(0xa4); }
  164. create() { this.code.push(0xf0); }
  165. call() { this.code.push(0xf1); }
  166. callcode() { this.code.push(0xf2); }
  167. return() { this.code.push(0xf3); }
  168. delegatecall() { this.code.push(0xf4); }
  169. staticcall() { this.code.push(0xfa); }
  170. revert() { this.code.push(0xfd); }
  171. invalid() { this.code.push(0xfe); }
  172. selfdestruct() { this.code.push(0xff); }
  173. }
  174. module.exports = Contract;