EExcel 丞燕快速查詢2

EExcel 丞燕快速查詢2
EExcel 丞燕快速查詢2 https://sandk.ffbizs.com/

修行

你從那裡來? 妄想從那裡來?

心自體不可得,作用可得

開顯自己的真如本性
修行從裡面(內在)生起,這個心誰都不能破壞

印光大師說:全世界的人念佛都沒有感應,全世界的人念佛都沒求生淨土,我照樣念佛,我照樣求生淨土

跟外境沒有關係

不生滅心

https://youtu.be/iudlojChsKs?list=PLA16E144975D1AFCD&t=1963



修正自己的行為

[轉]解決replacement transaction underpriced以太坊交易異常

https://www.twblogs.net/a/5bb2596a2b71770e645ddc3c

replacement transaction underpriced異常

問題概述

以太坊系列(ETH&ETC)在發送交易有三個對應的RPC接口,分別是ethsendTransaction、ethsendRawTransaction和personal_sendTransaction。這三個接口發送(或構造發送內容時)都需要一個參數nonce。官方文檔對此參數的解釋是:整數類型,允許使用相同隨機數覆蓋自己發送的處於pending狀態的交易。

僅從官網的解釋,我們無法獲取到更多的有效的信息。但在真實生成中我們會發現如果傳錯nonce字段值,通過RPC接口調用發送的交易很大可能將不會被確認。如果通過console命令來操作一般不會出現此問題,因爲節點已經幫我們處理了。

如果繼續追蹤問題,會發現nonce傳遞錯誤的交易可以通過eth_getTransaction查詢得到相關信息,但是它的blocknumber始終未null,也就說這邊交易始終未被確認。如果是在dev模式下,應該是很快就會被確認的。更進一步,通過txpool.content命令,會發現那筆交易一直處於queued隊列中,而未被消費。

在使用同一個地址連續發送交易時,每筆交易往往不可能立即到賬, 當前交易還未到賬的情況下,下一筆交易無論是通過eth.getTransactionCount()獲取nonce值來設置,還是由節點自動從區塊中查詢,都會獲得和前一筆交易同樣的nonce值,這時節點就會報錯Error: replacement transaction underpriced

爲了防止交易重播,ETH(ETC)節點要求每筆交易必須有一個nonce數值。每一個賬戶從同一個節點發起交易時,這個nonce值從0開始計數,發送一筆nonce對應加1。當前面的nonce處理完成之後纔會處理後面的nonce。注意這裏的前提條件是相同的地址在相同的節點發送交易。 以下是nonce使用的幾條規則:

● 當nonce太小(小於之前已經有交易使用的nonce值),交易會被直接拒絕。

● 當nonce太大,交易會一直處於隊列之中,這也就是導致我們上面描述的問題的原因;

● 當發送一個比較大的nonce值,然後補齊開始nonce到那個值之間的nonce,那麼交易依舊可以被執行。

● 當交易處於queue中時停止geth客戶端,那麼交易queue中的交易會被清除掉。

如果系統中的熱點賬戶或普通賬戶發起交易時出現error: replacement transaction underpriced異常,那麼就需要考慮nonce使用是否正確。

引起此異常原因主要是當一個賬戶發起一筆交易,假設使用nonce爲1,交易已經發送至節點中,但由於手續費不高或網絡擁堵或nonce值過高,此交易處於queued中遲遲未被打包。

同時此地址再發起一筆交易,如果通過eth_getTransactionCount獲取的nonce值與上一個nonce值相同,用同樣的nonce值再發出交易時,如果手續費高於原來的交易,那麼第一筆交易將會被覆蓋,如果手續費低於原來的交易就會發生上面的異常。

通常發生此異常意味着:
- 你的Ethereum客戶端中已經有一筆處於pending狀態的交易。
- 新的一筆交易擁有pending狀態交易相同的nonce值。

- 新的交易的gas price太小,無法覆蓋pending狀態的交易。

通常情況下,覆蓋掉一筆處於pending狀態的交易gas price需要高於原交易的110%。

經過上面的解釋追蹤,我們已經瞭解到了nonce的基本使用規則。那麼,在實際應該用中我們如何保障nonce值的可靠性呢?這裏有兩個思路,

