@msgboard/hardhat 0.0.1
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.
- package/README.md +77 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +67 -0
- package/dist/provider.d.ts +113 -0
- package/dist/provider.js +337 -0
- package/dist/tasks.d.ts +1 -0
- package/dist/tasks.js +298 -0
- package/dist/type-extensions.d.ts +17 -0
- package/dist/type-extensions.js +4 -0
- package/dist/types.d.ts +8 -0
- package/dist/types.js +2 -0
- package/package.json +66 -0
package/README.md
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# @pulsechain/hardhat-msgboard
|
|
2
|
+
|
|
3
|
+
Test your msgboard interfaces
|
|
4
|
+
|
|
5
|
+
[Hardhat](https://hardhat.org) plugin example.
|
|
6
|
+
|
|
7
|
+
## MsgBoard
|
|
8
|
+
|
|
9
|
+
MsgBoard allows for decentralized, public communication. Each msgboard instance may behave slightly differently quirks, but so long as the basic interface holds true, it can reliably push the ability to run software closer to the individual. One needs to tightly control which process is utilizing msgboard because it will block as it works through and eventually finds a valid hash.
|
|
10
|
+
|
|
11
|
+
## Installation
|
|
12
|
+
|
|
13
|
+
After installing nodejs (+23.6.1 with asdf recommended)
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npm install @pulsechain/hardhat-msgboard
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Import the plugin in your `hardhat.config.js`:
|
|
20
|
+
|
|
21
|
+
```js
|
|
22
|
+
require("@pulsechain/hardhat-msgboard");
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Or if you are using TypeScript, in your `hardhat.config.ts`:
|
|
26
|
+
|
|
27
|
+
```ts
|
|
28
|
+
import "@pulsechain/hardhat-msgboard";
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Tasks
|
|
32
|
+
|
|
33
|
+
`msgboard:status`
|
|
34
|
+
`msgboard:work`
|
|
35
|
+
`msgboard:send`
|
|
36
|
+
`msgboard:work:send`
|
|
37
|
+
|
|
38
|
+
```sh
|
|
39
|
+
> hardhat msgboard:status
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Environment extensions
|
|
43
|
+
|
|
44
|
+
<_A description of each extension to the Hardhat Runtime Environment_>
|
|
45
|
+
|
|
46
|
+
This plugin extends the Hardhat Runtime Environment by adding an `example` field
|
|
47
|
+
whose type is `ExampleHardhatRuntimeEnvironmentField`.
|
|
48
|
+
|
|
49
|
+
## Configuration
|
|
50
|
+
|
|
51
|
+
<_A description of each extension to the HardhatConfig or to its fields_>
|
|
52
|
+
|
|
53
|
+
This plugin extends the `HardhatUserConfig`'s `MsgBoardUserConfig` object with an optional `msgboard` field that is only applicable to the hardhat network.
|
|
54
|
+
|
|
55
|
+
This is an example of how to set it:
|
|
56
|
+
|
|
57
|
+
```ts
|
|
58
|
+
module.exports = {
|
|
59
|
+
msgboard: {
|
|
60
|
+
// only applicable to hardhat network
|
|
61
|
+
enabled: true,
|
|
62
|
+
workMultiplier: 1_000_000n,
|
|
63
|
+
workDivisor: 10_000n,
|
|
64
|
+
messageSizeLimit: 8n * 1024n,
|
|
65
|
+
boardCountLimit: 10_000n,
|
|
66
|
+
blockRangeLimit: 120n,
|
|
67
|
+
},
|
|
68
|
+
};
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## Usage
|
|
72
|
+
|
|
73
|
+
send messages to the msgboard and read from it
|
|
74
|
+
|
|
75
|
+
```ts
|
|
76
|
+
const msg = await hre.msgboard.doWork('0xcategory...', '0xdata...')
|
|
77
|
+
```
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
const config_1 = require("hardhat/config");
|
|
37
|
+
const plugins_1 = require("hardhat/plugins");
|
|
38
|
+
const msgboard = __importStar(require("@msgboard/sdk"));
|
|
39
|
+
const provider_1 = require("./provider");
|
|
40
|
+
// This import is needed to let the TypeScript compiler know that it should include your type
|
|
41
|
+
// extensions in your npm package's types file.
|
|
42
|
+
require("./type-extensions");
|
|
43
|
+
require("./tasks");
|
|
44
|
+
(0, config_1.extendConfig)((config, userConfig) => {
|
|
45
|
+
const userConf = userConfig;
|
|
46
|
+
const c = config;
|
|
47
|
+
c.msgboard = {
|
|
48
|
+
...provider_1.globalDefaultSettings,
|
|
49
|
+
...(userConf.msgboard ?? {}),
|
|
50
|
+
};
|
|
51
|
+
});
|
|
52
|
+
(0, config_1.extendEnvironment)((hre) => {
|
|
53
|
+
// We add a field to the Hardhat Runtime Environment here.
|
|
54
|
+
// We use lazyObject to avoid initializing things until they are actually
|
|
55
|
+
// needed.
|
|
56
|
+
hre.msgboard = (0, plugins_1.lazyObject)(() => {
|
|
57
|
+
return new msgboard.MsgBoardClient(msgboard.wrapLegacySend(hre.network.provider));
|
|
58
|
+
});
|
|
59
|
+
});
|
|
60
|
+
(0, config_1.extendProvider)((provider, config, network) => {
|
|
61
|
+
const isHardhatNetwork = network === 'hardhat';
|
|
62
|
+
const c = config;
|
|
63
|
+
const prov = new provider_1.MsgBoardProvider(provider, isHardhatNetwork);
|
|
64
|
+
prov.setNodeConstraints(c);
|
|
65
|
+
provider_1.providers.add(prov);
|
|
66
|
+
return prov;
|
|
67
|
+
});
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { ProviderWrapper } from 'hardhat/plugins';
|
|
2
|
+
import type { EIP1193Provider, RequestArguments } from 'hardhat/types';
|
|
3
|
+
import type { MsgBoardSettings } from './types';
|
|
4
|
+
export declare const globalDefaultSettings: MsgBoardSettings;
|
|
5
|
+
export declare const defaultSettings: () => {
|
|
6
|
+
enabled: boolean;
|
|
7
|
+
workMultiplier: bigint;
|
|
8
|
+
workDivisor: bigint;
|
|
9
|
+
messageSizeLimit: bigint;
|
|
10
|
+
boardCountLimit: bigint;
|
|
11
|
+
blockRangeLimit: bigint;
|
|
12
|
+
};
|
|
13
|
+
export declare class MsgBoardProvider extends ProviderWrapper {
|
|
14
|
+
protected readonly _wrappedProvider: EIP1193Provider;
|
|
15
|
+
protected readonly isHardhatNetwork: boolean;
|
|
16
|
+
private messages;
|
|
17
|
+
id: number;
|
|
18
|
+
private settings;
|
|
19
|
+
constructor(_wrappedProvider: EIP1193Provider, isHardhatNetwork: boolean);
|
|
20
|
+
/**
|
|
21
|
+
* Returns the default settings for a msgboard instance
|
|
22
|
+
* @returns The default settings for a msgboard instance
|
|
23
|
+
*/
|
|
24
|
+
static defaultSettings(): {
|
|
25
|
+
enabled: boolean;
|
|
26
|
+
workMultiplier: bigint;
|
|
27
|
+
workDivisor: bigint;
|
|
28
|
+
messageSizeLimit: bigint;
|
|
29
|
+
boardCountLimit: bigint;
|
|
30
|
+
blockRangeLimit: bigint;
|
|
31
|
+
};
|
|
32
|
+
/**
|
|
33
|
+
* Returns the status of the msgboard
|
|
34
|
+
* @returns The status object of this message board instance
|
|
35
|
+
*/
|
|
36
|
+
private status;
|
|
37
|
+
/**
|
|
38
|
+
* Sets the constraints for this message board instance
|
|
39
|
+
* @param constraints The constraints to set for this message board instance
|
|
40
|
+
*/
|
|
41
|
+
setNodeConstraints(constraints?: Partial<MsgBoardSettings>): Promise<void>;
|
|
42
|
+
/**
|
|
43
|
+
* Validates a message
|
|
44
|
+
* @param m The message to validate
|
|
45
|
+
* @returns The validated message and the produced hash
|
|
46
|
+
*/
|
|
47
|
+
private validateMessage;
|
|
48
|
+
/**
|
|
49
|
+
* Adds a message to the msgboard
|
|
50
|
+
* @param msg The rlp encoded message to add
|
|
51
|
+
* @returns The hash of the message
|
|
52
|
+
*/
|
|
53
|
+
private addMessage;
|
|
54
|
+
/**
|
|
55
|
+
* Adds a message to the msgboard in order
|
|
56
|
+
* @param latestBlockNumber The latest block number
|
|
57
|
+
* - to be passed to the removeStaleMessages method to prune old messages
|
|
58
|
+
* @param m The message to add
|
|
59
|
+
*/
|
|
60
|
+
private addOrderedMessage;
|
|
61
|
+
/**
|
|
62
|
+
* Removes stale messages from the msgboard
|
|
63
|
+
* @param latestBlockNumber The latest block number - used to prune old messages
|
|
64
|
+
*/
|
|
65
|
+
private removeStaleMessages;
|
|
66
|
+
/**
|
|
67
|
+
* Returns a message from the msgboard by hash
|
|
68
|
+
* @param hash The hash of the message to return
|
|
69
|
+
* @returns The message or null if it is not found
|
|
70
|
+
*/
|
|
71
|
+
private getMessage;
|
|
72
|
+
/**
|
|
73
|
+
* Returns the content of the msgboard
|
|
74
|
+
* @param filter The filter to apply to the content
|
|
75
|
+
* @returns The content of the msgboard
|
|
76
|
+
*/
|
|
77
|
+
private content;
|
|
78
|
+
/**
|
|
79
|
+
* Returns the categories of the msgboard
|
|
80
|
+
* @returns The categories of the msgboard
|
|
81
|
+
*/
|
|
82
|
+
private categories;
|
|
83
|
+
/**
|
|
84
|
+
* Handles a msgboard request
|
|
85
|
+
* @param args The request arguments
|
|
86
|
+
* @returns The result of the request
|
|
87
|
+
*/
|
|
88
|
+
private handleMsgboardRequest;
|
|
89
|
+
/**
|
|
90
|
+
* Emulates network latency by adding a XXms delay before and after the function call
|
|
91
|
+
* @param fn The function to execute
|
|
92
|
+
* @returns The result of the function
|
|
93
|
+
*/
|
|
94
|
+
private emulateNetworkLatency;
|
|
95
|
+
/**
|
|
96
|
+
* Handles a request to the msgboard, handling it locally if the network is hardhat
|
|
97
|
+
* @param args The request arguments
|
|
98
|
+
* @returns The result of the request
|
|
99
|
+
*/
|
|
100
|
+
request(args: RequestArguments): Promise<unknown>;
|
|
101
|
+
/**
|
|
102
|
+
* Resets the msgboard
|
|
103
|
+
*/
|
|
104
|
+
reset(): void;
|
|
105
|
+
destroy(): void;
|
|
106
|
+
}
|
|
107
|
+
export declare const providers: Set<MsgBoardProvider>;
|
|
108
|
+
/**
|
|
109
|
+
* Sets the constraints for all created msgboard providers
|
|
110
|
+
* @param constraints The settings to apply to all msgboard providers
|
|
111
|
+
*/
|
|
112
|
+
export declare const setNodeConstraints: (constraints: Partial<MsgBoardSettings>) => void;
|
|
113
|
+
export declare const reset: () => void;
|
package/dist/provider.js
ADDED
|
@@ -0,0 +1,337 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.reset = exports.setNodeConstraints = exports.providers = exports.MsgBoardProvider = exports.defaultSettings = exports.globalDefaultSettings = void 0;
|
|
37
|
+
const plugins_1 = require("hardhat/plugins");
|
|
38
|
+
const viem_1 = require("viem");
|
|
39
|
+
const msgboard = __importStar(require("@msgboard/sdk"));
|
|
40
|
+
exports.globalDefaultSettings = {
|
|
41
|
+
enabled: true,
|
|
42
|
+
workMultiplier: 10000n,
|
|
43
|
+
workDivisor: 1000000n,
|
|
44
|
+
messageSizeLimit: 1024n * 8n,
|
|
45
|
+
boardCountLimit: 10000n,
|
|
46
|
+
blockRangeLimit: 120n,
|
|
47
|
+
};
|
|
48
|
+
const defaultSettings = () => ({
|
|
49
|
+
...exports.globalDefaultSettings,
|
|
50
|
+
});
|
|
51
|
+
exports.defaultSettings = defaultSettings;
|
|
52
|
+
/**
|
|
53
|
+
* Waits for a given number of milliseconds
|
|
54
|
+
* @param ms The number of milliseconds to wait
|
|
55
|
+
*/
|
|
56
|
+
const wait = async (ms) => {
|
|
57
|
+
await new Promise((resolve) => setTimeout(resolve, ms));
|
|
58
|
+
};
|
|
59
|
+
const isNil = (value) => value === null || value === undefined;
|
|
60
|
+
let id = 0;
|
|
61
|
+
class MsgBoardProvider extends plugins_1.ProviderWrapper {
|
|
62
|
+
constructor(_wrappedProvider, isHardhatNetwork) {
|
|
63
|
+
super(_wrappedProvider);
|
|
64
|
+
this._wrappedProvider = _wrappedProvider;
|
|
65
|
+
this.isHardhatNetwork = isHardhatNetwork;
|
|
66
|
+
this.messages = [];
|
|
67
|
+
this.settings = {
|
|
68
|
+
...exports.globalDefaultSettings,
|
|
69
|
+
};
|
|
70
|
+
this.id = ++id;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Returns the default settings for a msgboard instance
|
|
74
|
+
* @returns The default settings for a msgboard instance
|
|
75
|
+
*/
|
|
76
|
+
static defaultSettings() {
|
|
77
|
+
return {
|
|
78
|
+
...exports.globalDefaultSettings,
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Returns the status of the msgboard
|
|
83
|
+
* @returns The status object of this message board instance
|
|
84
|
+
*/
|
|
85
|
+
status() {
|
|
86
|
+
return {
|
|
87
|
+
enabled: this.settings.enabled,
|
|
88
|
+
workMultiplier: (0, viem_1.numberToHex)(this.settings.workMultiplier),
|
|
89
|
+
workDivisor: (0, viem_1.numberToHex)(this.settings.workDivisor),
|
|
90
|
+
count: (0, viem_1.numberToHex)(this.messages.length),
|
|
91
|
+
size: (0, viem_1.numberToHex)(this.messages.reduce((acc, msg) => acc + msg.data.length, 0)),
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Sets the constraints for this message board instance
|
|
96
|
+
* @param constraints The constraints to set for this message board instance
|
|
97
|
+
*/
|
|
98
|
+
async setNodeConstraints(constraints = {}) {
|
|
99
|
+
this.settings = { ...this.settings, ...constraints };
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Validates a message
|
|
103
|
+
* @param m The message to validate
|
|
104
|
+
* @returns The validated message and the produced hash
|
|
105
|
+
*/
|
|
106
|
+
async validateMessage(m) {
|
|
107
|
+
// these errors may be out of order compared to the current node implementation
|
|
108
|
+
const bytes = (0, viem_1.hexToBytes)(m.data);
|
|
109
|
+
if (bytes.length > this.settings.messageSizeLimit) {
|
|
110
|
+
throw new Error('msgboard: message too large');
|
|
111
|
+
}
|
|
112
|
+
if (m.version !== 1) {
|
|
113
|
+
throw new Error('powmsg: invalid version');
|
|
114
|
+
}
|
|
115
|
+
if ((0, viem_1.hexToBytes)(m.category).length !== 32) {
|
|
116
|
+
throw new Error('powmsg: invalid category');
|
|
117
|
+
}
|
|
118
|
+
if (m.blockHash === viem_1.zeroHash) {
|
|
119
|
+
throw new Error('powmsg: invalid block hash');
|
|
120
|
+
}
|
|
121
|
+
if (m.nonce === 0n) {
|
|
122
|
+
throw new Error('powmsg: invalid nonce');
|
|
123
|
+
}
|
|
124
|
+
if (m.workDivisor === 0n || m.workMultiplier === 0n) {
|
|
125
|
+
throw new Error('powmsg: invalid difficulty');
|
|
126
|
+
}
|
|
127
|
+
const difficultyFactors = {
|
|
128
|
+
workMultiplier: this.settings.workMultiplier,
|
|
129
|
+
workDivisor: this.settings.workDivisor,
|
|
130
|
+
};
|
|
131
|
+
if (m.category === viem_1.zeroHash && m.data.length !== 0) {
|
|
132
|
+
throw new Error('powmsg: invalid data');
|
|
133
|
+
}
|
|
134
|
+
const difficulty = msgboard.difficulty(difficultyFactors, bytes.length);
|
|
135
|
+
const hash = msgboard.checkWork(m, difficulty);
|
|
136
|
+
if (!hash) {
|
|
137
|
+
if (difficultyFactors.workMultiplier !== this.settings.workMultiplier ||
|
|
138
|
+
difficultyFactors.workDivisor !== this.settings.workDivisor) {
|
|
139
|
+
console.log(this.id, difficultyFactors, m);
|
|
140
|
+
}
|
|
141
|
+
throw new Error('powmsg: invalid work');
|
|
142
|
+
}
|
|
143
|
+
const block = (await this._wrappedProvider.request({
|
|
144
|
+
method: 'eth_getBlockByHash',
|
|
145
|
+
params: [m.blockHash, false],
|
|
146
|
+
}));
|
|
147
|
+
if (!block) {
|
|
148
|
+
throw new Error('powmsg: invalid block hash');
|
|
149
|
+
}
|
|
150
|
+
return { hash, block };
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Adds a message to the msgboard
|
|
154
|
+
* @param msg The rlp encoded message to add
|
|
155
|
+
* @returns The hash of the message
|
|
156
|
+
*/
|
|
157
|
+
async addMessage(msg) {
|
|
158
|
+
const m = msgboard.fromRLP(msg);
|
|
159
|
+
const { hash, block: workBlock } = await this.validateMessage(m);
|
|
160
|
+
const latestBlock = (await this._wrappedProvider.request({
|
|
161
|
+
method: 'eth_getBlockByNumber',
|
|
162
|
+
params: ['latest', false],
|
|
163
|
+
}));
|
|
164
|
+
const latestBlockNumber = BigInt(latestBlock.number);
|
|
165
|
+
const workBlockNumber = BigInt(workBlock.number);
|
|
166
|
+
if (
|
|
167
|
+
// could swap out for bignumber.js to avoid precision issues
|
|
168
|
+
Number(m.workMultiplier) / Number(m.workDivisor) >
|
|
169
|
+
Number(this.settings.workMultiplier) / Number(this.settings.workDivisor)) {
|
|
170
|
+
throw new Error('msgboard: message work too easy');
|
|
171
|
+
}
|
|
172
|
+
if (workBlockNumber < latestBlockNumber - this.settings.blockRangeLimit) {
|
|
173
|
+
throw new Error('msgboard: message block too old');
|
|
174
|
+
}
|
|
175
|
+
this.addOrderedMessage(latestBlockNumber, {
|
|
176
|
+
...m,
|
|
177
|
+
blockNumber: workBlockNumber,
|
|
178
|
+
hash,
|
|
179
|
+
});
|
|
180
|
+
return hash;
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* Adds a message to the msgboard in order
|
|
184
|
+
* @param latestBlockNumber The latest block number
|
|
185
|
+
* - to be passed to the removeStaleMessages method to prune old messages
|
|
186
|
+
* @param m The message to add
|
|
187
|
+
*/
|
|
188
|
+
addOrderedMessage(latestBlockNumber, m) {
|
|
189
|
+
const index = this.messages.findIndex((msg) => {
|
|
190
|
+
return msg.blockNumber > m.blockNumber;
|
|
191
|
+
});
|
|
192
|
+
if (index === -1) {
|
|
193
|
+
this.messages.push(m);
|
|
194
|
+
}
|
|
195
|
+
else {
|
|
196
|
+
this.messages.splice(index, 0, m);
|
|
197
|
+
}
|
|
198
|
+
this.removeStaleMessages(latestBlockNumber);
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* Removes stale messages from the msgboard
|
|
202
|
+
* @param latestBlockNumber The latest block number - used to prune old messages
|
|
203
|
+
*/
|
|
204
|
+
removeStaleMessages(latestBlockNumber) {
|
|
205
|
+
// remove messages that are too old
|
|
206
|
+
const finalValidBlockNumber = latestBlockNumber - this.settings.blockRangeLimit;
|
|
207
|
+
const index = this.messages.findIndex((msg) => {
|
|
208
|
+
return msg.blockNumber >= finalValidBlockNumber;
|
|
209
|
+
});
|
|
210
|
+
if (index !== -1) {
|
|
211
|
+
this.messages.splice(0, index);
|
|
212
|
+
}
|
|
213
|
+
// remove messages when the board count limit is exceeded
|
|
214
|
+
if (BigInt(this.messages.length) > this.settings.boardCountLimit) {
|
|
215
|
+
this.messages.splice(0, this.messages.length - Number(this.settings.boardCountLimit));
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* Returns a message from the msgboard by hash
|
|
220
|
+
* @param hash The hash of the message to return
|
|
221
|
+
* @returns The message or null if it is not found
|
|
222
|
+
*/
|
|
223
|
+
getMessage(hash) {
|
|
224
|
+
const msg = this.messages.find((msg) => msg.hash === hash) ?? null;
|
|
225
|
+
return !msg ? null : msgboard.toRPCMessage(msg);
|
|
226
|
+
}
|
|
227
|
+
/**
|
|
228
|
+
* Returns the content of the msgboard
|
|
229
|
+
* @param filter The filter to apply to the content
|
|
230
|
+
* @returns The content of the msgboard
|
|
231
|
+
*/
|
|
232
|
+
content(filter = {}) {
|
|
233
|
+
return this.messages.reduce((content, msg) => {
|
|
234
|
+
if (filter.category && msg.category !== filter.category) {
|
|
235
|
+
// message category does not match filter category
|
|
236
|
+
return content;
|
|
237
|
+
}
|
|
238
|
+
if (!isNil(filter.fromBlock) && msg.blockNumber < filter.fromBlock) {
|
|
239
|
+
// message block number is below lower bound block number
|
|
240
|
+
return content;
|
|
241
|
+
}
|
|
242
|
+
if (!isNil(filter.toBlock) && msg.blockNumber > filter.toBlock) {
|
|
243
|
+
// message block number is above upper bound block number
|
|
244
|
+
return content;
|
|
245
|
+
}
|
|
246
|
+
if (!content[msg.category]) {
|
|
247
|
+
content[msg.category] = [];
|
|
248
|
+
}
|
|
249
|
+
content[msg.category].push(msgboard.toRPCMessage(msg));
|
|
250
|
+
return content;
|
|
251
|
+
}, {});
|
|
252
|
+
}
|
|
253
|
+
/**
|
|
254
|
+
* Returns the categories of the msgboard
|
|
255
|
+
* @returns The categories of the msgboard
|
|
256
|
+
*/
|
|
257
|
+
categories() {
|
|
258
|
+
return Array.from(new Set(this.messages.map((msg) => msg.category)));
|
|
259
|
+
}
|
|
260
|
+
/**
|
|
261
|
+
* Handles a msgboard request
|
|
262
|
+
* @param args The request arguments
|
|
263
|
+
* @returns The result of the request
|
|
264
|
+
*/
|
|
265
|
+
handleMsgboardRequest(args) {
|
|
266
|
+
if (args.method === 'msgboard_status') {
|
|
267
|
+
return this.status(...args.params);
|
|
268
|
+
}
|
|
269
|
+
if (args.method === 'msgboard_addMessage') {
|
|
270
|
+
return this.addMessage(...args.params);
|
|
271
|
+
}
|
|
272
|
+
if (args.method === 'msgboard_getMessage') {
|
|
273
|
+
return this.getMessage(...args.params);
|
|
274
|
+
}
|
|
275
|
+
if (args.method === 'msgboard_content') {
|
|
276
|
+
return this.content(...args.params);
|
|
277
|
+
}
|
|
278
|
+
if (args.method === 'msgboard_categories') {
|
|
279
|
+
return this.categories(...args.params);
|
|
280
|
+
}
|
|
281
|
+
// only for local hardhat network - does not exist on production networks
|
|
282
|
+
if (args.method === 'msgboard_reset') {
|
|
283
|
+
return this.reset(...args.params);
|
|
284
|
+
}
|
|
285
|
+
throw new Error('msgboard: unknown method');
|
|
286
|
+
}
|
|
287
|
+
/**
|
|
288
|
+
* Emulates network latency by adding a XXms delay before and after the function call
|
|
289
|
+
* @param fn The function to execute
|
|
290
|
+
* @returns The result of the function
|
|
291
|
+
*/
|
|
292
|
+
async emulateNetworkLatency(fn) {
|
|
293
|
+
await wait(2);
|
|
294
|
+
const result = await fn();
|
|
295
|
+
await wait(2);
|
|
296
|
+
return result;
|
|
297
|
+
}
|
|
298
|
+
/**
|
|
299
|
+
* Handles a request to the msgboard, handling it locally if the network is hardhat
|
|
300
|
+
* @param args The request arguments
|
|
301
|
+
* @returns The result of the request
|
|
302
|
+
*/
|
|
303
|
+
async request(args) {
|
|
304
|
+
if (this.isHardhatNetwork && args.method.startsWith('msgboard_')) {
|
|
305
|
+
return this.emulateNetworkLatency(() => this.handleMsgboardRequest(args));
|
|
306
|
+
}
|
|
307
|
+
return this._wrappedProvider.request(args);
|
|
308
|
+
}
|
|
309
|
+
/**
|
|
310
|
+
* Resets the msgboard
|
|
311
|
+
*/
|
|
312
|
+
reset() {
|
|
313
|
+
this.messages = [];
|
|
314
|
+
}
|
|
315
|
+
destroy() {
|
|
316
|
+
this.reset();
|
|
317
|
+
exports.providers.delete(this);
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
exports.MsgBoardProvider = MsgBoardProvider;
|
|
321
|
+
exports.providers = new Set();
|
|
322
|
+
/**
|
|
323
|
+
* Sets the constraints for all created msgboard providers
|
|
324
|
+
* @param constraints The settings to apply to all msgboard providers
|
|
325
|
+
*/
|
|
326
|
+
const setNodeConstraints = (constraints) => {
|
|
327
|
+
Array.from(exports.providers).forEach((p) => {
|
|
328
|
+
p.setNodeConstraints(constraints);
|
|
329
|
+
});
|
|
330
|
+
};
|
|
331
|
+
exports.setNodeConstraints = setNodeConstraints;
|
|
332
|
+
const reset = () => {
|
|
333
|
+
Array.from(exports.providers).forEach((p) => {
|
|
334
|
+
p.reset();
|
|
335
|
+
});
|
|
336
|
+
};
|
|
337
|
+
exports.reset = reset;
|
package/dist/tasks.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/tasks.js
ADDED
|
@@ -0,0 +1,298 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
const config_1 = require("hardhat/config");
|
|
37
|
+
const viem_1 = require("viem");
|
|
38
|
+
const msgboard = __importStar(require("@msgboard/sdk"));
|
|
39
|
+
const argumentTypes = __importStar(require("hardhat/internal/core/params/argumentTypes"));
|
|
40
|
+
const options = {
|
|
41
|
+
// params
|
|
42
|
+
category: ['category', 'the category of the work', '', argumentTypes.string],
|
|
43
|
+
data: ['data', 'the data of the work', '', argumentTypes.string],
|
|
44
|
+
rlp: ['rlp', 'the rlp of the message', '', argumentTypes.string],
|
|
45
|
+
messageJson: ['message', 'the decoded message to send', 'null', argumentTypes.string],
|
|
46
|
+
hash: ['hash', 'the hash of the message', '', argumentTypes.string],
|
|
47
|
+
// optional params
|
|
48
|
+
board: ['board', 'the board to use (programmatic only - no CLI)', null, argumentTypes.any],
|
|
49
|
+
message: ['message', 'the decoded message to send', null, argumentTypes.any],
|
|
50
|
+
fromBlock: ['fromBlock', 'the block number to start from', null, argumentTypes.bigint],
|
|
51
|
+
toBlock: ['toBlock', 'the block number to end at', null, argumentTypes.bigint],
|
|
52
|
+
size: ['size', 'the number of bytes to calculate the difficulty for', 0, argumentTypes.int],
|
|
53
|
+
workMultiplier: ['workMultiplier', 'the work multiplier', 0n, argumentTypes.bigint],
|
|
54
|
+
workDivisor: ['workDivisor', 'the work divisor', 0n, argumentTypes.bigint],
|
|
55
|
+
// flags
|
|
56
|
+
log: ['log', 'log the status'],
|
|
57
|
+
};
|
|
58
|
+
const descriptions = {
|
|
59
|
+
status: 'Gets the status of the msgboard',
|
|
60
|
+
work: 'Produce a proof of work for a given category and data',
|
|
61
|
+
send: 'Send an RLP encoded message to the msgboard',
|
|
62
|
+
sendDecoded: 'Send a decoded message to the msgboard',
|
|
63
|
+
workSend: 'Produce and send a proof of work to the msgboard',
|
|
64
|
+
getMessage: 'Get a message from the msgboard',
|
|
65
|
+
reset: 'Reset the msgboard',
|
|
66
|
+
categories: 'Get the categories of the msgboard',
|
|
67
|
+
content: 'Get the content of the msgboard',
|
|
68
|
+
getDifficulty: 'Calculate the difficulty for a given number of bytes',
|
|
69
|
+
};
|
|
70
|
+
const taskNames = {
|
|
71
|
+
status: 'status',
|
|
72
|
+
work: 'work',
|
|
73
|
+
send: 'send',
|
|
74
|
+
sendDecoded: 'send-decoded',
|
|
75
|
+
workSend: 'work:send',
|
|
76
|
+
getMessage: 'get-message',
|
|
77
|
+
reset: 'reset',
|
|
78
|
+
categories: 'categories',
|
|
79
|
+
content: 'content',
|
|
80
|
+
getDifficulty: 'get-difficulty',
|
|
81
|
+
};
|
|
82
|
+
const globalTaskName = (taskName) => `${scopeKey}:${taskName}`;
|
|
83
|
+
const scopeKey = 'msgboard';
|
|
84
|
+
const scoped = (0, config_1.scope)(scopeKey, 'A scope for msgboard tasks');
|
|
85
|
+
const omitNull = (obj) => Object.fromEntries(Object.entries(obj).filter(([_, v]) => v !== null && v !== undefined));
|
|
86
|
+
scoped.subtask(globalTaskName(taskNames.status))
|
|
87
|
+
.setDescription(descriptions.status)
|
|
88
|
+
.addOptionalParam(...options.board)
|
|
89
|
+
.addFlag(...options.log)
|
|
90
|
+
.setAction(async (taskArgs, hre) => {
|
|
91
|
+
const board = (taskArgs.board ?? hre.msgboard);
|
|
92
|
+
const status = await board.status();
|
|
93
|
+
if (taskArgs.log) {
|
|
94
|
+
board.log('status: %o', {
|
|
95
|
+
enabled: status.enabled,
|
|
96
|
+
workMultiplier: BigInt(status.workMultiplier),
|
|
97
|
+
workDivisor: BigInt(status.workDivisor),
|
|
98
|
+
count: BigInt(status.count),
|
|
99
|
+
size: BigInt(status.size),
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
return status;
|
|
103
|
+
});
|
|
104
|
+
scoped.task(taskNames.status)
|
|
105
|
+
.setDescription(descriptions.status)
|
|
106
|
+
.addFlag(...options.log)
|
|
107
|
+
.setAction(async (taskArgs, hre) => {
|
|
108
|
+
return hre.run({
|
|
109
|
+
scope: scopeKey,
|
|
110
|
+
task: globalTaskName(taskNames.status),
|
|
111
|
+
}, omitNull(taskArgs));
|
|
112
|
+
});
|
|
113
|
+
scoped.subtask(globalTaskName(taskNames.work))
|
|
114
|
+
.setDescription(descriptions.work)
|
|
115
|
+
.addParam(...options.category)
|
|
116
|
+
.addParam(...options.data)
|
|
117
|
+
.addFlag(...options.log)
|
|
118
|
+
.addOptionalParam(...options.board)
|
|
119
|
+
.setAction(async (taskArgs, hre) => {
|
|
120
|
+
const { category, data, board: b, log } = taskArgs;
|
|
121
|
+
const d = msgboard.encodeData(data);
|
|
122
|
+
const c = (0, viem_1.isHex)(category) ? (0, viem_1.toHex)(category, { size: 32 }) : (0, viem_1.keccak256)((0, viem_1.stringToBytes)(category));
|
|
123
|
+
const board = (b ?? hre.msgboard);
|
|
124
|
+
const work = await board.doPoW(c, d);
|
|
125
|
+
if (log) {
|
|
126
|
+
board.log('work: %o', work);
|
|
127
|
+
}
|
|
128
|
+
return work;
|
|
129
|
+
});
|
|
130
|
+
scoped.task(taskNames.work)
|
|
131
|
+
.setDescription(descriptions.work)
|
|
132
|
+
.setAction(async (taskArgs, hre) => {
|
|
133
|
+
return hre.run({
|
|
134
|
+
scope: scopeKey,
|
|
135
|
+
task: globalTaskName(taskNames.work),
|
|
136
|
+
}, omitNull(taskArgs));
|
|
137
|
+
});
|
|
138
|
+
scoped.subtask(globalTaskName(taskNames.send))
|
|
139
|
+
.setDescription(descriptions.send)
|
|
140
|
+
.addParam(...options.rlp)
|
|
141
|
+
.addOptionalParam(...options.board)
|
|
142
|
+
.setAction(async (taskArgs, hre) => {
|
|
143
|
+
const { rlp, board: b } = taskArgs;
|
|
144
|
+
const board = (b ?? hre.msgboard);
|
|
145
|
+
return await board.addMessage(rlp);
|
|
146
|
+
});
|
|
147
|
+
scoped.task(taskNames.send)
|
|
148
|
+
.setDescription(descriptions.send)
|
|
149
|
+
.setAction(async (taskArgs, hre) => {
|
|
150
|
+
return hre.run({
|
|
151
|
+
scope: scopeKey,
|
|
152
|
+
task: globalTaskName(taskNames.send),
|
|
153
|
+
}, omitNull(taskArgs));
|
|
154
|
+
});
|
|
155
|
+
scoped.subtask(globalTaskName(taskNames.sendDecoded))
|
|
156
|
+
.setDescription(descriptions.sendDecoded)
|
|
157
|
+
.addParam(...options.message)
|
|
158
|
+
.addOptionalParam(...options.board)
|
|
159
|
+
.setAction(async (taskArgs, hre) => {
|
|
160
|
+
const { message, board: b } = taskArgs;
|
|
161
|
+
return await hre.run({
|
|
162
|
+
scope: scopeKey,
|
|
163
|
+
task: globalTaskName(taskNames.send),
|
|
164
|
+
}, {
|
|
165
|
+
rlp: msgboard.toRLP(message),
|
|
166
|
+
board: b,
|
|
167
|
+
});
|
|
168
|
+
});
|
|
169
|
+
scoped.task(taskNames.sendDecoded)
|
|
170
|
+
.setDescription(descriptions.sendDecoded)
|
|
171
|
+
.setAction(async (taskArgs, hre) => {
|
|
172
|
+
return hre.run({
|
|
173
|
+
scope: scopeKey,
|
|
174
|
+
task: globalTaskName(taskNames.sendDecoded),
|
|
175
|
+
}, {
|
|
176
|
+
...taskArgs,
|
|
177
|
+
message: JSON.parse(taskArgs.message),
|
|
178
|
+
});
|
|
179
|
+
});
|
|
180
|
+
scoped.subtask(globalTaskName(taskNames.workSend))
|
|
181
|
+
.setDescription(descriptions.workSend)
|
|
182
|
+
.addParam(...options.category)
|
|
183
|
+
.addParam(...options.data)
|
|
184
|
+
.addOptionalParam(...options.board)
|
|
185
|
+
.addFlag(...options.log)
|
|
186
|
+
.setAction(async (taskArgs, hre) => {
|
|
187
|
+
const board = (taskArgs.board ?? hre.msgboard);
|
|
188
|
+
const work = (await hre.run({
|
|
189
|
+
scope: scopeKey,
|
|
190
|
+
task: globalTaskName(taskNames.work),
|
|
191
|
+
}, {
|
|
192
|
+
...taskArgs,
|
|
193
|
+
board,
|
|
194
|
+
}));
|
|
195
|
+
return await hre.run({
|
|
196
|
+
scope: scopeKey,
|
|
197
|
+
task: globalTaskName(taskNames.sendDecoded),
|
|
198
|
+
}, {
|
|
199
|
+
message: work.message,
|
|
200
|
+
board,
|
|
201
|
+
});
|
|
202
|
+
});
|
|
203
|
+
scoped.task(taskNames.workSend)
|
|
204
|
+
.setDescription(descriptions.workSend)
|
|
205
|
+
.addFlag(...options.log)
|
|
206
|
+
.addParam(...options.category)
|
|
207
|
+
.addParam(...options.data)
|
|
208
|
+
.setAction(async (taskArgs, hre) => {
|
|
209
|
+
return hre.run({
|
|
210
|
+
scope: scopeKey,
|
|
211
|
+
task: globalTaskName(taskNames.workSend),
|
|
212
|
+
}, omitNull(taskArgs));
|
|
213
|
+
});
|
|
214
|
+
scoped.subtask(globalTaskName(taskNames.getMessage))
|
|
215
|
+
.setDescription(descriptions.getMessage)
|
|
216
|
+
.addParam(...options.hash)
|
|
217
|
+
.addOptionalParam(...options.board)
|
|
218
|
+
.setAction(async (taskArgs, hre) => {
|
|
219
|
+
const { hash, board: b } = taskArgs;
|
|
220
|
+
const board = (b ?? hre.msgboard);
|
|
221
|
+
return await board.getMessage(hash);
|
|
222
|
+
});
|
|
223
|
+
scoped.task(taskNames.getMessage)
|
|
224
|
+
.setDescription(descriptions.getMessage)
|
|
225
|
+
.addParam(...options.hash)
|
|
226
|
+
.setAction(async (taskArgs, hre) => {
|
|
227
|
+
return hre.run({
|
|
228
|
+
scope: scopeKey,
|
|
229
|
+
task: globalTaskName(taskNames.getMessage),
|
|
230
|
+
}, omitNull(taskArgs));
|
|
231
|
+
});
|
|
232
|
+
scoped.task(taskNames.reset)
|
|
233
|
+
.setDescription(descriptions.reset)
|
|
234
|
+
.setAction(async (_taskArgs, hre) => {
|
|
235
|
+
if (hre.network.name !== 'hardhat')
|
|
236
|
+
return;
|
|
237
|
+
await hre.network.provider.send('msgboard_reset', []);
|
|
238
|
+
});
|
|
239
|
+
scoped.task('categories')
|
|
240
|
+
.setDescription('Get the categories of the msgboard')
|
|
241
|
+
.setAction(async (_taskArgs, hre) => {
|
|
242
|
+
return await hre.network.provider.send('msgboard_categories', []);
|
|
243
|
+
});
|
|
244
|
+
scoped.subtask(globalTaskName(taskNames.content))
|
|
245
|
+
.setDescription(descriptions.content)
|
|
246
|
+
.addOptionalParam(...options.board)
|
|
247
|
+
.addOptionalParam(...options.category)
|
|
248
|
+
.addOptionalParam(...options.fromBlock)
|
|
249
|
+
.addOptionalParam(...options.toBlock)
|
|
250
|
+
.setAction(async (taskArgs, hre) => {
|
|
251
|
+
const { board: b, category, fromBlock, toBlock } = taskArgs;
|
|
252
|
+
const board = (b ?? hre.msgboard);
|
|
253
|
+
return await board.content({ category, fromBlock, toBlock });
|
|
254
|
+
});
|
|
255
|
+
scoped.task(taskNames.content)
|
|
256
|
+
.setDescription(descriptions.content)
|
|
257
|
+
.addOptionalParam(...options.category)
|
|
258
|
+
.addOptionalParam(...options.fromBlock)
|
|
259
|
+
.addOptionalParam(...options.toBlock)
|
|
260
|
+
.setAction(async (taskArgs, hre) => {
|
|
261
|
+
return hre.run({
|
|
262
|
+
scope: scopeKey,
|
|
263
|
+
task: globalTaskName(taskNames.content),
|
|
264
|
+
}, omitNull(taskArgs));
|
|
265
|
+
});
|
|
266
|
+
scoped.subtask(globalTaskName(taskNames.getDifficulty))
|
|
267
|
+
.setDescription(descriptions.getDifficulty)
|
|
268
|
+
.addOptionalParam(...options.data)
|
|
269
|
+
.addOptionalParam(...options.size)
|
|
270
|
+
.addOptionalParam(...options.workMultiplier)
|
|
271
|
+
.addOptionalParam(...options.workDivisor)
|
|
272
|
+
.addOptionalParam(...options.board)
|
|
273
|
+
.setAction(async (taskArgs, hre) => {
|
|
274
|
+
const { size, data, board: b, workMultiplier, workDivisor } = taskArgs;
|
|
275
|
+
const board = (b ?? hre.msgboard);
|
|
276
|
+
if (workMultiplier && workDivisor) {
|
|
277
|
+
board.setDifficultyFactors(workMultiplier, workDivisor);
|
|
278
|
+
}
|
|
279
|
+
else {
|
|
280
|
+
const status = await board.status().catch(() => null);
|
|
281
|
+
if (status)
|
|
282
|
+
board.setDifficultyFactors(BigInt(status.workMultiplier), BigInt(status.workDivisor));
|
|
283
|
+
}
|
|
284
|
+
const d = data ?? `0x${new Array(size * 2).fill(0).join('')}`;
|
|
285
|
+
return board.getDifficulty(d);
|
|
286
|
+
});
|
|
287
|
+
scoped.task(taskNames.getDifficulty)
|
|
288
|
+
.setDescription(descriptions.getDifficulty)
|
|
289
|
+
.addOptionalParam(...options.size)
|
|
290
|
+
.addOptionalParam(...options.data)
|
|
291
|
+
.addOptionalParam(...options.workMultiplier)
|
|
292
|
+
.addOptionalParam(...options.workDivisor)
|
|
293
|
+
.setAction(async (taskArgs, hre) => {
|
|
294
|
+
return hre.run({
|
|
295
|
+
scope: scopeKey,
|
|
296
|
+
task: globalTaskName(taskNames.getDifficulty),
|
|
297
|
+
}, omitNull(taskArgs));
|
|
298
|
+
});
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import 'hardhat/types/config';
|
|
2
|
+
import 'hardhat/types/runtime';
|
|
3
|
+
import type { MsgBoardClient } from '@msgboard/sdk';
|
|
4
|
+
import type { MsgBoardSettings } from './types';
|
|
5
|
+
declare module 'hardhat/types/config' {
|
|
6
|
+
interface MsgBoardUserConfig {
|
|
7
|
+
msgboard?: Partial<MsgBoardSettings>;
|
|
8
|
+
}
|
|
9
|
+
interface MsgBoardConfig {
|
|
10
|
+
msgboard: MsgBoardSettings;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
declare module 'hardhat/types/runtime' {
|
|
14
|
+
interface HardhatRuntimeEnvironment {
|
|
15
|
+
msgboard: MsgBoardClient;
|
|
16
|
+
}
|
|
17
|
+
}
|
package/dist/types.d.ts
ADDED
package/dist/types.js
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@msgboard/hardhat",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "Hardhat plugin for MsgBoard",
|
|
5
|
+
"repository": "github:valve-tech/msgboard",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"publishConfig": {
|
|
8
|
+
"access": "public"
|
|
9
|
+
},
|
|
10
|
+
"main": "dist/index.js",
|
|
11
|
+
"types": "dist/index.d.ts",
|
|
12
|
+
"commonjs": "dist/index.js",
|
|
13
|
+
"exports": {
|
|
14
|
+
".": {
|
|
15
|
+
"types": "./dist/index.d.ts",
|
|
16
|
+
"require": "./dist/index.js",
|
|
17
|
+
"import": "./dist/index.js",
|
|
18
|
+
"default": "./dist/index.js"
|
|
19
|
+
},
|
|
20
|
+
"./provider": {
|
|
21
|
+
"types": "./dist/provider.d.ts",
|
|
22
|
+
"require": "./dist/provider.js",
|
|
23
|
+
"import": "./dist/provider.js",
|
|
24
|
+
"default": "./dist/provider.js"
|
|
25
|
+
},
|
|
26
|
+
"./types": {
|
|
27
|
+
"types": "./dist/types.d.ts",
|
|
28
|
+
"require": "./dist/types.js",
|
|
29
|
+
"import": "./dist/types.js",
|
|
30
|
+
"default": "./dist/types.js"
|
|
31
|
+
},
|
|
32
|
+
"./tasks": {
|
|
33
|
+
"types": "./dist/tasks.d.ts",
|
|
34
|
+
"require": "./dist/tasks.js",
|
|
35
|
+
"import": "./dist/tasks.js",
|
|
36
|
+
"default": "./dist/tasks.js"
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
"files": [
|
|
40
|
+
"dist"
|
|
41
|
+
],
|
|
42
|
+
"devDependencies": {
|
|
43
|
+
"@nomicfoundation/hardhat-network-helpers": "^1.0.8",
|
|
44
|
+
"hardhat": "^2.16.1",
|
|
45
|
+
"nyc": "^17.1.0",
|
|
46
|
+
"solidity-coverage": "^0.8.15",
|
|
47
|
+
"tsx": "^4.19.3",
|
|
48
|
+
"viem": "^2.28.0",
|
|
49
|
+
"vitest": "^3.1.2"
|
|
50
|
+
},
|
|
51
|
+
"scripts": {
|
|
52
|
+
"prebuild": "node -e \"require('fs').rmSync('dist',{recursive:true,force:true})\"",
|
|
53
|
+
"build": "npm run compile",
|
|
54
|
+
"print": "hardhat help",
|
|
55
|
+
"watch": "npm run compile:watch",
|
|
56
|
+
"compile": "tsc && hardhat compile",
|
|
57
|
+
"compile:watch": "as-soon -w contracts npm run compile",
|
|
58
|
+
"test": "vitest",
|
|
59
|
+
"coverage": "hardhat compile-for-coverage && vitest run --coverage && hardhat compile",
|
|
60
|
+
"coverage:compile:watch": "as-soon -w contracts hardhat compile-for-coverage",
|
|
61
|
+
"coverage:watch": "hardhat compile-for-coverage && vitest --coverage"
|
|
62
|
+
},
|
|
63
|
+
"dependencies": {
|
|
64
|
+
"@msgboard/sdk": "^0.0.28"
|
|
65
|
+
}
|
|
66
|
+
}
|