├── .gitignore ├── img └── yuque_diagram.jpg ├── src ├── info.js ├── lib.js ├── walletGenerater.js ├── balance.js ├── listener.js ├── index.js ├── calculater.js └── sender.js ├── old-ecosystem.config.js ├── config.example.js ├── README.md ├── .prettierrc ├── wallets.example.csv ├── ecosystem.config.js └── package.json /.gitignore: -------------------------------------------------------------------------------- 1 | config.js 2 | wallets.csv 3 | node_modules 4 | hashCache.json 5 | -------------------------------------------------------------------------------- /img/yuque_diagram.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuanluoyue/rbnb-mine/HEAD/img/yuque_diagram.jpg -------------------------------------------------------------------------------- /src/info.js: -------------------------------------------------------------------------------- 1 | const os = require('os') 2 | 3 | const main = () => { 4 | const numCpus = os.cpus().length 5 | console.log(`cpu 核数 ${numCpus}`) 6 | } 7 | 8 | main() 9 | -------------------------------------------------------------------------------- /old-ecosystem.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | apps: [ 3 | { 4 | name: 'app1', 5 | script: './src/index.js', 6 | instances: 2, 7 | }, 8 | ], 9 | } -------------------------------------------------------------------------------- /config.example.js: -------------------------------------------------------------------------------- 1 | const config = { 2 | difficulty: '0x9999', 3 | tick: 'rBNB', 4 | walletTablePath: 'wallets.csv', 5 | rpcUrl: 'https://bsc-dataseed1.bnbchain.org', 6 | } 7 | 8 | module.exports = config 9 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # rBNB 2 | 3 | 空气项目,虚假的 web3,仅供娱乐 4 | 5 | ```npm i pm2 -g``` 6 | ```npm i``` 7 | ```npm run gen-wallet``` 8 | ```npm run start``` 9 | 10 | ## 优化 11 | 12 | ### 现状 13 | 项目方的服务大部分时间不可用,导致脚本大部分时间都在做无效的计算 14 | 15 | ### 方案 16 | 将计算好的答案持久化存储,等服务正常的时候再发送 17 | 18 | ![](./img/yuque_diagram.jpg) 19 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "tabWidth": 2, 3 | "semi": false, 4 | "singleQuote": true, 5 | "trailingComma": "all", 6 | "arrowParens": "avoid", 7 | "bracketSpacing": true, 8 | "endOfLine": "lf", 9 | "jsxBracketSameLine": false, 10 | "printWidth": 100, 11 | "proseWrap": "preserve", 12 | "useTabs": false 13 | } -------------------------------------------------------------------------------- /wallets.example.csv: -------------------------------------------------------------------------------- 1 | 地址,私钥,助记词 2 | 0x100000000000,0x00000000000000000000,xxx xxx xx xx xx xxx xx 3 | 0x100000000000,0x00000000000000000000,xxx xxx xx xx xx xxx xx 4 | 0x100000000000,0x00000000000000000000,xxx xxx xx xx xx xxx xx 5 | 0x100000000000,0x00000000000000000000,xxx xxx xx xx xx xxx xx 6 | 0x100000000000,0x00000000000000000000,xxx xxx xx xx xx xxx xx 7 | -------------------------------------------------------------------------------- /ecosystem.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | apps: [ 3 | { 4 | name: '文件读写', 5 | script: './src/listener.js', 6 | instances: 1, 7 | }, 8 | { 9 | name: '离线计算', 10 | script: './src/calculater.js', 11 | instances: 2, 12 | }, 13 | { 14 | name: '答案消费', 15 | script: './src/sender.js', 16 | instances: 1, 17 | }, 18 | ], 19 | } 20 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "rbnb-mine", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "start": "pm2 start ecosystem.config.js", 9 | "old-start": "pm2 start old-ecosystem.config.js", 10 | "gen-wallet": "node ./src/walletGenerater.js", 11 | "info": "node ./src/info.js", 12 | "balance": "node ./src/balance.js" 13 | 14 | }, 15 | "keywords": [], 16 | "author": "", 17 | "license": "ISC", 18 | "dependencies": { 19 | "bip39": "^3.0.4", 20 | "ethers": "5.7.2", 21 | "fast-csv": "^5.0.0", 22 | "node-fetch": "2.7.0", 23 | "nodemon": "^3.0.2" 24 | } 25 | } -------------------------------------------------------------------------------- /src/lib.js: -------------------------------------------------------------------------------- 1 | const fetch = require('node-fetch') 2 | 3 | const postResultData = async body => { 4 | const res = await fetch('https://ec2-18-218-197-117.us-east-2.compute.amazonaws.com/validate', { 5 | headers: { 6 | accept: 'application/json, text/plain, */*', 7 | 'accept-language': 'zh-CN,zh;q=0.9', 8 | 'content-type': 'application/json', 9 | 'sec-ch-ua': '"Not_A Brand";v="8", "Chromium";v="120", "Google Chrome";v="120"', 10 | 'sec-ch-ua-mobile': '?0', 11 | 'sec-ch-ua-platform': '"Windows"', 12 | 'sec-fetch-dest': 'empty', 13 | 'sec-fetch-mode': 'cors', 14 | 'sec-fetch-site': 'cross-site', 15 | Referer: 'https://bnb.reth.cc/', 16 | 'Referrer-Policy': 'strict-origin-when-cross-origin', 17 | }, 18 | body, 19 | method: 'POST', 20 | }) 21 | const r = await res.json() 22 | return r 23 | } 24 | 25 | const getRandomInt = (min, max) => { 26 | return Math.floor(Math.random() * (max - min + 1)) + min 27 | } 28 | 29 | async function sleepMS(ms) { 30 | return new Promise(resolve => setTimeout(resolve, ms)) 31 | } 32 | 33 | module.exports = { 34 | postResultData, 35 | getRandomInt, 36 | sleepMS, 37 | } 38 | -------------------------------------------------------------------------------- /src/walletGenerater.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs') 2 | const csv = require('fast-csv') 3 | const bip39 = require('bip39') 4 | const { ethers } = require('ethers') 5 | 6 | const KEY_PATH = `m/44'/60'/0'/0/0` 7 | const genCount = 20 8 | 9 | const genWallet = () => { 10 | const mnemonic = bip39.generateMnemonic() 11 | const wallet = ethers.Wallet.fromMnemonic(mnemonic, KEY_PATH) 12 | 13 | return { 14 | 地址: wallet.address, 15 | 私钥: wallet.privateKey, 16 | 助记词: mnemonic, 17 | } 18 | } 19 | 20 | const main = async () => { 21 | const walletData = [] 22 | const filePath = 'wallets.csv' 23 | 24 | const isExist = fs.existsSync(filePath) 25 | 26 | if (isExist) { 27 | throw Error('文件已存在,请先备份并删除') 28 | } 29 | 30 | for (let i = 0; i < genCount; i++) { 31 | const w = genWallet() 32 | walletData.push(w) 33 | } 34 | 35 | const writableStream = fs.createWriteStream(filePath) 36 | 37 | csv 38 | .write(walletData, { headers: true }) 39 | .pipe(writableStream) 40 | .on('finish', () => { 41 | console.log('CSV file has been written successfully.') 42 | }) 43 | .on('error', err => { 44 | console.error('Error writing CSV file:', err) 45 | }) 46 | } 47 | 48 | main() 49 | -------------------------------------------------------------------------------- /src/balance.js: -------------------------------------------------------------------------------- 1 | const fetch = require('node-fetch') 2 | const csv = require('fast-csv') 3 | const fs = require('fs') 4 | 5 | const { sleepMS } = require('./lib') 6 | const { walletTablePath } = require('../config') 7 | 8 | process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0' 9 | 10 | const initWallet = async () => { 11 | const wallets = [] 12 | return new Promise((resolve, reject) => { 13 | fs.createReadStream(walletTablePath) 14 | .pipe(csv.parse({ headers: true })) 15 | .on('error', error => reject(error)) 16 | .on('data', row => { 17 | wallets.push({ 18 | address: row['地址'], 19 | }) 20 | }) 21 | .on('end', () => resolve(wallets)) 22 | }) 23 | } 24 | 25 | const getBalance = async address => { 26 | const url = `https://ec2-18-218-197-117.us-east-2.compute.amazonaws.com/balance?address=${address}` 27 | const res = await fetch(url, { 28 | headers: { 29 | accept: 'application/json, text/plain, */*', 30 | 'accept-language': 'zh-CN,zh;q=0.9', 31 | 'sec-ch-ua': '"Not_A Brand";v="8", "Chromium";v="120", "Google Chrome";v="120"', 32 | 'sec-ch-ua-mobile': '?0', 33 | 'sec-ch-ua-platform': '"Windows"', 34 | 'sec-fetch-dest': 'empty', 35 | 'sec-fetch-mode': 'cors', 36 | 'sec-fetch-site': 'cross-site', 37 | }, 38 | referrer: 'https://bnb.reth.cc/', 39 | referrerPolicy: 'strict-origin-when-cross-origin', 40 | body: null, 41 | method: 'GET', 42 | mode: 'cors', 43 | credentials: 'omit', 44 | }) 45 | const r = await res.json() 46 | console.log(r.address, r.balance) 47 | return r.balance 48 | } 49 | 50 | const main = async () => { 51 | let count = 0 52 | const wallets = await initWallet() 53 | 54 | for (const w of wallets) { 55 | try { 56 | const balance = await getBalance(w.address) 57 | count += balance 58 | } catch (err) { 59 | console.log('请求失败') 60 | } 61 | 62 | await sleepMS(1000) 63 | } 64 | 65 | console.log('总量:', count) 66 | } 67 | 68 | main() 69 | -------------------------------------------------------------------------------- /src/listener.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs') 2 | const net = require('net') 3 | 4 | const filePath = 'hashCache.json' 5 | const PORT = 3000 6 | 7 | // const solution = { 8 | // address: '', 9 | // solution: '', 10 | // failCount: 0, 11 | // } 12 | 13 | // const message = { 14 | // action: 'push', 15 | // data: { 16 | // address: '', 17 | // solution: '', 18 | // failCount: 0, 19 | // }, 20 | // } 21 | 22 | const pushSolution = solution => { 23 | const data = fs.readFileSync(filePath, 'utf-8') 24 | const arr = JSON.parse(data) 25 | arr.push(solution) 26 | const newData = JSON.stringify(arr) 27 | fs.writeFileSync(filePath, newData, 'utf-8') 28 | console.log('当前答案数量', arr.length) 29 | } 30 | 31 | const popSolution = () => { 32 | const data = fs.readFileSync(filePath, 'utf-8') 33 | const arr = JSON.parse(data) 34 | const solution = arr.pop() 35 | const newData = JSON.stringify(arr) 36 | fs.writeFileSync(filePath, newData, 'utf-8') 37 | console.log('当前答案数量', arr.length) 38 | return solution 39 | } 40 | 41 | const main = () => { 42 | const isExist = fs.existsSync(filePath) 43 | 44 | if (!isExist) { 45 | // 创建共享文件 46 | fs.writeFileSync(filePath, JSON.stringify([])) 47 | } 48 | 49 | const server = net.createServer(socket => { 50 | socket.on('data', data => { 51 | try { 52 | const message = JSON.parse(data) 53 | // console.log(message) 54 | if (message.action === 'push') { 55 | pushSolution(message.data) 56 | } else if (message.action === 'pop') { 57 | const solution = popSolution() 58 | if (solution) { 59 | const reMsg = JSON.stringify(solution) 60 | socket.write(reMsg) 61 | } else { 62 | console.log('暂无可用答案') 63 | socket.write('') 64 | } 65 | } 66 | } catch (error) { 67 | console.error('Error processing data:', error) 68 | } 69 | }) 70 | 71 | socket.on('error', err => console.log(err)) 72 | socket.on('end', () => {}) 73 | }) 74 | 75 | server.on('error', err => console.log(err)) 76 | 77 | server.listen(PORT, () => { 78 | console.log(`Server listening on port ${PORT}`) 79 | }) 80 | } 81 | 82 | main() 83 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | const { ethers } = require('ethers') 2 | const csv = require('fast-csv') 3 | const fs = require('fs') 4 | 5 | const { difficulty, walletTablePath, tick } = require('../config') 6 | const { postResultData, getRandomInt, sleepMS } = require('./lib') 7 | 8 | process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0' 9 | 10 | // const provider = new ethers.providers.JsonRpcProvider(rpcUrl) 11 | 12 | const currentChallenge = ethers.utils.formatBytes32String(tick) 13 | 14 | // 查找可能的solution 15 | function findSolution(difficulty, walletInfo) { 16 | const { address } = walletInfo 17 | while (1) { 18 | const random_value = ethers.utils.randomBytes(32) 19 | const potential_solution = ethers.utils.hexlify(random_value) 20 | const hashed_solution = ethers.utils.keccak256( 21 | ethers.utils.defaultAbiCoder.encode( 22 | ['bytes32', 'bytes32', 'address'], 23 | [potential_solution, currentChallenge, address], 24 | ), 25 | ) 26 | if (hashed_solution.startsWith(difficulty)) { 27 | return potential_solution 28 | } 29 | } 30 | } 31 | 32 | async function sendTransaction(solution, walletInfo) { 33 | const body = { 34 | solution, 35 | challenge: currentChallenge, 36 | address: walletInfo.address, 37 | difficulty, 38 | tick, 39 | } 40 | 41 | console.log(body) 42 | 43 | await postResultData(JSON.stringify(body)) 44 | } 45 | 46 | const initWallet = async () => { 47 | const wallets = [] 48 | return new Promise((resolve, reject) => { 49 | fs.createReadStream(walletTablePath) 50 | .pipe(csv.parse({ headers: true })) 51 | .on('error', error => reject(error)) 52 | .on('data', row => { 53 | wallets.push({ 54 | address: row['地址'], 55 | }) 56 | }) 57 | .on('end', () => resolve(wallets)) 58 | }) 59 | } 60 | 61 | async function main() { 62 | const wallets = await initWallet() 63 | 64 | try { 65 | while (true) { 66 | const index = getRandomInt(0, wallets.length - 1) 67 | const walletInfo = wallets[index] 68 | const solution = findSolution(difficulty, walletInfo) 69 | 70 | await sendTransaction(solution, walletInfo) 71 | console.log(`发送成功 solution: ${solution}`) 72 | 73 | await sleepMS(50) 74 | } 75 | } catch (err) { 76 | console.log('错误 ------------------') 77 | console.log(err) 78 | console.log('-----------------------') 79 | console.log('重启程序') 80 | main() 81 | } 82 | } 83 | 84 | main() 85 | -------------------------------------------------------------------------------- /src/calculater.js: -------------------------------------------------------------------------------- 1 | const net = require('net') 2 | const csv = require('fast-csv') 3 | const fs = require('fs') 4 | const { ethers } = require('ethers') 5 | 6 | const { difficulty, walletTablePath, tick } = require('../config') 7 | const { getRandomInt, sleepMS } = require('./lib') 8 | 9 | const PORT = 3000 10 | const currentChallenge = ethers.utils.formatBytes32String(tick) 11 | 12 | const connectAsync = (client, port, host) => { 13 | return new Promise((resolve, reject) => { 14 | // 尝试连接 15 | client.connect(port, host, () => { 16 | resolve() // 连接成功,Promise 解析 17 | }) 18 | 19 | // 处理连接错误 20 | client.on('error', err => { 21 | reject(err) // 连接失败,Promise 拒绝 22 | }) 23 | }) 24 | } 25 | 26 | // 查找可能的solution 27 | function findSolution(difficulty, walletInfo) { 28 | const { address } = walletInfo 29 | while (1) { 30 | const random_value = ethers.utils.randomBytes(32) 31 | const potential_solution = ethers.utils.hexlify(random_value) 32 | const hashed_solution = ethers.utils.keccak256( 33 | ethers.utils.defaultAbiCoder.encode( 34 | ['bytes32', 'bytes32', 'address'], 35 | [potential_solution, currentChallenge, address], 36 | ), 37 | ) 38 | if (hashed_solution.startsWith(difficulty)) { 39 | return potential_solution 40 | } 41 | } 42 | } 43 | 44 | const initWallet = async () => { 45 | const wallets = [] 46 | return new Promise((resolve, reject) => { 47 | fs.createReadStream(walletTablePath) 48 | .pipe(csv.parse({ headers: true })) 49 | .on('error', error => reject(error)) 50 | .on('data', row => { 51 | wallets.push({ 52 | address: row['地址'], 53 | }) 54 | }) 55 | .on('end', () => resolve(wallets)) 56 | }) 57 | } 58 | 59 | const main = async () => { 60 | const client = new net.Socket() 61 | const wallets = await initWallet() 62 | 63 | await connectAsync(client, PORT, 'localhost') 64 | 65 | client.on('error', err => { 66 | console.log('calculater', err) 67 | }) 68 | 69 | client.on('end', () => {}) 70 | 71 | while (true) { 72 | const index = getRandomInt(0, wallets.length - 1) 73 | const walletInfo = wallets[index] 74 | const solution = findSolution(difficulty, walletInfo) 75 | 76 | const message = { 77 | action: 'push', 78 | data: { 79 | address: walletInfo.address, 80 | solution, 81 | failCount: 0, 82 | }, 83 | } 84 | 85 | try { 86 | client.write(JSON.stringify(message)) 87 | console.log('计算完成') 88 | } catch (err) { 89 | console.log('连接异常', err) 90 | } 91 | 92 | await sleepMS(50) 93 | } 94 | } 95 | 96 | main() 97 | -------------------------------------------------------------------------------- /src/sender.js: -------------------------------------------------------------------------------- 1 | const net = require('net') 2 | const { ethers } = require('ethers') 3 | 4 | const { postResultData, sleepMS } = require('./lib') 5 | const { difficulty, tick } = require('../config') 6 | 7 | const PORT = 3000 8 | 9 | const currentChallenge = ethers.utils.formatBytes32String(tick) 10 | 11 | const connectAsync = (client, port, host) => { 12 | return new Promise((resolve, reject) => { 13 | // 尝试连接 14 | client.connect(port, host, () => { 15 | resolve() // 连接成功,Promise 解析 16 | }) 17 | 18 | // 处理连接错误 19 | client.on('error', err => { 20 | reject(err) // 连接失败,Promise 拒绝 21 | }) 22 | }) 23 | } 24 | 25 | async function sendTransaction(solution, walletInfo) { 26 | const body = { 27 | solution, 28 | challenge: currentChallenge, 29 | address: walletInfo.address, 30 | difficulty, 31 | tick, 32 | } 33 | 34 | const res = await postResultData(JSON.stringify(body)) 35 | return res 36 | } 37 | 38 | const main = async () => { 39 | process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0' 40 | const client = new net.Socket() 41 | try { 42 | await connectAsync(client, PORT, 'localhost') 43 | } catch (err) { 44 | await sleepMS(2000) 45 | console.log('重新连接 linstener') 46 | main() 47 | return 48 | } 49 | 50 | client.on('error', err => { 51 | console.log(err) 52 | }) 53 | 54 | client.on('end', () => {}) 55 | 56 | while (true) { 57 | try { 58 | const message = { 59 | action: 'pop', 60 | } 61 | 62 | client.write(JSON.stringify(message)) 63 | 64 | const data = await new Promise(resolve => { 65 | client.once('data', resolve) 66 | }) 67 | 68 | if (data) { 69 | const d = JSON.parse(data) 70 | try { 71 | console.log('开始发送') 72 | const res = await sendTransaction(d.solution, { address: d.address }) 73 | console.log('res', res) 74 | if (res.msg.includes('success')) { 75 | console.log('请求成功') 76 | } else { 77 | console.error('!!! 未知原因 关注') 78 | throw Error('') 79 | } 80 | } catch (err) { 81 | console.log('#2 err', err) 82 | console.log('对方服务异常,回收答案') 83 | const msg = { 84 | action: 'push', 85 | data: { 86 | address: d.address, 87 | solution: d.solution, 88 | failCount: d.failCount + 1, 89 | }, 90 | } 91 | if (msg.data.failCount < 6) { 92 | client.write(JSON.stringify(msg)) 93 | } 94 | } 95 | } 96 | } catch (err) { 97 | console.log('#1 err', err) 98 | } 99 | 100 | await sleepMS(500) 101 | } 102 | } 103 | 104 | main() 105 | --------------------------------------------------------------------------------