第一個思路就是由業務系統維護nonce值的遞增。如果交易發送就出現問題,那麼該地址下一筆交易繼續使用這個nonce進行發送交易。


第二個思路就是使用現有的api查詢當前地址已經發送交易的nonce值,然後對其加1,再發送交易。對應的API接口爲:eth_getTransactionCount,此方法由兩個參數,第一個參數爲需要查詢nonce的地址,第二個參數爲block的狀態:latest、earliest和pending。一般情況使用pending就可以查詢獲得最新已使用的nonce。其他狀態大家可以自行驗證。


第三個思路就
如果該熱點賬戶的私鑰信息等都存放在Ethereum客戶端中,那麼在發送交易的時候不傳遞nonce值,Ethereum客戶端會幫你處理好此nonce值的排序。


當然,此方案有兩個弊端。第一個是安全性無法保障(未進行冷熱賬戶分離),第二,在熱點賬戶下如果想覆蓋掉一筆交易,需要先查詢一下該交易的信息,從中獲取nonce值。

第一個思路

自行管理nonce適用於冷熱賬戶模式,也就是適用sendRawTransaction發送已經簽名好的交易時,此時nonce值已經存在於交易中,並且已經被簽名。

這種模式下,需要在業務系統中維護nonce的自增序列,使用一個nonce之後,在業務系統中對nonce進行加一處理。

此種方案也有限制條件。第一,由於nonce統一進行維護,那麼這個地址必須是內部地址,而且發起交易必須通過統一維護的nonce作爲出口,否則在其他地方發起交易,原有維護的nonce將會出現混亂。第二,一旦已經發出的交易發生異常,異常交易的nonce未被使用,那麼異常交易的nonce需要重新被使用之後它後面的nonce纔會生效。

在構建一筆新的交易時,在交易數據結構中會產生一個nonce值, nonce是當前區塊鏈下,發送者(from地址)發出的交易(成功記錄進區塊的)總數, 再加上1。例如新構建一筆從A發往B的交易,A地址之前的交易次數爲10,那麼這筆交易中的nonce則會設置成11, 節點驗證通過後則會放入交易池(txPool),並向其他節點廣播,該筆交易等待礦工將其打包進新的區塊。

第二個思路

那麼,如果在先構建併發送了一筆從地址A發出的,nonce爲11的交易,在該交易未打包進區塊之前, 再次構建一筆從A發出的交易,並將它發送到節點,不管是先通過web3的eth.getTransactionCount(A)獲取到的過往的交易數量,還是由節點自行填寫nonce, 後面的這筆交易的nonce同樣是11, 此時就出現了問題:

後面的這筆交易手續費給得更高, 那麼節點會前面的那筆交易從交易池中剔除,轉而放入後面構建的這筆交易
如果後面的這筆交易給得不夠高, 就會被廢棄掉, 如果通過web3這樣的sdk來向節點發送交易時,會收到錯誤信息

實際場景中

,會有批量從一個地址發送交易的需求,首先這些操作可能也應該是並行的,我們不會等待一筆交易成功寫入區塊後再發起第二筆交易,那麼此時有什麼好的解決辦法呢?先來看看geth節點中交易池對交易的處理流程

如之前所說,

第三個思路

構建一筆交易時如果不手動設置nonce值,geth節點會默認計算發起地址此前最大nonce數(寫入區塊的才算數),然後將其加上1, 然後將這筆交易放入節點交易池中的pending隊列,等到節點將其打包進區塊。

第一個思路

構建交易時,nonce值是可以手動設置的,如果當前的nonce本應該設置成11, 但是我手動設置成了13, 在節點收到這筆交易時, 發現pending隊列中並沒有改地址下nonce爲11及12的交易, 就會將這筆nonce爲13的交易放入交易池的queued隊列中。只有當前面的nonce補齊(nonce爲11及12的交易被發現並放入pending隊列)之後,纔會將它放入pending隊列中等待打包。

我們把pending隊列中的交易視爲可執行的,因爲它們可能被礦工打包進最新的區塊。 而queue隊列因爲前面的nonce存在缺失,暫時無法被礦工打包,稱爲不可執行交易。

