以太坊交易堵塞、合约部署、合约调用、常用命令

一、每个账户发起的交易,nonce从0开始

二、如果遇到交易堵塞情况,可以按以下步骤排查

1、查看该账号目前发起的交易数量:

> eth.getTransactionCount(eth.accounts[0])                                                                  
2

2、通过交易ID查看堵塞的交易nonce:

> eth.getTransaction("0x6db14bb72145761a90f06c3cc7843803b7750750c12b9c029ef6a701a3cc8de6")                  
{
  from: "0x61863ab78fbd4b889de008594403e74876e00855",
  gas: 3000000,
  gasPrice: 1000000000,
  nonce: 3,
  ...
}

3、此交易的nonce=3>2,因此该交易会等待交易2完成,所以我们可以增加gas费用让交易2提速完成,或者取消交易2,注意,取消交易也是需要时间的。

4、有时候找不到交易2是在哪里发起的,有可能交易2只是占用了nonce却没有广播出去,这样就永远堵塞了。如果只是一个在私链上不重要的交易,可以直接重启geth即可重置一些数据。(交易处于queued中时,停止geth客户端,交易queued中的交易会被清除掉。)

5、最根本的解决方案是使用正确的nonce创建每一笔交易,使用统一维护的nonce获取接口,并且仅使用此方式获取,以免因使用了其它方式,导致nonce错乱。(具体的nonce获取接口实现在将来实际使用时再补上,暂不深入研究了。)

三、投票合约

使用Remix IDE 编写、编译、部署、调用
使用MetaMask 切换要连接的用户

Ballot.sol:

pragma solidity ^0.6.0;

contract Ballot {
    struct Voter {
        uint weight;
        bool voted;
        address delegate;
        uint vote;
    }
    
    struct Proposal {
        bytes32 name;
        uint voteCount;
    }
    
    address public chairperson;
    
    mapping(address => Voter) public voters;
    
    Proposal[] public proposals;
    
    constructor(bytes32[] memory proposalNames) public {
        chairperson = msg.sender;
        voters[chairperson].weight = 1;
        for(uint i = 0;i < proposalNames.length;i++){
            proposals.push(Proposal({
                name:proposalNames[i],
                voteCount:0
            }));
        }
    }
    
    function giveRightToVote(address voter) public{
        require(
            msg.sender == chairperson,
            "Only chairperson can give right to vote.");
        require(!voters[voter].voted,
            "The voter already voted");
        require(voters[voter].weight==0);
        voters[voter].weight=1;
    }
    
    function delegate(address to) public{
        Voter storage sender = voters[msg.sender];
        require(!sender.voted,"You already voted.");
        
        require(to!=msg.sender,"Self-delegation is disallowed.");
        
        while(voters[to].delegate!=address(0)){
            to = voters[to].delegate;
            require(to!=msg.sender);
        }
        
        sender.voted = true;
        // find last
        sender.delegate = to;
        Voter storage delegate_ = voters[to];
        if(delegate_.voted){
            // sum
            proposals[delegate_.vote].voteCount + sender.weight;
        }else{
            delegate_.weight += sender.weight;
        }
        
    }
    
    function vote(uint proposal) public {
        Voter storage sender = voters[msg.sender];
        require(!sender.voted,"You already voted.");
        sender.voted = true;
        sender.vote = proposal;
        proposals[proposal].voteCount+=sender.weight;
    }
    
    function winningProposal() public view returns(uint winningProposal_){
        uint winnigVoteCount = 0;
        for(uint p = 0;p < proposals.length;p++){
            if(proposals[p].voteCount>winnigVoteCount){
                winnigVoteCount = proposals[p].voteCount;
                winningProposal_ = p;
            }
        }
    }
    
    function winnerName() public view returns(bytes32 winnerName_){
        winnerName_ = proposals[winningProposal()].name;
    }
}

要点一:构造方法,部署前的传入提案名称:

["0x0000000000000000000000000000000000000000000000000000000000000005",
 "0x0000000000000000000000000000000000000000000000000000000000000020", 
 "0x0000000000000000000000000000000000000000000000000000000000000100"]

要点二:部署者为主席,发放投票资格
在这里插入图片描述
要点三:投票给提案,传参为提案索引,而不是提案名称

提案5的索引为0:0x0000000000000000000000000000000000000000000000000000000000000000
提案20的索引为1:0x0000000000000000000000000000000000000000000000000000000000000001
提案100的索引为2:0x0000000000000000000000000000000000000000000000000000000000000002

要点四:使用MetaMask切换连接的用户,进行投票
以太坊交易堵塞、合约部署、合约调用、常用命令_第1张图片
以太坊交易堵塞、合约部署、合约调用、常用命令_第2张图片
两个投票给索引1的提案,一个账户投票给索引2的提案,因此胜出的提案索引为1,如下:

decoded output 	{
	"0": "uint256: winningProposal_ 1"
}

胜出的提案名称为20,如下:

decoded output 	{
	"0": "bytes32: winnerName_ 0x0000000000000000000000000000000000000000000000000000000000000020"
}

四、常用命令

创建账户

> personal.newAccount()

解锁账户

> personal.unlockAccount(eth.accounts[0])    

修改矿工账户,挖矿收入账户

> miner.setEtherbase(eth.accounts[1]) 

发起转账交易

> eth.sendTransaction({from:eth.accounts[0],to:eth.accounts[1],,value:web3.toWei(25,'ether')})  

查询本地账户

> eth.accounts 

查询账户余额,单位转以太币

> web3.fromWei(eth.getBalance(eth.accounts[0]),'ether')     

查看交易池状态

> txpool.status

查看区块数目

> eth.blockNumber

查看交易详情

> eth.getTransaction("xxx")

查看交易在区块中的详细信息,包括合约部署后的地址信息

> eth.getTransactionReceipt("xxx")

查看区块

> eth.getBlock(10) 

查看同步情况

> eth.syncing

开始挖矿,可指定线程数

> miner.start(1)

停止挖矿

> miner.stop()

查看节点的encode url:

> admin.nodeInfo.enode

添加节点

> admin.addPeer("enode://xxx")

后台运行geth

nohup geth --datadir chaindata --port 30303 --networkid 1108 --identity "node1" --rpc --rpcaddr 192.168.78.102 --rpcport 9545 --allow-insecure-unlock --rpccorsdomain "*"  > out.log &

运行geth后,可使用以下命令进入console

geth attach ./chaindata/geth.ipc

你可能感兴趣的:(区块链)