那麼

實際開發中
,批量從一個地址發送交易時,應該怎麼辦呢?


方案一:

那麼在批量從一個地址發送交易時, 可以持久化一個本地的nonce,構建交易時用本地的nonce去累加,逐一填充到後面的交易。(要注意本地的nonce可能會出現偏差,可能需要定期從區塊中重新獲取nonce,更新至本地)。這個方法也有一定的侷限性,適合內部地址(即只有這個服務會使用該地址發送交易)。

說到

這裏還有個坑

,許多人認爲通過eth.getTransactionCount(address, "pending"),第二個參數爲pending, 就能獲得包含本地交易池pending隊列的nonce值,但是實際情況並不是這樣, 這裏的pending只包含待放入打包區塊的交易, 假設已寫入交易區塊的數量爲20, 又發送了nonce爲21,22,23的交易, 通過上面方法取得nonce可能是21(前面的21,22,23均未放入待打包區塊), 也可能是22(前面的21放入待打包區塊了,但是22,23還未放入)。

新版本的Geth好像解決了這個問題,在超大量測試transaction中,沒發現上述情況,如這問題還在應該會是大量錯誤一直產生才對!

超大量測試transaction

方案二:

是每次構建交易時,從geth節點的pending隊列取到最後一筆可執行交易的nonce, 在此基礎上加1,再發送給節點。可以通過txpool.content或txpool.inspect來獲得交易池列表,裏面可以看到pending及queue的交易列表。

其他方式:

啓動節點時,是可以設置交易池中的每個地址的pending隊列的容量上限,queue隊列的上容量上限, 以及整個交易池的pending隊列和queue隊列的容量上限。所以高併發的批量交易中,需要增加節點的交易池容量。

當然,除了擴大交易池,控制發送頻率,更要設置合理的交易手續費,eth上交易寫入區塊的速度取決於手續費及eth網絡的擁堵狀況,發送每筆交易時,設置合理的礦工費用,避免大量的交易積壓在交易池。

How to test your self ethereum geth private poa truffle

Important!! web3.eth.sendTransaction({ data: bytecode

"certjson.bytecode" or "certjson.bytecode.object"

MUST Have "0x" at line First Character


Use Truffle


1. run https://www.trufflesuite.com/docs/truffle/quickstart

1-1. run command


mkdir testtruffle
cd testtruffle
npm i web3

truffle unbox metacoin
truffle test ./test/TestMetaCoin.sol
truffle test ./test/metacoin.js
truffle compile

2. modify truffle-config.js
Here use your private poa chain networkinfo. from address must be can used. genesis file can put this address.


module.exports = {
  // Uncommenting the defaults below 
  // provides for an easier quick-start with Ganache.
  // You can also follow this format for other networks;
  // see 
  // for more details on how to specify configuration options!
  //
  networks: {
    development: {
      host: "192.168.99.100",
      port: 8545,
      network_id: "*",
      from: "0x5921a4c1b13afbd4b61d63e9c7bd47741c47b176"
    },
  //  test: {
  //    host: "127.0.0.1",
  //    port: 7545,
  //    network_id: "*"
  //  }
  }
  
};

3. modify migrations/1_initial_migration.js

If account have password, remark some line to put password. Here example no password.

Import: importRawKey maybe run one time, get error msg "Error: Returned error: account already exists" then remark.


Import: if unlock failed, may be is geth new version need to add --allow-insecure-unlock



const Web3 = require('web3');
const TruffleConfig = require('../truffle-config.js');

const Migrations = artifacts.require("Migrations");

module.exports = function(deployer) {
  const config = TruffleConfig.networks.development;

  //if (process.env.ACCOUNT_PASSWORD) {
    const web3 = new Web3(new Web3.providers.HttpProvider('http://' + config.host + ':' + config.port));

    // maybe only run one time for geth
    // web3.eth.personal.importRawKey('d05bd152f3d71ff5f91830f3ccc1090fb670c7026ebf8c2136d4e5090d59398d', '')
    // web3.eth.personal.importRawKey('138cbbfb21686ddc3b5ffeb2cfc83491175af68319977acb81d0ae93392c626c', '')

    // if unlock failed, may be is geth new version need to add --allow-insecure-unlock 
    console.log('>> Unlocking account ' + config.from);
    // //web3.personal.unlockAccount(config.from, process.env.ACCOUNT_PASSWORD, 36000);
    web3.eth.personal.unlockAccount(config.from, '', 36000);
  //}

  console.log('>> Deploying migration');

  deployer.deploy(Migrations);
};


truffle migrate


4. run

truffle test

Why you need to do this, because you can run many test (open 3 or more command line run truffle test) on same time for test your private poa ethereum.

If see Error, next step.


5. modify test/metacoin.js check code like this:


const MetaCoin = artifacts.require("MetaCoin");

Check accounts who have coin then change balance 0 or 1 & account one or two.

contract('MetaCoin', (accounts) => {
  it('should put 10000 MetaCoin in the first account', async () => {
    const metaCoinInstance = await MetaCoin.deployed();
    console.log('\n accounts: %o\n', accounts);
    
    const balance0 = await metaCoinInstance.getBalance.call(accounts[0]);
    const balance1 = await metaCoinInstance.getBalance.call(accounts[1]);
    console.log('balance0: %s', balance0.valueOf());
    console.log('balance1: %s\n', balance1.valueOf());

    assert.equal(balance1.valueOf(), 10000, "10000 wasn't in the first account");
  });
  it('should call a function that depends on a linked library', async () => {
    const metaCoinInstance = await MetaCoin.deployed();
    const metaCoinBalance = (await metaCoinInstance.getBalance.call(accounts[0])).toNumber();
    const metaCoinEthBalance = (await metaCoinInstance.getBalanceInEth.call(accounts[0])).toNumber();

    assert.equal(metaCoinEthBalance, 2 * metaCoinBalance, 'Library function returned unexpected function, linkage may be broken');
  });
  it('should send coin correctly', async () => {
    const metaCoinInstance = await MetaCoin.deployed();

    // Setup 2 accounts.
    const accountOne = accounts[1];
    const accountTwo = accounts[0];

    // Get initial balances of first and second account.
    const accountOneStartingBalance = (await metaCoinInstance.getBalance.call(accountOne)).toNumber();
    const accountTwoStartingBalance = (await metaCoinInstance.getBalance.call(accountTwo)).toNumber();

    // Make transaction from first account to second.
    const amount = 10;
    await metaCoinInstance.sendCoin(accountTwo, amount, { from: accountOne });

    // Get balances of first and second account after the transactions.
    const accountOneEndingBalance = (await metaCoinInstance.getBalance.call(accountOne)).toNumber();
    const accountTwoEndingBalance = (await metaCoinInstance.getBalance.call(accountTwo)).toNumber();


    assert.equal(accountOneEndingBalance, accountOneStartingBalance - amount, "Amount wasn't correctly taken from the sender");
    assert.equal(accountTwoEndingBalance, accountTwoStartingBalance + amount, "Amount wasn't correctly sent to the receiver");
  });
});


===========

web3 private key unlock & create contract


createcontract.js methond 1

var fs  = require('fs');

var Web3 = require("web3");
var provider = new Web3.providers.HttpProvider("http://192.168.99.100:18545");
var web3 = new Web3(provider);

console.log("before web set account: %o", web3.eth.defaultAccount);
const privateKey = 'd05bd152f3d71ff5f91830f3ccc1090fb670c7026ebf8c2136d4e5090d59398d';
const account = web3.eth.accounts.privateKeyToAccount('0x' + privateKey);
web3.eth.accounts.wallet.add(account);
console.log("private key import to account: %o", account)
web3.eth.defaultAccount = account.address;

try {
    web3.eth.personal.unlockAccount(account.address, "").then(console.log('Account unlocked!'));
} catch (err) {
    console.error('web3 unlockAccount Error: %o', err);
}

var certjson;
var certjsonpath = './Cert.json';

try {
    certjson = JSON.parse(fs.readFileSync(certjsonpath));
} catch (err) {
    console.error('readFileSync Error: %o', err);
}

const certContract = new web3.eth.Contract(certjson.abi);
certContract.options.data = certjson.bytecode;
certContract.options.from = '0x5921a4C1B13afbD4b61d63e9c7BD47741C47B176'
certContract.options.gas = '4700000'

console.log("web3 version: %o", web3.version)
web3.eth.getAccounts().then(o=>{console.log("Accounts: %o", o)})

certContract.deploy().send()
.on('error', (error) => {
    console.log("error: %o", error)
})
.on('transactionHash', (transactionHash) => {
    console.log("transactionHash: %o", transactionHash)
})
.on('receipt', (receipt) => {
    // receipt will contain deployed contract address
    console.log("receipt: %o", receipt)
    console.log("receipt.contractAddress: %o", receipt.contractAddress) 
})
.on('confirmation', (confirmationNumber, receipt) => {
    console.log("confirmationNumber: %o", confirmationNumber)
    console.log("confirmation receipt: %o", receipt)
})
.then(function(newContractInstance){
    if (typeof newContractInstance.options.address !== 'undefined') {
        console.log('Contract mined! address: ' + newContractInstance.options.address);
    }else{
        console.log("newContractInstance.address is undefined!")
    }
});

createcontract.js methond 2

var fs  = require('fs');

var Web3 = require("web3");
var provider = new Web3.providers.HttpProvider("http://192.168.99.100:18545");
var web3 = new Web3(provider);

console.log("before web set account: %o", web3.eth.defaultAccount);
const privateKey = 'd05bd152f3d71ff5f91830f3ccc1090fb670c7026ebf8c2136d4e5090d59398d';
const account = web3.eth.accounts.privateKeyToAccount('0x' + privateKey);
web3.eth.accounts.wallet.add(account);
console.log("private key import to account: %o", account)
web3.eth.defaultAccount = account.address;

try {
    web3.eth.personal.unlockAccount(account.address, "").then(console.log('Account unlocked!'));
} catch (err) {
    console.error('web3 unlockAccount Error: %o', err);
}

var certjson;
var certjsonpath = './Cert.json';

try {
    certjson = JSON.parse(fs.readFileSync(certjsonpath));
} catch (err) {
    console.error('readFileSync Error: %o', err);
}

const certContract = new web3.eth.Contract(certjson.abi);
certContract.options.data = certjson.bytecode;
certContract.options.from = '0x5921a4C1B13afbD4b61d63e9c7BD47741C47B176'
certContract.options.gas = '4700000'

console.log("web3 version: %o", web3.version)
web3.eth.getAccounts().then(o=>{console.log("Accounts: %o", o)})

// 怖署合約
var TxHash;

console.log("######## promise all ##############");

const getNonce = () => {
    return new Promise((resolve, reject) => {
        web3.eth.getTransactionCount(web3.eth.defaultAccount, (error, result) => {
            if(error) reject(error);
            resolve(web3.utils.toHex(result));
        })
    })
}

const getGasPrice = () => {
    return new Promise((resolve, reject) => {
        web3.eth.getGasPrice((error, result) => {
            if(error) reject(error);
            resolve(web3.utils.toHex(result));
        })
    })
}

// const sendRawTransaction = (rawTx) => {
//     const privateKey = "d05bd152f3d71ff5f91830f3ccc1090fb670c7026ebf8c2136d4e5090d59398d";
//     const tx = new Tx(rawTx);
//     const privateKeyBuffer = Buffer.from(privateKey, 'hex');
//     tx.sign(privateKeyBuffer);
//     const serializedTx = tx.serialize();
//     web3.eth.sendRawTransaction('0x' + serializedTx.toString('hex'), function(err, hash) {
//         console.log('Error:', err);
//         console.log('Hash:', hash);
//     });
// }
  
Promise.all([getNonce(), getGasPrice()]).then(values => {
    // const rawTx = {
    //     to: '0x203D17B4a1725E001426b7Ab3193E6657b0dBcc6',
    //     gasLimit: web3.toHex(1000000),
    //     value: web3.toHex(web3.toWei('0.1', 'ether')),
    //     nonce: values[0],
    //     gasPrice: values[1]
    // };
    // console.log(rawTx);
    // return(rawTx);

       console.log("nonce: %s", web3.utils.hexToNumber(values[0]));
       console.log("GasPrice: %s", web3.utils.hexToNumber(values[1]));

       web3.eth.estimateGas({from: "0x5921a4C1B13afbD4b61d63e9c7BD47741C47B176",data: contractjson.bytecode.object}).then(o=>{console.log("estimateGas: %o", o);})

    web3.eth.sendTransaction({
        from: "0x5921a4C1B13afbD4b61d63e9c7BD47741C47B176", // web3.eth.coinbase,  // web3.eth.getAccounts() 第一筆
        data: certjson.bytecode,
        nonce: values[0],
        gasPrice: values[1],
        gas: 4700000
    }).then(o=>{
        console.log("txhash object: %o", o); 
        TxHash = o.transactionHash;
        console.log("TxHash: %o", TxHash)
    
        web3.eth.getTransactionReceipt(TxHash).then(o=>{
            console.log("check contractAddress object: %s", o.contractAddress); 
        });    
    })
    .catch(e => console.log("sendTransaction error: %o", e));
})
.then(console.log("create transaction ok!"))
.catch(e => console.log("promise all error: %o", e))


node createcontract.js


===========
every 10sec create contract

First: fixed contract



pragma solidity >=0.4.25 <0.7.0;


contract MetaCoin {
 mapping (address => uint) balances;

 event Transfer(address indexed _from, address indexed _to, uint256 _value);

 constructor() public {
  balances[msg.sender] = 10000;
 }

 function sendCoin(address receiver, uint amount) public returns(bool sufficient) {
  if (balances[msg.sender] < amount) return false;
  balances[msg.sender] -= amount;
  balances[receiver] += amount;
  emit Transfer(msg.sender, receiver, amount);
  return true;
 }

 function getBalance(address addr) public view returns(uint) {
  return balances[addr];
 }
}

Promise.all method & web3.eth.sendTransaction


var fs  = require('fs');

var Web3 = require("web3");
var provider = new Web3.providers.HttpProvider("http://192.168.99.100:18545");
var web3 = new Web3(provider);

console.log("before web set account: %o", web3.eth.defaultAccount);
const privateKey = '138cbbfb21686ddc3b5ffeb2cfc83491175af68319977acb81d0ae93392c626c';
const account = web3.eth.accounts.privateKeyToAccount('0x' + privateKey);
web3.eth.accounts.wallet.add(account);
console.log("private key import to account: %o", account.address)
web3.eth.defaultAccount = account.address;

try {
    web3.eth.personal.unlockAccount(account.address, "").then(console.log('Account unlocked!'));
} catch (err) {
    console.error('web3 unlockAccount Error: %o', err);
}

var contractjson;
var contractjsonpath = './MetaCoin.json';

try {
    contractjson = JSON.parse(fs.readFileSync(contractjsonpath));
} catch (err) {
    console.error('readFileSync Error: %o', err);
}

const getNonce = () => {
    return new Promise((resolve, reject) => {
        web3.eth.getTransactionCount(web3.eth.defaultAccount, (error, result) => {
            if(error) reject(error);
            resolve(web3.utils.toHex(result));
        })
    })
}

const getGasPrice = () => {
    return new Promise((resolve, reject) => {
        web3.eth.getGasPrice((error, result) => {
            if(error) reject(error);
            resolve(web3.utils.toHex(result));
        })
    })
}

Promise.all([getNonce(), getGasPrice()]).then(values => {
    console.log("values: Nonce %s  GasPrice %s", web3.utils.hexToNumber(values[0]), web3.utils.hexToNumber(values[1]));
}).then(console.log("create transaction ok!"))
.catch(e => console.log("promise all error: %o", e))

setInterval( () => {

Promise.all([getNonce(), getGasPrice()]).then(values => {
    console.log("nonce: %s", web3.utils.hexToNumber(values[0]));
    console.log("GasPrice: %s", web3.utils.hexToNumber(values[1]));
   
   web3.eth.estimateGas({from: "e79d33e93bd888b35e055f1a12d876354729037b",data: contractjson.bytecode.object}).then(o=>{console.log("estimateGas: %o", o);})

    web3.eth.sendTransaction({
        from: "e79d33e93bd888b35e055f1a12d876354729037b", // web3.eth.coinbase,  // web3.eth.getAccounts() 第一筆
        data: contractjson.bytecode.object,
        nonce: values[0],
        gasPrice: 20000000000, //20,000,000,000
        gas: 181949 //181,949
    }).then(o=>{
        console.log("txhash object: %o", o); 
        TxHash = o.transactionHash;
        console.log("TxHash: %o", TxHash)
    
        web3.eth.getTransactionReceipt(TxHash).then(o=>{
            console.log("check contractAddress object: %s", o.contractAddress); 
        });    
    })
    .catch(e => console.log("sendTransaction error: %o", e.message));
})
.then(console.log("create transaction ok!"))
.catch(e => console.log("promise all error: %o", e.message))

}, Math.random() * 10000);


every 5sec create contract & web3 contract method


var fs  = require('fs');

var Web3 = require("web3");
var provider = new Web3.providers.HttpProvider("http://192.168.99.100:18545");
var web3 = new Web3(provider);

console.log("before web set account: %o", web3.eth.defaultAccount);
const privateKey = '138cbbfb21686ddc3b5ffeb2cfc83491175af68319977acb81d0ae93392c626c';
const account = web3.eth.accounts.privateKeyToAccount('0x' + privateKey);
web3.eth.accounts.wallet.add(account);
console.log("private key import to account: %o", account.address)
web3.eth.defaultAccount = account.address;

try {
    web3.eth.personal.unlockAccount(account.address, "").then(console.log('Account unlocked!'));
} catch (err) {
    console.error('web3 unlockAccount Error: %o', err);
}

var contractjson;
var contractjsonpath = './MetaCoin.json';

try {
    contractjson = JSON.parse(fs.readFileSync(contractjsonpath));
} catch (err) {
    console.error('readFileSync Error: %o', err);
}

setInterval( () => {

contractAddr = "0x46Fac13Ca8398545479bF2DA18133Aa87377b559";
contractfrom = "0xe79d33e93bd888b35e055f1a12d876354729037b";
coinOwnerAddr = "0xe79d33e93bd888b35e055f1a12d876354729037b"
sendCointoAddr = "0x5921a4C1B13afbD4b61d63e9c7BD47741C47B176";

var metacoinContract = new web3.eth.Contract(contractjson.abi, contractAddr);

metaCoinContract.methods.getBalance(coinOwnerAddr).call({
    from: contractfrom,
    gasPrice: 20000000000, //20,000,000,000
    gas: 181949
})
.then(o=>{console.log(coinOwnerAddr+" getBalance: %o", o)});

metaCoinContract.methods.sendCoin(sendCointoAddr, 10).send({
    from: contractfrom,
    gasPrice: 20000000000, //20,000,000,000
    gas: 181949
})
.then(o=>{console.log("sendCoin: %o", o)});

metaCoinContract.methods.getBalance(sendCointoAddr).call({
    from: contractfrom,
    gasPrice: 20000000000, //20,000,000,000
    gas: 181949
})
.then(o=>{console.log(sendCointoAddr+" getBalance: %o", o)});

}, Math.random() * 5000);

// .on('transactionHash', function(transactionHash){
//     console.log("transactionHash: %o", transactionHash)
// })
// .on('receipt', function(receipt){
//     console.log("receipt: %o", receipt)
//     console.log("receipt.contractAddress: %o", receipt.contractAddress) 
// })
// .on('confirmation', function(confirmationNumber, receipt){
//     console.log("confirmationNumber: %o", confirmationNumber)
//     console.log("confirmation receipt: %o", receipt)
// })
// .on('error', function(error){console.log("error: %o", error.message)});


=====
https://medium.com/finnovate-io/how-do-i-sign-transactions-with-web3-f90a853904a2
https://ethereum.stackexchange.com/questions/60611/defining-the-transaction-object-for-offline-transaction-signing-using-web3-js-f
https://github.com/ethereum/web3.js/issues/1430

https://programtheblockchain.com/posts/