汪晓明对区块链、以太坊的思考

记录创业、生活的所思所感,探讨去中心化思想,推动区块链的发展。

HPB74:HPB主网接入最佳实践之JS版

1、开始准备

1.1 学习门槛

1.2 源码地址

1
https://github.com/loglos/web3.git

2、HPB JavaScript API使用说明

This is the HPB compatible JavaScript API which implements the Generic JSON RPC spec.

You need to run a local HPB node to use this library.

2.1 Table of Contents

As a Browser module

CDN

1
<script type="text/javascript" src="https://hpb.io/web_hpb.min.js"></script>
  • Include web3_hpb.min.js in your html file.

2.2 Usage

Use the web3_hpb object directly from the global namespace:

1
2
3
var Web3ForHpb = require('web3_hpb');
var web3Hpb = new Web3ForHpb();
console.log(web3Hpb); //{ hpb:..., shh:... }

Set a provider (HttpProvider):

1
2
// Set the provider you want from Web3.providers
web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:8545"));

There you go, now you can use it:

1
2
var coinbase = web3Hpb.hpb.coinbase;
var balance = web3Hpb.hpb.getBalance(coinbase);

3、HPB JavaScript API examples

3.1 balance

https://github.com/yanranxiaoxiaoshu/web3/blob/master/web3_hpb/example/balance.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
<!DOCTYPE html>
<html>

<head>
    <script type="text/javascript" src="../node_modules/bignumber.js/bignumber.min.js"></script>
    <script type="text/javascript" src="../dist/web3_hpb-light.js"></script>
    <script type="text/javascript">

        var web3_hpb = require('web3_hpb');
        var web3_hpb = new web3_hpb();
        web3_hpb.setProvider(new web3_hpb.providers.HttpProvider());

        function watchBalance() {
            var coinbase = web3_hpb.hpb.coinbase;

            var originalBalance = web3_hpb.hpb.getBalance(coinbase).toNumber();
            document.getElementById('coinbase').innerText = 'coinbase: ' + coinbase;
            document.getElementById('original').innerText = ' original balance: ' + originalBalance + '    watching...';

            web3_hpb.hpb.filter('latest').watch(function () {
                var currentBalance = web3_hpb.hpb.getBalance(coinbase).toNumber();
                document.getElementById("current").innerText = 'current: ' + currentBalance;
                document.getElementById("diff").innerText = 'diff:    ' + (currentBalance - originalBalance);
            });
        }

    </script>
</head>

<body>
    <h1>coinbase balance</h1>
    <button type="button" onClick="watchBalance();">watch balance</button>
    <div></div>
    <div id="coinbase"></div>
    <div id="original"></div>
    <div id="current"></div>
    <div id="diff"></div>
</body>

</html>

3.2 contract

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
<!DOCTYPE html>
<html>

<head>
<script type="text/javascript" src="../dist/web3_hpb.js"></script>
<script type="text/javascript">
    var web3_hpb = require('web3_hpb');
    var web3_hpb = new web3_hpb();
    web3_hpb.setProvider(new web3_hpb.providers.HttpProvider("http://localhost:8545"));
    // solidity code code
    var source = "" +
    "pragma solidity ^0.4.6;" +
    "contract test {\n" +
    "   function multiply(uint a) constant returns(uint d) {\n" +
    "       return a * 7;\n" +
    "   }\n" +
    "}\n";
    var compiled = web3_hpb.hpb.compile.solidity(source);
    var code = compiled.code;
    // contract json abi, this is autogenerated using solc CLI
    var abi = compiled.info.abiDefinition;
    var myContract;
    function createExampleContract() {
        // hide create button
        document.getElementById('create').style.visibility = 'hidden';
        document.getElementById('code').innerText = code;
        // let's assume that coinbase is our account
        web3_hpb.hpb.defaultAccount = web3_hpb.hpb.coinbase;
        // create contract
        document.getElementById('status').innerText = "transaction sent, waiting for confirmation";
        web3_hpb.hpb.contract(abi).new({data: code}, function (err, contract) {
            if(err) {
                console.error(err);
                return;
            // callback fires twice, we only want the second call when the contract is deployed
            } else if(contract.address){
                myContract = contract;
                console.log('address: ' + myContract.address);
                document.getElementById('status').innerText = 'Mined!';
                document.getElementById('call').style.visibility = 'visible';
            }
        });
    }
    function callExampleContract() {
        // this should be generated by hpber
        var param = parseInt(document.getElementById('value').value);
        // call the contract
        var res = myContract.multiply(param);
        document.getElementById('result').innerText = res.toString(10);
    }
</script>
</head>
<body>
    <h1>contract</h1>
    <div id="code"></div> 
    <div id="status"></div>
    <div id='create'>
        <button type="button" onClick="createExampleContract();">create example contract</button>
    </div>
    <div id='call' style='visibility: hidden;'>
        <input type="number" id="value" onkeyup='callExampleContract()'></input>
    </div>
    <div id="result"></div>
</body>
</html>

3.3 contract_array

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
<!DOCTYPE html>
<html>

<head>
<script type="text/javascript" src="../dist/web3_hpb.js"></script>
<script type="text/javascript">
    var web3_hpb = require('web3_hpb');
    var web3_hpb = new web3_hpb();
    web3_hpb.setProvider(new web3_hpb.providers.HttpProvider("http://localhost:8545"));
    // solidity code code
    var source = "" +
    "pragma solidity ^0.4.6;" +
    "contract test {\n" +
    "   function take(uint[] a, uint b) constant returns(uint d) {\n" +
    "       return a[b];\n" +
    "   }\n" +
    "}\n";
    var compiled = web3_hpb.hpb.compile.solidity(source);
    var code = compiled.code;
    // contract json abi, this is autogenerated using solc CLI
    var abi = compiled.info.abiDefinition;
    var myContract;
    function createExampleContract() {
        // hide create button
        document.getElementById('create').style.visibility = 'hidden';
        document.getElementById('code').innerText = code;
        // let's assume that coinbase is our account
        web3_hpb.hpb.defaultAccount = web3_hpb.hpb.coinbase;
        // create contract
        document.getElementById('status').innerText = "transaction sent, waiting for confirmation";
        web3_hpb.hpb.contract(abi).new({data: code}, function (err, contract) {
            if (err) {
                console.error(err);
                return;
            // callback fires twice, we only want the second call when the contract is deployed
            } else if(contract.address){
                myContract = contract;
                console.log('address: ' + myContract.address);
                document.getElementById('status').innerText = 'Mined!';
                document.getElementById('call').style.visibility = 'visible';
            }
        });
    }
    function callExampleContract() {
        // this should be generated by hpber
        var param = parseInt(document.getElementById('value').value);
        // call the contract
        var res = myContract.take([0,6,5,2,1,5,6], param);
        document.getElementById('result').innerText = res.toString(10);
    }
</script>
</head>
<body>
    <h1>contract</h1>
    <div id="code"></div> 
    <div id="status"></div>
    <div id='create'>
        <button type="button" onClick="createExampleContract();">create example contract</button>
    </div>
    <div id='call' style='visibility: hidden;'>
        <div>var array = [0,6,5,2,1,5,6];</div>
        <div>var x = array[
            <input type="number" id="value" onkeyup='callExampleContract()'></input>
        ];
        </div>
    </div>
    <div id="result"></div>
</body>
</html>

3.4 event_inc

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
<!DOCTYPE html>
<html>
    <head>
    <script type="text/javascript" src="../dist/web3_hpb.js"></script>
    <script type="text/javascript">
        var web3_hpb = require('web3_hpb');
        var web3_hpb = new web3_hpb();
        web3_hpb.setProvider(new web3_hpb.providers.HttpProvider('http://localhost:8545'));
        var source = "" +
        "pragma solidity ^0.4.6;" +
        "contract Contract { " +
        "   event Incremented(bool indexed odd, uint x); " +
        "   function Contract() { " +
        "        x = 70; " +
        "    } " +
        "    function inc() { " +
        "        ++x; " +
        "        Incremented(x % 2 == 1, x); " +
        "    } " +
        "    uint x; " +
        "}";
        var compiled = web3_hpb.hpb.compile.solidity(source);
        var code = compiled.code;
        var abi = compiled.info.abiDefinition;
        var address;
        var contract;
        var inc;
        var update = function (err, x) {
            document.getElementById('result').textContent = JSON.stringify(x, null, 2);
        };

        var createContract = function () {
            // let's assume that we have a private key to coinbase ;)
            web3_hpb.hpb.defaultAccount = web3_hpb.hpb.coinbase;

            document.getElementById('create').style.visibility = 'hidden';
            document.getElementById('status').innerText = "transaction sent, waiting for confirmation";
            web3_hpb.hpb.contract(abi).new({data: code}, function (err, c) {
                if (err) {
                    console.error(err);
                    return;
                // callback fires twice, we only want the second call when the contract is deployed
                } else if(c.address){
                    contract = c;
                    console.log('address: ' + contract.address);
                    document.getElementById('status').innerText = 'Mined!';
                    document.getElementById('call').style.visibility = 'visible';
                    inc = contract.Incremented({odd: true}, update);
                }
            });
        };
        var counter = 0;
        var callContract = function () {
            counter++;
            var all = 70 + counter;
            document.getElementById('count').innerText = 'Transaction sent ' + counter + ' times. ' +
                'Expected x value is: ' + (all - (all % 2 ? 0 : 1)) + ' ' +
                'Waiting for the blocks to be mined...';

            contract.inc();
        };
    </script>
    </head>

    <body>
        <div id="status"></div>
        <div>
            <button id="create" type="button" onClick="createContract();">create contract</button>
        </div>
        <div>
            <button id="call" style="visibility: hidden;" type="button" onClick="callContract();">test1</button>
        </div>
        <div id='count'></div>
        <div id="result">
        </div>
    </body>

3.5 icap

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
<!DOCTYPE html>
<html>

<head>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css">
<script src="https://code.jquery.com/jquery-2.1.4.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"></script>
<script type="text/javascript" src="../dist/web3_hpb.js"></script>
<script type="text/javascript">
    var web3_hpb = require('web3_hpb');
    var web3_hpb = new web3_hpb();
    var BigNumber = require('bignumber.js');
    web3_hpb.setProvider(new web3_hpb.providers.HttpProvider("http://localhost:8545"));
    var from = web3_hpb.hpb.coinbase;
    web3_hpb.hpb.defaultAccount = from;
    var nameregAbi = [
        {"constant":true,"inputs":[{"name":"_owner","type":"address"}],"name":"name","outputs":[{"name":"o_name","type":"bytes32"}],"type":"function"},
        {"constant":true,"inputs":[{"name":"_name","type":"bytes32"}],"name":"owner","outputs":[{"name":"","type":"address"}],"type":"function"},
        {"constant":true,"inputs":[{"name":"_name","type":"bytes32"}],"name":"content","outputs":[{"name":"","type":"bytes32"}],"type":"function"},
        {"constant":true,"inputs":[{"name":"_name","type":"bytes32"}],"name":"addr","outputs":[{"name":"","type":"address"}],"type":"function"},
        {"constant":false,"inputs":[{"name":"_name","type":"bytes32"}],"name":"reserve","outputs":[],"type":"function"},
        {"constant":true,"inputs":[{"name":"_name","type":"bytes32"}],"name":"subRegistrar","outputs":[{"name":"o_subRegistrar","type":"address"}],"type":"function"},
        {"constant":false,"inputs":[{"name":"_name","type":"bytes32"},{"name":"_newOwner","type":"address"}],"name":"transfer","outputs":[],"type":"function"},
        {"constant":false,"inputs":[{"name":"_name","type":"bytes32"},{"name":"_registrar","type":"address"}],"name":"setSubRegistrar","outputs":[],"type":"function"},
        {"constant":false,"inputs":[],"name":"Registrar","outputs":[],"type":"function"},
        {"constant":false,"inputs":[{"name":"_name","type":"bytes32"},{"name":"_a","type":"address"},{"name":"_primary","type":"bool"}],"name":"setAddress","outputs":[],"type":"function"},
        {"constant":false,"inputs":[{"name":"_name","type":"bytes32"},{"name":"_content","type":"bytes32"}],"name":"setContent","outputs":[],"type":"function"},
        {"constant":false,"inputs":[{"name":"_name","type":"bytes32"}],"name":"disown","outputs":[],"type":"function"},
        {"constant":true,"inputs":[{"name":"_name","type":"bytes32"}],"name":"register","outputs":[{"name":"","type":"address"}],"type":"function"},
        {"anonymous":false,"inputs":[{"indexed":true,"name":"name","type":"bytes32"}],"name":"Changed","type":"event"},
        {"anonymous":false,"inputs":[{"indexed":true,"name":"name","type":"bytes32"},{"indexed":true,"name":"addr","type":"address"}],"name":"PrimaryChanged","type":"event"}
    ];
    var depositAbi = [{"constant":false,"inputs":[{"name":"name","type":"bytes32"}],"name":"deposit","outputs":[],"type":"function"}];
    var Namereg = web3_hpb.hpb.contract(nameregAbi);
    var Deposit = web3_hpb.hpb.contract(depositAbi);
    var namereg = web3_hpb.hpb.ibanNamereg;
    var deposit;
    var iban;
    function validateNamereg() {
        var address = document.getElementById('namereg').value;
        var ok = web3_hpb.isAddress(address) || address === 'default';
        if (ok) {
            namereg = address === 'default' ? web3_hpb.hpb.ibanNamereg : Namereg.at(address);
            document.getElementById('nameregValidation').innerText = 'ok!';
        } else {
            document.getElementById('nameregValidation').innerText = 'namereg address is incorrect!';
        }
        return ok;
    };
    function onNameregKeyUp() {
        updateIBAN(validateNamereg());
        onExchangeKeyUp();
    };

    function validateExchange() {
        var exchange = document.getElementById('exchange').value;
        var ok = /^[0-9A-Z]{4}$/.test(exchange);
        if (ok) {
            var address = namereg.addr(exchange);
            deposit = Deposit.at(address);
            document.getElementById('exchangeValidation').innerText = 'ok! address of exchange: ' + address;
        } else {
            document.getElementById('exchangeValidation').innerText = 'exchange id is incorrect';
        }
        return ok;
    };
    function onExchangeKeyUp() {
        updateIBAN(validateExchange());
    };
    function validateClient() {
        var client = document.getElementById('client').value;
        var ok = /^[0-9A-Z]{9}$/.test(client);
        if (ok) {
            document.getElementById('clientValidation').innerText = 'ok!';
        } else {
            document.getElementById('clientValidation').innerText = 'client id is incorrect';
        }
        return ok;
    };
    function onClientKeyUp() {
        updateIBAN(validateClient());
    };
    function validateValue() {
        try {
            var value = document.getElementById('value').value;
            var bnValue = new BigNumber(value);
            document.getElementById('valueValidation').innerText = bnValue.toString(10);
            return true;
        } catch (err) {
            document.getElementById('valueValidation').innerText = 'Value is incorrect, cannot parse';
            return false;
        }
    };
    function onValueKeyUp() {
        validateValue();
    };
    function validateIBAN() {
        if (!iban.isValid()) {
            return document.getElementById('ibanValidation').innerText = ' - IBAN number is incorrect';
        }
        document.getElementById('ibanValidation').innerText = ' - IBAN number correct';
    };
    function updateIBAN(ok) {
        var exchangeId = document.getElementById('exchange').value;
        var clientId = document.getElementById('client').value;
        iban = web3_hpb.hpb.iban.createIndirect({
            institution: exchangeId,
            identifier: clientId
        });
        document.getElementById('iban').innerText = iban.toString();
        validateIBAN();
    };
    function transfer() {
        var value = new BigNumber(document.getElementById('value').value);
        var exchange = document.getElementById('exchange').value;
        var client = document.getElementById('client').value;
        deposit.deposit(web3_hpb.fromAscii(client), {value: value});
        displayTransfer("deposited client's " + client + " funds " + value.toString(10) + " to exchange " + exchange);
    };
    function displayTransfer(text) {
        var node = document.createElement('li');
        var textnode = document.createTextNode(text);
        node.appendChild(textnode);
        document.getElementById('transfers').appendChild(node);
    }

</script>
</head>
<body>
    <div class="col-lg-12">
        <i>This page expects ghpb with JSON-RPC running at port 8545</i>
        <div class="page-header">
            <h1>ICAP transfer</h1>
        </div>
        <div class="col-lg-6">
            <div class="well">
                <legend class="lead">namereg address</legend>
                <small>eg. 0x436474facc88948696b371052a1befb801f003ca or 'default')</small>
                <div class="form-group">
                    <input class="form-control" type="text" id="namereg" onkeyup='onNameregKeyUp()' value="default"></input>
                    <text id="nameregValidation"></text>
                </div>

                <legend class="lead">exchange identifier</legend>
                <small>eg. WYWY</small>
                <div class="form-group">
                    <input class="form-control" type="text" id="exchange" onkeyup='onExchangeKeyUp()'></input>
                    <text id="exchangeValidation"></text>
                </div>

                <legend class="lead">client identifier</legend>
                <small>eg. GAVOFYORK</small>
                <div class="form-group">
                    <input class="form-control" type="text" id="client" onkeyup='onClientKeyUp()'></input>
                    <text id="clientValidation"></text>
                </div>

                <legend class="lead">value</legend>
                <small>eg. 100</small>
                <div class="form-group">
                    <input class="form-control" type="text" id="value" onkeyup='onValueKeyUp()'></input>
                    <text id="valueValidation"></text>
                </div>

                <legend class="lead">IBAN: </legend>
                <div class="form-group">

                    <text id="iban"></text>
                    <text id="ibanValidation"></text>
                </div>
                <div>
                    <button class="btn btn-default" id="transfer" type="button" onClick="transfer()">Transfer!</button>
                    <text id="transferValidation"></text>
                </div>
            </div>
        </div>
        <div class="col-lg-6">
            <div class="well">
                <div>
                    <legend class="lead">transfers</legend>
                </div>
                <div>
                    <ul id='transfers'></ul>
                </div>
            </div>
        </div>
    </div>
</body>
</html>

3.6 namereg

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
<!DOCTYPE html>
<html>

<head>
<script type="text/javascript" src="../dist/web3_hpb.js"></script>
<script type="text/javascript">
    var web3_hpb = require('web3_hpb');
    var web3_hpb = new web3_hpb();
    web3_hpb.setProvider(new web3_hpb.providers.HttpProvider("http://localhost:8545"));
    var from = web3_hpb.hpb.coinbase;
    web3_hpb.hpb.defaultAccount = from;
    window.onload = function () {
        var filter = web3_hpb.hpb.namereg().Changed();
        filter.watch(function (err, event) {
            // live update all fields
            onAddressKeyUp();
            onNameKeyUp();
            onRegisterOwnerKeyUp();
        });
    };
    function registerOwner() {
        var name = document.getElementById('registerOwner').value;
        web3_hpb.hpb.namereg().reserve(name);
        document.getElementById('nameAvailability').innerText += ' Registering name in progress, please wait...';
    };

    function changeAddress() {
        var name = document.getElementById('registerOwner').value;
        var address = document.getElementById('newAddress').value;
        web3_hpb.hpb.namereg().setAddress(name, address, true);
        document.getElementById('currentAddress').innerText += ' Changing address in progress. Please wait.';
    };
    function onRegisterOwnerKeyUp() {
        var name = document.getElementById('registerOwner').value;
        var owner = web3_hpb.hpb.namereg().owner(name)
        document.getElementById('currentAddress').innerText = web3_hpb.hpb.namereg().addr(name);
        if (owner !== '0x0000000000000000000000000000000000000000') {
            if (owner === from) {
                document.getElementById('nameAvailability').innerText = "This name is already owned by you " + owner;
            } else {
                document.getElementById('nameAvailability').innerText = "This name is not available. It's already registered by " + owner;
            }
            return;
        }
        document.getElementById('nameAvailability').innerText = "This name is available. You can register it.";
    };
    function onAddressKeyUp() {
        var address = document.getElementById('address').value;
        document.getElementById('nameOf').innerText = web3_hpb.hpb.namereg().name(address);
    };

    function onNameKeyUp() {
        var name = document.getElementById('name').value;
        document.getElementById('addressOf').innerText = web3_hpb.hpb.namereg().addr(name);
    };
</script>
</head>
<body>
    <i>This example shows only part of namereg functionalities. Namereg contract is available <a href="https://github.com/hpber/dapp-bin/blob/master/GlobalRegistrar/contract.sol">here</a>
    </i>
    <h1>Namereg</h1>
    <h3>Search for name</h3>
    <div>
        <text>Address: </text>
        <input type="text" id="address" onkeyup='onAddressKeyUp()'></input>
        <text>Name: </text>
        <text id="nameOf"></text>
    </div>
    <h3>Search for address</h3>
    <div>
        <text>Name: </text>
        <input type="text" id="name" onkeyup='onNameKeyUp()'></input>
        <text>Address: </text>
        <text id="addressOf"></text>
    </div>
    <h3>Register name</h3>
    <div>
        <text>Check if name is available: </text>
        <input type="text" id="registerOwner" onkeyup='onRegisterOwnerKeyUp()'></input>
        <text id='nameAvailability'></text>
    </div>
    <div>
        <button id="registerOwnerButton" type="button" onClick="registerOwner()">Register!</button>
    </div>
    <h3></h3>
    <i>If you own the name, you can  also change the address it points to</i>
    <div>
        <text>Address: </text>
        <input type="text" id="newAddress"></input>
        <button id="changeAddress" type="button" onClick="changeAddress()">Change address!</button>
        <text>Current address :</text>
        <text id="currentAddress"></text>
    </div>

</body>
</html>

3.7 node-app

1
2
3
4
5
6
7
8
9
10
11
12
#!/usr/bin/env node

var web3_hpb = require('../index.js');
var web3_hpb = new web3_hpb();

web3_hpb.setProvider(new web3_hpb.providers.HttpProvider('http://localhost:8545'));

var coinbase = web3_hpb.hpb.coinbase;
console.log(coinbase);

var balance = web3_hpb.hpb.getBalance(coinbase);
console.log(balance.toString(10));

3.8 signature-verifier

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
var web3_hpb = require('../index.js');
var hpbURL = "";
var defaultAc = "";
var defaultAcPWD="";
var signatureContractCodeReadable="\n\tcontract SignatureVerifier {\n\t\tfunction verify( bytes32 hash, uint8 v, bytes32 r, bytes32 s) \n"+
    "\t\tconstant returns(address returnAddress) {\n \t\t\treturnAddress = ecrecover(hash, v, r, s);\n\t\t}\n\t}\n\n";

var sigContractInstance = null;
var sigContractAddress= "";
var sigContractInstance = null;
var strAbi='[{"constant":true,"inputs":[{"name":"hash","type":"bytes32"},{"name":"v","type":"uint8"},{"name":"r","type":"bytes32"},{"name":"s","type":"bytes32"}],"name":"verify","outputs":[{"name":"returnAddress","type":"address"}],"payable":false,"type":"function"}]';
var signMessage="";

var hpbweb3_hpb = null;

function setContractAddress(conAddress){
    sigContractAddress = conAddress;
}

function setAccount(act){
    defaultAc = act;
}

function setPassword(pwd){
    defaultAcPWD = pwd;
}

function setHpbURL(url){
    hpbURL = url;
}

function setMessage(msg){
    signMessage = msg;
}

function initializeHpbConnection(){
   if(hpbweb3_hpb!=null && hpbweb3_hpb.isConnected()==true)  {
    return true;
  }

  hpbweb3_hpb = new web3_hpb(new web3_hpb.providers.HttpProvider(hpbURL));

  if(hpbweb3_hpb.isConnected()==true){
      if(defaultAc==''){
        defaultAc=hpbweb3_hpb.hpb.accounts[1];
      }
      return true;
  }

  return false;
}

function unlockAccount(acAddress){
  if(acAddress!=undefined && acAddress!=null){
    var state=hpbweb3_hpb.personal.unlockAccount(defaultAc, defaultAcPWD, 100);
    return state;
  }

  return false;
}


function initializeContract(){
    initializeHpbConnection();
    if(hpbweb3_hpb.isConnected()==false){
        return;
    }
    var abi = JSON.parse(strAbi);
    var contract = hpbweb3_hpb.hpb.contract(abi);

    sigContractInstance =  contract.at(sigContractAddress)
}

function signMessage(message){

    initializeHpbConnection();
    if(hpbweb3_hpb.isConnected()==false){
        return false;
    }

    var state=unlockAccount(defaultAc);

    const msg = new Buffer(message);
    const sig = hpbweb3_hpb.hpb.sign(defaultAc, '0x' + msg.toString('hex'));

    return sig;
}

function verifySignedByAc(message, sig){
    initializeHpbConnection();

    if(hpbweb3_hpb.isConnected()==false){
        return false;
    }
    initializeContract();

    const res = splitSig(sig);

    // Unfortunately Ghpb client adds this line to the message as a prefix while signing
    // So while finding who signed it we need to prefix this part 
    const prefix = new Buffer("\x19Hpb Signed Message:\n");
    const msg = new Buffer(message);
    const prefixedMsg = hpbweb3_hpb.sha3(
    Buffer.concat([prefix, new Buffer(String(msg.length)), msg]).toString('utf8')
    );

    var strPrefixedMsg=prefixedMsg;

    var finalAddress=sigContractInstance.verify.call(strPrefixedMsg, res.v, res.r, '0x'+ res.s);

    return finalAddress;
}

function splitSig(sig) {
  return {
    v: hpbweb3_hpb.toDecimal('0x' + sig.slice(130, 132)),
    r: sig.slice(0, 66),
    s: sig.slice(66, 130)
  }

}

function sign(){
    var message = document.getElementById('txtMessage').value;
    var signMsg = signMessage(message);
    document.getElementById('dvSig').innerText = signMsg;
}

function verify(){
    var message = document.getElementById('txtMessage').value;
    var actAddr = verifySignedByAc(message, document.getElementById('dvSig').innerText);
    document.getElementById('dvSignedBy').innerText = actAddr;
}


function execute(){
    console.log("\n\n**********************************************************************");
    console.log("Steps to Run");
    console.log("**********************************************************************");
    console.log("1. Deploy the following contract in your hpber environment");
    console.log(signatureContractCodeReadable);
    console.log("2. Set the following parameters (i.e. at the end of the code)");
    console.log("\ta. Hpb URL");
    console.log("\tb. Hpb Account Address");
    console.log("\tc. Hpb Account Passphrase");
    console.log("\td. Signature Contract Address");
    console.log("\te. Message for signing");
    console.log("**********************************************************************");

    if(hpbURL==''){
        console.log("Error: Hpb URL is not specified");
        return;
    }
    if(defaultAc==''){
        console.log("Error: Account Address is not specified");
        return;
    }
    if(defaultAcPWD==''){
        console.log("Error: Account password is not specified");
        return;
    }
    if(sigContractAddress==''){
        console.log("Error: Signature Contract Address is not specified");
        return;
    }
    if(signMessage==''){
        console.log("Error: Message for signing is not specified");
        return;
    }


    console.log("Following parameters applied");
    console.log("\ta. Hpb URL                  :",hpbURL);
    console.log("\tb. Hpb Account Address      :",defaultAc);
    console.log("\tc. Hpb Account Passphrase   :",defaultAcPWD);
    console.log("\td. Signature Contract Address    :",sigContractAddress);
    console.log("\te. Message for signing           :",signMessage);

    console.log("**********************************************************************");
    console.log("Result");
    console.log("**********************************************************************");

    var sig=signMessage(signMessage);
    console.log("Signature");
    console.log(sig);

    var addr=verifySignedByAc(signMessage, sig);
    console.log("Signed By");
    console.log(addr);

    console.log("**********************************************************************");
    console.log("Exit");
    console.log("**********************************************************************");
}

// Please uncomment the below listed three lines of code and provide the required values

// Value 1- Please provide the hpber account address which you want to use to perform the operation
//setAccount('<Provide the account address>');

// Value 2- Please provide the password of the accound to be used 
//setPassword('<Provide the password>');

// Value 3- Please update the address of the contract after deployment
// The contract code is made available at the top under signatureContractCodeReadable variable
// Please deploy the contract and update the contract address here
//setContractAddress('<Provide the deployed contract address>');

// Value 4- If required please update with a different message
setHpbURL('http://localhost:8545');

// Value 5- If required please update with a Hpb URL
setMessage('This the test sign message');


execute();

感谢HPB技术团队整理。

HPB73:HPB P2P网络介绍

1 P2P网络介绍

​ 对等网络(P2P网络)是分布式系统和计算机网络相结合的产物。可以定义为:网络的参与者共享他们所拥有的一部分硬件资源(处理能力,存储能力,网络连接能力,打印机等),这些共享资源通过 网络提供服务和内容,能被其他对等节点直接访问而无需经过中间实体。在此网络中的参与者即是资源,服务和内容的提供者,又是资源,服务和内容的获取者。

​ 在HPB主网网络中,是由运行HPB公链程序的计算机作为单个节点,这些节点通过网络连接在一起组成P2P网络,提供网络连接,数据库存储和处理能力(例如挖矿和共识,执行合约等)。

​ 下面对HPB主网的网络结构图和组成网络的节点进行介绍。

2 P2P网络的特点

P2P网络是对分布式概念的拓展,相较于传统方式下的集中式网络,其特点主要体现在以下几个方面

非中心化:网络中的资源和服务分散在所有节点上,信息的传输和服务器的实现都直接在节点之间进行,可以无需中间环节和服务器的介入。

可扩展性:在P2P网络中,节点可以很容易的接入和删除,随着节点的增加,系统整体的资源和服务能力也在同步的扩充,理论上其扩展性可以认为是无限的。

健壮性:P2P网络由于是由对等的网络节点组成的,服务也是分散在各个节点之间进行的,即使部分节点遭到破坏,对整个网络的影响也是很小的。

最终一致性:在共识算法的作用下,每个节点都要求自身的数据库与主网其他节点保持一致,因此,在不断的同步和转发过程中,各节点的数据库将最终保持一致。

3 P2P网络图

​ 下图是HPB主网的P2P网络的网络结构图。从图中可以看出,各个节点之间除了bootnode与bootnode之间,snode与snode不会相互连接之外,其他的节点之间都会进行连接。在HPB主网中根据共识算法将node节点区分为3种不同的类型,其中图中Bnode代表静态节点bootnode,hnode代表高性能节点,pnode代表候选节点,snode代表同步节点。关于3种节点类型的产生将在下节介绍。

node

4 节点介绍

在P2P网络中,从节点通信方式上看,可以分成两类:邻居节点和Peer节点

邻居节点

邻居节点是指通过了udp ping-pong通信的节点,udp ping-pong通信用于检测对方节点是否在线。

peer节点

peer是网络中通过了通信握手的节点,只有邻居节点才有可能称为peer节点。通信握手是为了确认对方节点的合法性。peer节点是相互的,A节点是B节点的peer,则B节点也会是A节点的peer。在P2P网络中,每一个新接入的节点都有可能节点的peer。

从共识角度看,节点可以分成3类:高性能节点(hpnode),候选节点(prenode),同步节点(synnode)

高性能节点(hpnode):从候选节点中选举出来的,用于生成区块,目前数量最大为31个。

候选节点(prenode):由社区投票产生。

同步节点(synnode):仅用于同步数据库,不参与选举和产生区块。

备注:高性能节点和候选节点都是带有boe的节点。

5 节点管理

​ 在P2P网络中,节点可以自由的加入或退出网络,这就需要各个节点能够管理其他的节点信息。包括节点是发现其他节点的,如何添加节点和删除节点的。

6 节点发现

​ 由于P2P网络本身并没有一个中心化的服务器用于连接,因此一个新节点想要加入到P2P网络中,必须知道P2P网络中的节点信息。因此,为了新节点能够接入到网络中,在节点启动的时候查找静态节点信息,并通过连接静态节点的方式接入网络,然后通过与静态节点(bootnode)的交互获取到网络中的其他节点信息。静态节点是指所有节点启动都要先连接的节点,节点信息是直接写入到代码里的。下面是节点发现的时序图:

reqnodemsg

上图中nodeA已与bootnode节点建立连接,连接过程与其他节点的连接是一样的,具体过程参考下一节。

7 节点添加

7.1 添加邻居节点

​ 在节点发现阶段,连接静态节点成功后,新节点会向bootnode请求bootnode自身的邻居节点信息,然后针对bootnode返回的节点信息,一一进行udp ping-pong请求。如果通信正常,则将该节点信息加入到邻居节点中。请参考下图

nodeA-nodeB

7.2 添加peer节点

​ 前文介绍了邻居节点是怎么来的,这个过程是持续不断的进行的。节点启动后,也会不断的检查bootnode列表与邻居节点列表,并将未连接的节点信息取出来,进行握手通信。连接成功后,将节点信息加入peers节点列表,使用admin.peers命令查看到的就是这里的peers节点列表。三次握手通信具体过程请参考下图,握手过程中只要出错,则此次连接就算失败,然后等待一段时间后重新发起握手通信。

connect

​ 第一次握手:节点生成认证信息发送给对方。

​ 第二次握手:收到对方的认证信息使用boe进行签名(没有boe就不签名)并发送给对方,并校验对方发送过来的签名是否是使用boe签名。如果不是boe签名或者对方节点信息没在硬件信息表中,就可以认为对方是snode。

​ 第三次握手:更新硬件信息表。

​ 以上3步完成后,nodeA节点将nodeB节点添加到自己的peers列表中,同理,nodeB也同样将nodeA添加到自己的peers列表中。至此,nodeA与nodeB的连接成功,添加节点完成,

8 节点删除

​ 节点能添加就能删除。下面介绍下将对方节点会从peers中删除的几种情况。

​ 1.校验genesis失败的时候。

​ 2.同步数据的时候,对方发送的区块信息不合法的时候,会主动断开连接,删除peer。

​ 3.在进行网络通信如发送数据失败的时候和读取数据失败的时候。

​ 4.收到对方节点发来的断开连接的请求时。

9 数据转发规则

​ 在HPB主网的P2P网络中,由于每个节点都尽可能多的连接着其他的节点,为了保证数据的最终一致性,每个节点都有责任将自身产生或者接收到其他节点的数据转发给其他节点。

​ 从数据的转发方式上又可以分为两种。一种是定向发送即一对一,一种是广播发送即一对多。

​ a.定向发送:例如节点的数据同步,请求节点和发送节点是一对一的。

​ b.广播发送:例如节点在校验新的交易和新的区块通过后,通过广播的方式发送给连接的所有节点。在HPB主网中为了节省带宽,降低数据冗余,提高公链性能,根据节点类型对转发规则进行了优化。规则如下:

​ 针对新交易:

​ 当前节点是snode:将交易广播给pnode节点和hnode节点

​ 当前节点是pnode:将交易广播给pnode节点和hnode节点

​ 当前节点是hnode:将交易广播给hnode节点。

​ 针对新区块:

​ 当前节点是snode:不需要广播新块出去。

​ 当前节点是pnode:将新块广播给pnode节点和snode节点。

​ 当前节点是hnode:将新块广播给hnode节点和pnode节点。

​ 在以上规则中,主要是减少了高性能节点hnode产生的新块的转发量,来提高hnode的性能。

10 总结

​ 从上文了解到的信息,可以和其他公链的区块链做个比较,以以太坊为例,两者在P2P网络方面是大同小异,HPB在P2P网络方面主要有2个不同点,可以说是根据自身的节点特性做的调整:

​ 1、节点类型的划分,通过在节点连接的三次握手环节,增加boe签名和验签,判断对方节点是否属于同步节点,如果自己也是同步节点,就可以减少无用的连接。

​ 2、在区块广播方面,以太坊每次广播的节点是peers列表中前连接数的平方根个节点,最坏的情况下会出现区块只在小范围的节点之间传播,而HPB根据节点类型的广播则不会出现这种情况。

​ 以上就是对HPB主网的P2P网络的简单介绍。

感谢HPB技术团队整理。

HPB72:HPB共识算法选举机制描述

简介

为了适应BOE技术的要求,同时尽可能的提升安全TPS, HPB共识算法采用了高效的双层选举机制,即外层选举和内层选举。

外层选举:由具有BOE板卡的所有用户中选取出。选取周期为3个月。选取方式为通过HPB钱包进行投票选举。

内层选举:采用节点贡献值评价指标,从众多候选节点中选出高贡献值节点成员。基于Hash队列记名投票机制,在每次区块生成时,计算高贡献值节点生成区块的优先级,优先级高的高贡献值节点享有优先生成区块的权利。

在整个共识算法设计中, HPB共识算法的轻量级消息交换机制使其在共识效率上远高于其他共识算法, 同时在安全性,隐私性等方面也做了较大幅度的提升。

外层选举

由于在申请BOE板卡时已经考虑了除用户持币量的其他因素,所以外层选举在钱包投票节点主要考虑持币量的因素,以及用户的认可度,用户认可度高,则用户会对他进行投票,反之则投票数量少。

注1:如果具有BOE的用户较多,会存在一定数量的用户在外层选举中落选。落选的用户仍然可以入网,但是不会作为候选节点或者高性能节点,并且也不会收到奖励。

内层选举

本文重点关注内层选举。将会详细描述内层选举的实现方式和关键因素。

选举包括2部分,首先是投票节点,然后是唱票阶段。

关键因素

内层选举阶段发生在网络运行中的特定阶段,每间隔一定数量的区块进行一次选举,并且根据关键因素进行排名,选择优秀的节点进行投票。

节点带宽:在节点运行期间,节点会定期测试与其他节点间的带宽数据,并保存在节点中,提供给共识使用,节点的带宽数据会记录在区块中。

用户持币量:用户在投票时的持币数量。

投票数量:外层选举过程中用户节点获得的投票数量。

投票规则

节点根据外层选举得出的节点数据为集合,根据关键因素的排名加权选择最优节点,进行投票。为了保证选举结果数量,在投票过程中进行了随机化操作,并不是在所有的外层选举集合内进行最有选择,而是随机选择出特定数量的集合,然后选择最优节点投票。这个目的是保证选举结果的数量达到稳定值,保证网络的稳定性,并且排除节点排名较靠后的节点。

唱票

已经有了投票的基础数据后,在特定阶段环节进行唱票工作,所有节点在唱票阶段通过读取区块进行唱票,将区块中所有的投票数据提取出来进行统计。在投票阶段会将投票的数据写入voteIndex。

唱票规则

将获得投票的所有节点作为一个集合,从中选出特定数量的节点,作为下一轮的高性能节点。因此需要对该结合中的节点进行排名操作,排名的依据是voteIndex的均值。

最后

在注2中可以看到几个与次文关系较密切的字段,分别是candAddress,miner以及voteIndex。

miner:产生区块的节点。

candAddress:是由miner根据内层选举的3个关键因素确定的。

voteIndex:是candAddress所对应的因素加权结果值。

从投票到唱票的所有环节,所有节点均存在校验机制,确保节点无法进行虚假投票和唱票,如果投票伪造,则该区块会被其他节点拒收;如果唱票伪造,则会被其他节点踢出网络。

注2:区块部分内容。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
{
**candAddress: “0x4a8111ecec1f9150d366ae319d0585303085748f”**,
comdAddress: “0x4a8111ecec1f9150d366ae319d0585303085748f”,
difficulty: 2,
extraData: “0x00000000000…”,
gasLimit: 100000000,
gasUsed: 0,
hardwareRandom: “0x2bce19ff44fbf1b05edfb93fcb7c7d3ab04c50fd7dc947e2fce65d66493d0dff”,
hash: “0x1fceb9c0d5a822fdddaa72bb9378f5ce24cd168b0281082a83d8f3a00c62d79a”,
logsBloom: “0x00000000000…”,
**miner: “0x4a8111ecec1f9150d366ae319d0585303085748f”**,
mixHash: “0x0000000000000000000000000000000000000000000000000000000000000000”,
nonce: “0x0000000000000000”,
number: 100,
parentHash: “0xab7299002317fecbfdd835b28bacb470e24a7933b41102f75cb76491957baa98”,
receiptsRoot: “0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421”,
sha3Uncles: “0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347”,
size: 683,
stateRoot: “0xc46fc99654813b2f92e9be58f7e69957499fa2c9b1c0ac31d1da86679f3b9a62”,
timestamp: 1541416798,
totalDifficulty: 201,
transactions: [],
transactionsRoot: “0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421”,
uncles: [],
**voteIndex: "0x0"**
}

具体投票机制可能根据最新的需求会调整,请及时参考最新的代码

感谢HPB技术团队整理。

HPB71:如何在HPB主网上发布智能合约

1 概述

1.1 前言

本文档主要通过实例指导如何在HPB主网上发布智能合约教程。

文档阅读人员:社区开发人员、测试人员、运维人员。

1.2 学习准备

1.2.1 Solidity语言

Solidity是一种开源的智能合约高级语言,可以运行支持开源的Ethereum虚拟机(EVM)之上。 具体的语言介绍和学习入门,在以下的网址中有详细介绍: https://solidity.readthedocs.io/en/v0.5.2/

1.2.2 Remix

支持智能合约开发IDE,可以在浏览器中快速部署测试智能合约,支持Solidity语言。 访问和使用地址: http://remix.ethereum.org

1.2.3 HPB主链接入指导

详情请前往HPB官网的接入详情界面,会指导你如何通过RPC,SDK等方式和主链交互。 https://www.hpb.io/client

1.2.4 智能合约Demo地址

https://github.com/loglos/web3-hpb-test.git

2 开发智能合约

2.1 环境准备

2.1.1 通过在线Remix在线编译器进行智能合约开发

请访问链接进行智能合约开发http://remix.ethereum.org 具体智能合约的开发请见第3章节

2.1.2 通过下载Remix开源代码搭建本地开发环境

下载地址:https://github.com/ethereum/remix-ide

  • 安装步骤

nstall npm and node.js (see https://docs.npmjs.com/getting-started/installing-node), then do:

Remix-ide has been published as an npm module:

1
2
npm install remix-ide -g
remix-ide

Or if you want to clone the github repository (wget need to be installed first) :

1
2
3
4
5
6
git clone https://github.com/ethereum/remix-ide.git
git clone https://github.com/ethereum/remix.git # only if you plan to link remix and remix-ide repositories and develop on it.
cd remix-ide
npm install
npm run setupremix  # only if you plan to link remix and remix-ide repositories and develop on it.
npm start
  • DEVELOPING:

Run npm start and open http://127.0.0.1:8080 in your browser.

Then open your text editor and start developing. The browser will automatically refresh when files are saved.

Most of the the time working with other modules (like debugger etc.) hosted in the Remix repository is not needed.

Troubleshooting building Some things to consider if you have trouble building the package:

Make sure that you have the correct version of node, npm and nvm. You can find the version that is tested on Travis CI by looking at the log in the build results. Run:

1
2
3
node --version
npm --version
nvm --version

In Debian based OS such as Ubuntu 14.04LTS you may need to run apt-get install build-essential. After installing build-essential run npm rebuild.

  • Unit Testing Register new unit test files in test/index.js. The tests are written using tape.

Run the unit tests via: npm test

For local headless browser tests run npm run test-browser (requires Selenium to be installed – can be done with npm run selenium-install)

Running unit tests via npm test requires at least node v7.0.0

  • Browser Testing

To run the Selenium tests via Nightwatch serve the app through a local web server:

1
npm run serve # starts web server at localhost:8080

Then you will need to either:

1.Have a Selenium server running locally on port 4444.

1
   Run: npm run test-browser

2.Or, install and run SauceConnect.

1
2
   Run: sc -u <USERNAME> -k <ACCESS_KEY> (see .travis.yml for values)
   Run: npm run browser-test-sc
  • Usage as a Chrome Extension

If you would like to use this as a Chrome extension, you must either build it first or pull from the gh-pages branch, both described above. After that, follow these steps:

1
2
3
4
1.Browse to chrome://extensions/
2.Make sure 'Developer mode' has been checked
3.Click 'Load unpacked extension...' to pop up a file-selection dialog
4.Select your remix-ide folder
  • Documentation

To see details about how to use Remix for developing and/or debugging Solidity contracts, please see our documentation page https://remix.readthedocs.io/en/latest/

2.3 使用Remix进行开发智能合约

2.3.1 合约准备

这里提供了一份发行ERC20标准token的合约代码。 见文章末尾附件(1)

打开solidity智能合约在线编译器或者本地编辑器:

https://remix.ethereum.org/#optimize=true&version=soljson-v0.4.11+commit.68ef5810.js

粘贴代码到编辑器中,选择编译器编译版本为合约代码中指定的版本。

2.3.2 重新编译ERC20 Token源代码

重新编译ERC20源代码,然后复制编译通过的代码的ABI数据,为后续部署到HPB主链做准备。

点击查看详情

2.3.3 发布合约到HPB主链

发布合约到HPB主链,有两种方式,一种是通过HPB官方提供JAVA SDK来发布;一种是通过安装节点后通过命令行来发布。

2.3.3.1 准备环境

通过JAVA SDK发布智能合约教程,请见HPB主网最佳实践之JAVA版本。

文章链接: http://192.168.1.1 请参加Java最佳实践这篇文章。

演示工程代码下载地址: https://github.com/loglos/web3-hpb-test.git

这里提醒开发者,需要新建合约对应的智能合约代码对应的 “.abi”和 “.bin” 文件并把以上复制的abi和bin代码复制到对应的该文件中。 这里再简单讲解下关键代码。

源码工程下载后需要转为maven类型工程,注意在pom.xml文件中,引入了JAVA SDK的包。 这里提醒下,请使用最新的2.0.3版本,修复了一些生程Java代码的缺陷。

1
2
3
4
5
6
<dependency>
          <groupId>io.hpb.web3</groupId>
          <artifactId>web3-hpb</artifactId>
          <version>2.0.3</version>
</dependency>

2.3.3.2 演示源码说明

演示的程序在这个package下面

1
2
package io.hpb.web3.test;

package里面演示的Demo java类这里进行下说明

  • UFOToken.sol:本次演示的ERC20的智能合约源码
  • UFOToken.abi:智能合约编译后的abi源码
  • UFOToken.bin:智能合约编译后的bin文件
  • UFOTokenRun.java:Java生成智能合约对象类的执行类
  • UFOToken.java:系统自动生成的智能合约映射的java源码。

2.3.3.2 UFOTokenRun执行说明

开发者可以直接执行UFOTokenRun.java里面的main方法,来进行调试。 其中相关的地址的路径,请根据自身的开发环境的实际调用地址和HPB账号信息填写

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
package io.hpb.web3.test;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Arrays;

import io.hpb.web3.codegen.SolidityFunctionWrapperGenerator;
import io.hpb.web3.crypto.Credentials;
import io.hpb.web3.crypto.WalletUtils;
import io.hpb.web3.protocol.Web3;
import io.hpb.web3.protocol.Web3Service;
import io.hpb.web3.protocol.admin.Admin;
import io.hpb.web3.protocol.core.DefaultBlockParameterName;
import io.hpb.web3.protocol.core.methods.response.TransactionReceipt;
import io.hpb.web3.protocol.http.HttpService;
import io.hpb.web3.tx.ChainId;
import io.hpb.web3.tx.RawTransactionManager;
import io.hpb.web3.utils.Convert;
import okhttp3.OkHttpClient;
import io.hpb.web3.abi.datatypes.Address;
import io.hpb.web3.abi.datatypes.generated.Uint256;

public class UFOTokenRun {

  
  //发布智能合约账号的,keystore全路径,请根据实际地址来修改        
  private static String keyStoreAbsolutePath = "/path/UTC--2018-5cb988b9ce48fd3b5a328b582dd64f5c10d0e114"; 
  //发布智能合约的账号密码,请使用你自己的账号和密码
  private static String fromPassword = "demo111";
    //发布智能合约的地址:这是目前已发布到主网的UFOToken智能合约地址,用户可以进行查询,但是不能转账,转账需要有HPB余额才能转账
  private static String address = "0xfbbe0ba33812b531aced666d0bb2450216c11d11";
    //开放的HPB节点URL地址,也可以自行搭建节点;此节点是HPB正式网开放的节点
  private static String blockChainUrl = "http://pub.node.hpb.io/";
    
  //系统默认参数设置
  private static BigInteger GAS_PRICE = new BigInteger("18000000000");

  private static BigInteger GAS_LIMIT = new BigInteger("100000000");
    
    
  public static void main(String[] args) {
 
    //指定生成智能合约java映射类的package路径
      String packageName = "io.hpb.web3.test";
    //指定生成智能合约java映射类源码的本地存放地址
      String outDirPath = "//erc20//UFO//java";
      
      //指定智能合约源码的本地地址,这两个文件也放在本类的package下面,读者可以自行处理
      String binFilePath = "//erc20//UFO//bin//UFOToken.bin";
      String abiFilePath = "//erc20//UFO//bin//UFOToken.abi";


        
      //1、通过io.hpb.web3来生成智能合约sol源码的的映射类;然后把映射的类放到对应的package中
      GenContractJavaCode(packageName, binFilePath, abiFilePath, outDirPath) ;


        //2、发布智能合约,并好获取地址
      String address = depolyUFOTokenTest();
      
      //3、得到智能合约的余额
      getUFOTokenContractBalance();
      
  
      //查询指定地址的erc20余额
      String  queryAddress = "0xd8ACcED8A7A92b334007f9C6127A848fE51D3C3b";
      //4、校验智能合约并打印相关的信息    
      checkUFOTokenContract(queryAddress);
      
      
      //5、转账
      String  toAddress = "0x6cb988b9ce48Fd3b5a328B582dd64F5C10d0E114";
      transferUFOTokenContract(toAddress,"13333333000000000000000000");
 
      //5.2 查询余额
      //checkUFOTokenContract(contractAddress,toAddress);
      
  }
  

  /**
   * 通过智能合约的源码.sol文件和编译后的.bin文件生成java的源码
   * String packageName:java源码的packagename
   * String binFileName:存放智能合约bin文件地址
   * String abiFileName:存放智能合约的abi文件地址
   * String outDirPath :java源码输出地址 
   * 
   * **/
  public static void GenContractJavaCode(String packageName,String binFilePath,String abiFilePath,String outDirPath) {
         try {
              String SOLIDITY_TYPES_ARG = "--solidityTypes";
              
              SolidityFunctionWrapperGenerator.main(Arrays.asList(SOLIDITY_TYPES_ARG,
                      binFilePath,abiFilePath,"-p",packageName, "-o", outDirPath).toArray(new String[0]));
          } catch (Exception e) {
              e.printStackTrace();
          }

  }

  


  /**
   * 通过编译智能合约源码得到合约映射的java类
   * 
   * **/
  public static String depolyUFOTokenTest(){
  
      Credentials credentials = null;
      Admin admin = null;

        String contractAddress =  "";
      try{
          Web3Service web3Service = new HttpService(blockChainUrl, new OkHttpClient.Builder().build(), true);
          admin = Admin.build(web3Service);
          credentials = WalletUtils.loadCredentials(fromPassword, keyStoreAbsolutePath);
          RawTransactionManager transactionManager=new RawTransactionManager(admin, credentials, ChainId.MAINNET);

          // 1.发布 TOKEN
          UFOToken contract = UFOToken.deploy(admin, transactionManager, GAS_PRICE, GAS_LIMIT).send();
          System.out.println("合约地址:" + contract.getContractAddress());
          contractAddress = contract.getContractAddress();
    
      }catch (Exception e){
          e.printStackTrace();
      }
      return contractAddress;
  }
  
  
  /**
   * 查询余额
   * 
   * **/
  public static BigDecimal getUFOTokenContractBalance(){
      
      Credentials credentials = null;
      Admin admin = null;
      BigDecimal balanceWeiAmt = null;

      try{
          
          Web3Service web3Service = new HttpService(blockChainUrl, new OkHttpClient.Builder().build(), true);
          admin = Admin.build(web3Service);
    
          BigInteger balance = admin.hpbGetBalance(address, DefaultBlockParameterName.LATEST).send().getBalance();
          balanceWeiAmt = Convert.fromWei(balance.toString(), Convert.Unit.HPB);
          System.out.println(address + "账户余额:" + balanceWeiAmt);
 
      }catch (Exception e){
          e.printStackTrace();
      }
      
      return balanceWeiAmt;
  }
  
  
  
  /**
   * 校验智能合约并打印地址ERC20余额
   * 
   * **/
  public static void checkUFOTokenContract(String queryAddress){
       
      Credentials credentials = null;
      Admin admin = null;
      
      try{
          
          Web3Service web3Service = new HttpService(blockChainUrl, new OkHttpClient.Builder().build(), true);
          admin = Admin.build(web3Service);
          credentials = WalletUtils.loadCredentials(fromPassword, keyStoreAbsolutePath);
          RawTransactionManager transactionManager=new RawTransactionManager(admin, credentials, ChainId.MAINNET);
          
          //检查合约是否可用

          UFOToken contract = UFOToken.load(address, admin, transactionManager, GAS_PRICE, GAS_LIMIT);
          System.out.println("验证合约是否有效:" +contract.isValid() );
          if(contract.isValid()) {
              BigInteger totalSupply = contract.totalSupply().send().getValue().divide(new BigInteger("1000000000000000000"));            
              System.out.println("UFOtoken总供给量:"+totalSupply);
                  System.out.println(address+" UFOToken余额:"+contract.balanceOf(new Address(address)).sendAsync().get().getValue().divide(new BigInteger("1000000000000000000")));                       
              System.out.println(queryAddress+" UFOToken余额:"+contract.balanceOf(new Address(queryAddress)).sendAsync().get().getValue().divide(new BigInteger("1000000000000000000")));   
          }
          


      }catch (Exception e){
          e.printStackTrace();
      }
  }
  
  public String toDecimal(int decimal, BigInteger integer) {
        StringBuffer sbf = new StringBuffer("1");
        for (int i = 0; i < decimal; i++) {
            sbf.append("0");
        }
        String balance = new BigDecimal(integer).divide(new BigDecimal(sbf.toString()), 18, BigDecimal.ROUND_DOWN).toPlainString();
        return balance;
    }



  /**
   * 转账
   * 
   * **/
  public static void transferUFOTokenContract(String toAddress,String toValue){
      //keystore全路径
      Credentials credentials = null;
      Admin admin = null;
      try{
          
          Web3Service web3Service = new HttpService(blockChainUrl, new OkHttpClient.Builder().build(), true);
          admin = Admin.build(web3Service);
          credentials = WalletUtils.loadCredentials(fromPassword, keyStoreAbsolutePath);
          RawTransactionManager transactionManager=new RawTransactionManager(admin, credentials, ChainId.MAINNET);

          // 转账交易
          UFOToken contract = UFOToken.load(address, admin, transactionManager, GAS_PRICE, GAS_LIMIT);
          TransactionReceipt receipt =  contract.transfer(new Address(toAddress), new Uint256(new BigInteger(toValue))).send();
          System.out.println("交易Hash::::::"+receipt.getTransactionHash());
          
      }catch (Exception e){
          e.printStackTrace();
      }
  }
 

}



附件1 ERC20智能合约代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
//指定使用solidity开发语言版本
pragma solidity ^0.4.19;
/**
 * @title SafeMath
 * @dev Math operations with safety checks that throw on error
 */
library SafeMath {
  //基本的算术方法库
  //乘
  function mul(uint256 a, uint256 b) internal pure returns (uint256) {
    if (a == 0) {
      return 0;
    }
    uint256 c = a * b;
    assert(c / a == b);
    return c;
  }
  
  //除
  function div(uint256 a, uint256 b) internal pure returns (uint256) {
    // assert(b > 0); // Solidity automatically throws when dividing by 0
    uint256 c = a / b;
    // assert(a == b * c + a % b); // There is no case in which this doesn't hold
    return c;
  }
  //减
  function sub(uint256 a, uint256 b) internal pure returns (uint256) {
    assert(b <= a);
    return a - b;
  }
  //加
  function add(uint256 a, uint256 b) internal pure returns (uint256) {
    uint256 c = a + b;
    assert(c >= a);
    return c;
  }
}
/**
 * @title ERC20Basic
 * @dev Simpler version of ERC20 interface
 * @dev see https://github.com/ethereum/EIPs/issues/179
 */
contract ERC20Basic {
  //总供给量,也就是发币总量
  uint256 public totalSupply;
  //查询指定地址余额
  function balanceOf(address who) public view returns (uint256);
  //推荐的转账方法可以安全写入
  function transfer(address to, uint256 value) public returns (bool);
  //记录日志
  //address indexed fromaddress indexed to, uint256 value:
  event Transfer(address indexed from, address indexed to, uint256 value);
}
/**
 * @title ERC20 interface
 * @dev see https://github.com/ethereum/EIPs/issues/20
 */
contract ERC20 is ERC20Basic {
  //, _owner  _spender查询能够从地址 _owner 提出的代币数量 
  function allowance(address owner, address spender) public view returns (uint256);
  
  // A-B从地址 _from 转移代币到地址 _to,必须触发 Transfer 事件
  function transferFrom(address from, address to, uint256 value) public returns (bool);
  //  _spender  _value成功调用 approve 时触发 
  function approve(address spender, uint256 value) public returns (bool);
  
  //触发事件记录日志
  event Approval(address indexed owner, address indexed spender, uint256 value);
}
/**
 * @title Basic token
 * @dev Basic version of StandardToken, with no allowances.
 */
contract BasicToken is ERC20Basic {
  //SafeMathLibrary,
  using SafeMath for uint256;
  //
  mapping(address => uint256) balances;
  //_valuetoken_to
  /**
  * @dev transfer token for a specified address
  * @param _to The address to transfer to.
  * @param _value The amount to be transferred.
  */
  function transfer(address _to, uint256 _value) public returns (bool) {
    //require
    //address(0) 必须是有效地址
    require(_to != address(0));
    
    //balances:
    //msg.sender
    //发送者余额不为0
    require(_value <= balances[msg.sender]);
    // SafeMath.sub will throw if there is not enough balance.
    //发送者余额扣减
    balances[msg.sender] = balances[msg.sender].sub(_value);
    //接受者余额增加
    balances[_to] = balances[_to].add(_value);
    //进行交易
    Transfer(msg.sender, _to, _value);
    return true;
  }
  //// balanceOffunctionbalanceOf(address _owner)constantreturns(uint256 balance)
  /**
  * @dev Gets the balance of the specified address.
  * @param _owner The address to query the the balance of.
  * @return An uint256 representing the amount owned by the passed address.
  */
  function balanceOf(address _owner) public view returns (uint256 balance) {
    return balances[_owner];
  }
}
/**
 * @title Standard ERC20 token
 *
 * @dev Implementation of the basic standard token.
 * @dev https://github.com/ethereum/EIPs/issues/20
 */
contract StandardToken is ERC20, BasicToken {
  mapping (address => mapping (address => uint256)) internal allowed;
  /**
   * @dev Transfer tokens from one address to another
   * @param _from address The address which you want to send tokens from
   * @param _to address The address which you want to transfer to
   * @param _value uint256 the amount of tokens to be transferred
   */
  function transferFrom(address _from, address _to, uint256 _value) public returns (bool) {
    require(_to != address(0));
    require(_value <= balances[_from]);
    require(_value <= allowed[_from][msg.sender]);
    balances[_from] = balances[_from].sub(_value);
    balances[_to] = balances[_to].add(_value);
    allowed[_from][msg.sender] = allowed[_from][msg.sender].sub(_value);
    Transfer(_from, _to, _value);
    return true;
  }
  /**
   * @dev Approve the passed address to spend the specified amount of tokens on behalf of msg.sender.
   *
   * Beware that changing an allowance with this method brings the risk that someone may use both the old
   * and the new allowance by unfortunate transaction ordering. One possible solution to mitigate this
   * race condition is to first reduce the spender's allowance to 0 and set the desired value afterwards:
   * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
   * @param _spender The address which will spend the funds.
   * @param _value The amount of tokens to be spent.
   */
  function approve(address _spender, uint256 _value) public returns (bool) {
    allowed[msg.sender][_spender] = _value;
    Approval(msg.sender, _spender, _value);
    return true;
  }
  /**
   * @dev Function to check the amount of tokens that an owner allowed to a spender.
   * @param _owner address The address which owns the funds.
   * @param _spender address The address which will spend the funds.
   * @return A uint256 specifying the amount of tokens still available for the spender.
   */
  function allowance(address _owner, address _spender) public view returns (uint256) {
    return allowed[_owner][_spender];
  }
}
/// @title UFO Protocol Token.
/// For more information about this token, please visit http://www.banyanbbt.org
contract UFOToken is StandardToken {
    string public name;
    string public symbol;
    uint public decimals;
    /**
     * CONSTRUCTOR 
     * 
     * @dev Initialize the UFO Token
     */
    function UFOToken() public {      
        totalSupply = 10 * 10 ** 26;
        balances[msg.sender] = totalSupply;
        name = "UFOToken";
        symbol = "UFO";
        decimals = 18;
    }
}

感谢HPB技术团队整理。

HPB70:HPB主网接入最佳实践之Java版

1、开始准备

1.1 学习门槛

  • 熟悉Java的基本语法和使用
  • 熟悉Java的IDE工具基本使用(Eclipse,IDEA)
  • 熟悉Git版本管理的基本语法和使用
  • 熟悉SpingBoot开发(本Demo提供的是基于Springboot的源码)
  • 熟悉区块链的基本原理
  • HPB主网如何介入请前往https://www.hpb.io/client%E4%BA%86%E8%A7%A3

1.2 环境准备

  • JDK1.8以上版本
  • Eclipse4.7或者以上
  • Eclipse安装了Git插件
  • Eclipse安装了Spring插件
  • HPB主网接入的JAVA SDK请前往这里地址下载:https://www.hpb.io/client
  • 因为是maven工程,会从网络中下载工程依赖的jar宝,所以需要机器处于联网状态

1.3 源码地址

1
https://github.com/loglos/web3-hpb-test.git

2、开始实践

2.1 通过Eclipse Import 演示代码

  • 打开Eclipse,通过菜单栏依次点击打开:File/Import/Git/Projects form Git/
  • 选择通过Clone URI导入,在导入界面,输入源码的Github地址;
  • 然后下一步,选择master主分支
  • 然后下一步指定代码下载存放的路径
  • 然后下一步,选择Import as general project
  • 下一步,指定工程名称,默认是Github源码工程的名称,可以不修改,点击完成。

2.2 改变代码工程的属性

  • 因为上传到Github的代码是不包括代码工程配置信息的,所以需要进行简单的调整。
  • 源码工程是基于maven的类型,可以右键工程代码,选择“configure/convert to maven projects”
  • 转换成功后,系统就能识别为maven类型的工程了
  • 提醒:转换为maven工程后,很多依赖的jar包都是通过pom.xml来配置管理的,同时如果本地没安装过maven的本地仓库,第一次会默认从远程的拉取依赖jar包,速度比较慢,如果工程报错,需要多尝试几次

2.3 源码关键配置信息说明

打开maven配置文件pom.xml

1
2
3
4
5
6
7
8
9
<!--
其他的配置不需要修改,这里说明下,引用的事HPB主网的JAVA版本SDK
-->
      <dependency>
          <groupId>io.hpb.web3</groupId>
          <artifactId>web3-hpb</artifactId>
          <version>1.0.0</version>
      </dependency>
      

打开application.properties文件,配置文件可以根据需要进行修改,也可以不进行修改。 这里罗列了重要的几个配置属性进行说明

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#指定工程发布后访问名称
spring.application.name=HpbWeb3Test

#工程发布后的访问服务端口
server.port=9988
server.servlet.path=/
server.use-forward-headers=true
server.servlet.context-path=/HpbWeb3Test
server.servlet.application-display-name=hpb web3 test application
web3.admin-client=true
web3.httpTimeoutSeconds=600

#指定的连接HPB主网的RPC网址,这里是主网正式网的开放的RPC地址
#通过访问这个地址,可以进行通过Java操作RPC命令,直接和HPB主网进行交互。
web3.client-address=http://pub.node.hpb.io/

打开HpbWeb3Controller.java文件,这里是本次演示的具体代码,这里对关键代码进行下说明。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
//注意这里,是引用了HPB主网提供的Java SDK包,里面封装了如何通过RPC方式与底层交互的方法
import io.hpb.web3.abi.datatypes.Address;
import io.hpb.web3.abi.datatypes.DynamicArray;
import io.hpb.web3.abi.datatypes.generated.Bytes32;
import io.hpb.web3.contract.HpbNodes;
import io.hpb.web3.crypto.Credentials;
import io.hpb.web3.crypto.RawTransaction;
import io.hpb.web3.crypto.WalletUtils;
import io.hpb.web3.protocol.admin.Admin;
import io.hpb.web3.protocol.core.DefaultBlockParameterName;
import io.hpb.web3.protocol.core.methods.response.HpbBlockNumber;
import io.hpb.web3.protocol.core.methods.response.HpbGetBalance;
import io.hpb.web3.protocol.core.methods.response.HpbGetTransactionCount;
import io.hpb.web3.protocol.core.methods.response.HpbGetTransactionReceipt;
import io.hpb.web3.protocol.core.methods.response.HpbSendTransaction;
import io.hpb.web3.protocol.core.methods.response.TransactionReceipt;
import io.hpb.web3.tuples.generated.Tuple4;
import io.hpb.web3.tx.ChainId;
import io.hpb.web3.tx.RawTransactionManager;
import io.hpb.web3.utils.Convert;
import io.hpb.web3.utils.Numeric;
import io.swagger.annotations.ApiOperation;

@RestController
@RequestMapping("/")
public class HpbWeb3Controller{
    
    //输出日志
  private static Log log = LogFactory.getLog(HpbWeb3Controller.class);
  //超时时间
  private final long WEB3J_TIMEOUT = 3;
  
  //演示的HPB账号地址
  private final String contractAddr = "0x7be6aa25600feed355b79b6a4e14dcdb0bd529cb";
  
  //设置账号的余额单位为18GWEI
  private final BigInteger gasPrice = Convert.toWei("18", Convert.Unit.GWEI).toBigInteger();
  //设置默认的GasLimit
  private final BigInteger gasLimit = new BigInteger("95000000");
  
  
  @Autowired
  private Admin admin;
  @ApiOperation(value="通过根据交易hash查询交易收据",notes = "过根据交易hash查询交易收据"
          + " reqStrList [  参数1:交易hash]")
  @PostMapping("/QueryByHash")
  public List<Object> QueryByHash(@RequestBody List<String> reqStrList)throws Exception{
      List<Object> list=new ArrayList<Object>();
      if(reqStrList!=null&&reqStrList.size()>0) {
          String transactionHash = reqStrList.get(0);
          
          //初始化封装的Java SDK包里的方法;通过初始化HpbGetTransactionReceipt,可以获得指定账号的交易数据
          HpbGetTransactionReceipt receipt = admin.hpbGetTransactionReceipt(transactionHash).send();
          if(!receipt.hasError()) {
              TransactionReceipt transactionReceipt = receipt.getResult();
              if(transactionReceipt.isStatusOK()) {
                  list.add(transactionReceipt);
              }
          }
      }
      return list;
  }
  
  
  @ApiOperation(value="获得当前区块号",notes = "获得当前区块号")
  @PostMapping("/getCurrentBlock")
  public List<Object> getCurrentBlock()throws Exception{
      List<Object> list=new ArrayList<Object>();
      
      //初始化封装的Java SDK包里的方法;通过HpbBlockNumber获取当前区块的对象内容
      HpbBlockNumber blockNumber = admin.hpbBlockNumber().sendAsync().get(WEB3J_TIMEOUT, TimeUnit.MINUTES);
      list.add(blockNumber);
      return list;
  }
  @ApiOperation(value="获得当前账户的Nonce",notes = "获得当前账户的Nonce"
          + " reqStrList [ 参数1:账户地址;")
  @PostMapping("/getCurrentNonce")
  public List<Object> getCurrentNonce(@RequestBody List<String> reqStrList)throws Exception{
      List<Object> list=new ArrayList<Object>();
      if(reqStrList!=null&&reqStrList.size()>0) {
          String address =reqStrList.get(0);
          
          //初始化封装的Java SDK包里的方法;通过HpbGetTransactionCount获取当前账号Nonce
          //Nonce是账户的随机数:在一个账户中的防止多重交易的用途。
          HpbGetTransactionCount transactionCount = admin.hpbGetTransactionCount(address, 
                  DefaultBlockParameterName.PENDING).sendAsync().get(WEB3J_TIMEOUT, TimeUnit.MINUTES);
          BigInteger nonce = transactionCount.getTransactionCount();
          log.info(nonce);
          list.add(nonce);
      }
      return list;
  }
  
  
  
  @ApiOperation(value="获得当前账户的余额",notes = "获得当前账户的余额"
          + " reqStrList [ 参数1:账户地址; ]")
  @PostMapping("/getBalance")
  public List<Object> getBalance(@RequestBody List<String> reqStrList)throws Exception{
      List<Object> list=new ArrayList<Object>();
      if(reqStrList!=null&&reqStrList.size()>0) {
          String address =reqStrList.get(0);
          
          //初始化封装的Java SDK包里的方法;通过HpbGetBalance获取当前账号的余额。
          HpbGetBalance balance = admin.hpbGetBalance(address, DefaultBlockParameterName.LATEST).send();
          log.info(balance);
          list.add(balance);
      }
      return list;
  }
  
  
  
  @ApiOperation(value="发送交易",notes = "发送交易"
          + " reqStrList [ 参数1:账户keystore地址; 参数2:密码; 参数3:接收账户地址;参数4:转账金额;]")
  @PostMapping("/sendTransaction")
  public List<Object> sendTransaction(@RequestBody List<String> reqStrList)throws Exception{
      List<Object> list=new ArrayList<Object>();
      if(reqStrList!=null&&reqStrList.size()>3) {
          //获取指定账号的keystore
          String keystore =reqStrList.get(0);
          
          //获取用户输入发送交易的账号密码
          String password =reqStrList.get(1);
          
          //加载私钥对象
          Credentials credentials = WalletUtils.loadCredentials(password, keystore);
          
          //创建交易管理对象
          RawTransactionManager transactionManager=new RawTransactionManager(admin, credentials, ChainId.MAINNET);
          
          //获取nonce
          HpbGetTransactionCount transactionCount = admin.hpbGetTransactionCount(credentials.getAddress(), 
                  DefaultBlockParameterName.PENDING).sendAsync().get(WEB3J_TIMEOUT, TimeUnit.MINUTES);
          
          BigInteger nonce = transactionCount.getTransactionCount();
          
          //获取目标地址
          String to =reqStrList.get(2);
          
          //转账金额
          String value =reqStrList.get(3);
          
          //创建交易对象
          RawTransaction rawTransaction = RawTransaction.createTransaction(
                  nonce,
                  gasPrice,
                  gasLimit,
                  to,
                  Convert.toWei(value, Convert.Unit.HPB).toBigInteger(),
                  "");
              
          //签名并发送交易
          HpbSendTransaction transaction = transactionManager.signAndSend(rawTransaction);
          log.info(transaction.getTransactionHash());
          list.add(transaction);
      }
      return list;
  }
  
  
  
  @ApiOperation(value="调用HpbNodes智能合约",notes = "调用HpbNodes智能合约"
          + " reqStrList [ 参数1:账户keystore地址; 参数2:密码]")
  @PostMapping("/invokeHpbNodes")
  public List<Object> invokeHpbNodes(@RequestBody List<String> reqStrList)throws Exception{
      List<Object> list=new ArrayList<Object>();
      if(reqStrList!=null&&reqStrList.size()>1) {
          String keystore =reqStrList.get(0);
          String password =reqStrList.get(1);
          Credentials credentials = WalletUtils.loadCredentials(password, keystore);
          RawTransactionManager transactionManager=new RawTransactionManager(admin, credentials, ChainId.MAINNET);
          HpbNodes hpbNodes = HpbNodes.load(contractAddr, admin, transactionManager, gasPrice, gasLimit);
          //调用智能合约
          Tuple4<DynamicArray<Address>, DynamicArray<Bytes32>, DynamicArray<Bytes32>, DynamicArray<Bytes32>> send = 
                  hpbNodes.getAllHpbNodes().send();
          Bytes32 bytes32 = send.getValue2().getValue().get(1);
          log.info(Numeric.toHexStringNoPrefix(bytes32.getValue()));
          Bytes32 bytes321 = send.getValue3().getValue().get(1);
          log.info(Numeric.toHexStringNoPrefix(bytes321.getValue()));
          Bytes32 bytes322 = send.getValue3().getValue().get(1);
          log.info(Numeric.toHexStringNoPrefix(bytes322.getValue()));
          list.add(send);
      }
      return list;
  }
  
}

2.4 运行程序和调试

1.发布程序

找到和选择好Web3HpbTestApplication类,右击”Run as /Spring Boot App” 启动成功后,系统会出现类似如下提示:

1
2
3
4
5
6
7
8
9
10
11
12
13
2019-01-09 10:49:18.538 HpbWeb3Test [main] INFO  io.hpb.web3.Web3HpbTestApplication Caller+0  at org.springframework.boot.StartupInfoLogger.logStarting(StartupInfoLogger.java:50)
 - Starting Web3HpbTestApplication on jason-hpbdeMBP with PID 46179 (/Users/hpb2017/git/web3-hpb-test/target/classes started by hpb2017 in /Users/hpb2017/git/web3-hpb-test)
2019-01-09 10:49:18.540 HpbWeb3Test [main] DEBUG io.hpb.web3.Web3HpbTestApplication Caller+0   at org.springframework.boot.StartupInfoLogger.logStarting(StartupInfoLogger.java:53)
 - Running with Spring Boot v2.1.1.RELEASE, Spring v5.1.3.RELEASE
2019-01-09 10:49:18.542 HpbWeb3Test [main] INFO  io.hpb.web3.Web3HpbTestApplication Caller+0   at org.springframework.boot.SpringApplication.logStartupProfileInfo(SpringApplication.java:675)
 - No active profile set, falling back to default profiles: default
2019-01-09 10:49:20.818 HpbWeb3Test [main] INFO  i.h.w.c.Web3AutoConfiguration Caller+0    at io.hpb.web3.configure.Web3AutoConfiguration.admin(Web3AutoConfiguration.java:51)
 - Building admin service for endpoint: http://pub.node.hpb.io/
2019-01-09 10:49:21.406 HpbWeb3Test [main] INFO  i.h.w.c.Web3AutoConfiguration Caller+0    at io.hpb.web3.configure.Web3AutoConfiguration.Web3(Web3AutoConfiguration.java:42)
 - Building service for endpoint: http://pub.node.hpb.io/
2019-01-09 10:49:22.057 HpbWeb3Test [main] INFO  io.hpb.web3.Web3HpbTestApplication Caller+0   at org.springframework.boot.StartupInfoLogger.logStarted(StartupInfoLogger.java:59)
 - Started Web3HpbTestApplication in 3.943 seconds (JVM running for 5.429)
 

2.测试验证接口

Springboot的接口可以通过自带的swagger插件进行访问和测试。 打开本地访问地址:http://localhost:9988/HpbWeb3Test/swagger-ui.html#/ 会显示如目前系统开放的测试接口,然后选择点击“hpb-web-3-controller”,接入该接口的具体方法测试界面。 点击“/getBalance”方法,点击“Try it out”开启编辑模式,输入你要查询余额的HPB地址;然后点击“Execute”开始执行。 系统会显示执行的结果,注意这里获取的余额显示的是科学计数法。 其他的接口可以依次根据接口的内容进行测试。

感谢HPB技术团队整理。

HPB69:HPB JSON RPC API 介绍

JSON RPC API 索引

JSON RPC API

JSON 是一种轻量级数据交换格式。它可以表示数字,字符串,有序的值序列以及名称/值对的集合。

JSON-RPC 是一种无状态,轻量级的远程过程调用(RPC)协议。该规范主要定义了几个数据结构和围绕其处理的规则。它与传输无关,因为这些概念可以在同一进程中,通过套接字,通过HTTP或在许多不同的消息传递环境中使用。它使用JSON (RFC 4627)作为数据格式。

Curl 案例解释

下面的curl选项可能会返回一个响应,其中节点包含内容类型,这是因为—data选项将内容类型设置为application / x-www-form-urlencoded。如果您的节点发出不响应,请通过在呼叫开始时放置-H“Content-Type:application / json”来手动设置标头。

这些示例也不包括URL / IP和端口组合,它们必须是curl e.x的一个参数,例如: 127.0.0.1:8545

JSON-RPC 方法

net_version Returns the current network protocol version.

Parameters none

Returns String – The current network protocol version

Example

1
2
3
4
5
6
7
8
9
// Request
curl -H "Content-Type:application/json" -X POST --data '{"jsonrpc":"2.0","method":"net_version","params":[],"id":67}'

// Result
{
  "id":67,
  "jsonrpc": "2.0",
  "result": "59"
}

net_listening Returns true if client is actively listening for network connections.

Parameters none

Returns Boolean – true when listening, otherwise false.

Example

1
2
3
4
5
6
7
8
9
// Request
curl -H "Content-Type:application/json" -X POST --data '{"jsonrpc":"2.0","method":"net_listening","params":[],"id":67}'

// Result
{
  "id":67,
  "jsonrpc":"2.0",
  "result":true
}

net_peerCount Returns number of peers currenly connected to the client.

Parameters none

Returns QUANTITY – integer of the number of connected peers.

Example

1
2
3
4
5
6
7
8
9
// Request
curl -H "Content-Type:application/json" -X POST --data '{"jsonrpc":"2.0","method":"net_peerCount","params":[],"id":74}'

// Result
{
  "id":74,
  "jsonrpc": "2.0",
  "result": "0x2" // 2
}

hpb_protocolVersion Returns the current hpb protocol version.

Parameters none

Returns String – The current hpb protocol version

Example

1
2
3
4
5
6
7
8
9
// Request
curl -H "Content-Type:application/json" -X POST --data '{"jsonrpc":"2.0","method":"hpb_protocolVersion","params":[],"id":67}'

// Result
{
  "id":67,
  "jsonrpc": "2.0",
  "result": "54"
}

hpb_syncing Returns an object object with data about the sync status or FALSE.

Parameters none

Returns Object|Boolean, An object with sync status data or FALSE, when not syncing:

startingBlock: QUANTITY – The block at which the import started (will only be reset, after the sync reached his head) currentBlock: QUANTITY – The current block, same as hpb_blockNumber highestBlock: QUANTITY – The estimated highest block Example

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// Request
curl -H "Content-Type:application/json" -X POST --data '{"jsonrpc":"2.0","method":"hpb_isSyncing","params":[],"id":1}'

// Result
{
  "id":1,
  "jsonrpc": "2.0",
  "result": {
    startingBlock: '0x384',
    currentBlock: '0x386',
    highestBlock: '0x454'
  }
}
// Or when not syncing
{
  "id":1,
  "jsonrpc": "2.0",
  "result": false
}

hpb_coinbase Returns the client coinbase address.

Parameters none

Returns DATA, 20 bytes – the current coinbase address.

Example

1
2
3
4
5
6
7
8
9
// Request
curl -H "Content-Type:application/json" -X POST --data '{"jsonrpc":"2.0","method":"hpb_coinbase","params":[],"id":64}'

// Result
{
  "id":64,
  "jsonrpc": "2.0",
  "result": "0x407d73d8a49eeb85d32cf465507dd71d507100c1"
}

hpb_mining Returns true if client is actively mining new blocks.

Parameters none

Returns Boolean – returns true of the client is mining, otherwise false.

Example

1
2
3
4
5
6
7
8
9
// Request
curl -H "Content-Type:application/json" -X POST --data '{"jsonrpc":"2.0","method":"hpb_mining","params":[],"id":71}'

// Result
{
  "id":71,
  "jsonrpc": "2.0",
  "result": true
}

hpb_gasPrice Returns the current price per gas in wei.

Parameters none

Returns QUANTITY – integer of the current gas price in wei.

Example

1
2
3
4
5
6
7
8
9
// Request
curl -H "Content-Type:application/json" -X POST --data '{"jsonrpc":"2.0","method":"hpb_gasPrice","params":[],"id":73}'

// Result
{
  "id":73,
  "jsonrpc": "2.0",
  "result": "0x09184e72a000" // 10000000000000
}

hpb_accounts Returns a list of addresses owned by client.

Parameters none

Returns Array of DATA, 20 Bytes – addresses owned by the client.

Example

1
2
3
4
5
6
7
8
9
// Request
curl -H "Content-Type:application/json" -X POST --data '{"jsonrpc":"2.0","method":"hpb_accounts","params":[],"id":1}'

// Result
{
  "id":1,
  "jsonrpc": "2.0",
  "result": ["0x407d73d8a49eeb85d32cf465507dd71d507100c1"]
}

hpb_blockNumber Returns the number of most recent block.

Parameters none

Returns QUANTITY – integer of the current block number the client is on.

Example

1
2
3
4
5
6
7
8
9
// Request
curl -H "Content-Type:application/json" -X POST --data '{"jsonrpc":"2.0","method":"hpb_blockNumber","params":[],"id":83}'

// Result
{
  "id":83,
  "jsonrpc": "2.0",
  "result": "0x4b7" // 1207
}

hpb_getBalance Returns the balance of the account of given address.

Parameters

1
2
3
4
5
6
DATA, 20 Bytes - address to check for balance.
QUANTITY|TAG - integer block number, or the string "latest", "earliest" or "pending"
params: [
   '0x407d73d8a49eeb85d32cf465507dd71d507100c1',
   'latest'
]

Returns QUANTITY – integer of the current balance in wei.

Example

1
2
3
4
5
6
7
8
9
// Request
curl -H "Content-Type:application/json" -X POST --data '{"jsonrpc":"2.0","method":"hpb_getBalance","params":["0x407d73d8a49eeb85d32cf465507dd71d507100c1", "latest"],"id":1}'

// Result
{
  "id":1,
  "jsonrpc": "2.0",
  "result": "0x0234c8a3397aab58" // 158972490234375000
}

hpb_getStorageAt Returns the value from a storage position at a given address.

Parameters

1
2
3
4
5
6
7
8
DATA, 20 Bytes - address of the storage.
QUANTITY - integer of the position in the storage.
QUANTITY|TAG - integer block number, or the string "latest", "earliest" or "pending"
params: [
   '0x407d73d8a49eeb85d32cf465507dd71d507100c1',
   '0x0', // storage position at 0
   '0x2' // state at block number 2
]

Returns DATA – the value at this storage position.

Example

1
2
3
4
5
6
7
8
9
// Request
curl -H "Content-Type:application/json" -X POST --data '{"jsonrpc":"2.0","method":"hpb_getStorageAt","params":["0x407d73d8a49eeb85d32cf465507dd71d507100c1", "0x0", "0x2"],"id":1}'

// Result
{
  "id":1,
  "jsonrpc": "2.0",
  "result": "0x03"
}

hpb_getTransactionCount Returns the number of transactions sent from an address.

Parameters

1
2
3
4
5
6
DATA, 20 Bytes - address.
QUANTITY|TAG - integer block number, or the string "latest", "earliest" or "pending"
params: [
   '0x407d73d8a49eeb85d32cf465507dd71d507100c1',
   'latest' // state at the latest block
]

Returns QUANTITY – integer of the number of transactions send from this address.

Example

1
2
3
4
5
6
7
8
9
// Request
curl -H "Content-Type:application/json" -X POST --data '{"jsonrpc":"2.0","method":"hpb_getTransactionCount","params":["0x407d73d8a49eeb85d32cf465507dd71d507100c1","latest"],"id":1}'

// Result
{
  "id":1,
  "jsonrpc": "2.0",
  "result": "0x1" // 1
}

hpb_getBlockTransactionCountByHash Returns the number of transactions in a block from a block matching the given block hash.

Parameters

1
2
3
4
DATA, 32 Bytes - hash of a block
params: [
   '0xb903239f8543d04b5dc1ba6579132b143087c68db1b2168786408fcbce568238'
]

Returns QUANTITY – integer of the number of transactions in this block.

Example

1
2
3
4
5
6
7
8
9
// Request
curl -H "Content-Type:application/json" -X POST --data '{"jsonrpc":"2.0","method":"hpb_getBlockTransactionCountByHash","params":["0xb903239f8543d04b5dc1ba6579132b143087c68db1b2168786408fcbce568238"],"id":1}'

// Result
{
  "id":1,
  "jsonrpc": "2.0",
  "result": "0xb" // 11
}

hpb_getBlockTransactionCountByNumber Returns the number of transactions in a block from a block matching the given block number.

Parameters

1
2
3
4
QUANTITY|TAG - integer of a block number, or the string "earliest", "latest" or "pending".
params: [
   '0xe8', // 232
]

Returns QUANTITY – integer of the number of transactions in this block.

Example

1
2
3
4
5
6
7
8
9
// Request
curl -H "Content-Type:application/json" -X POST --data '{"jsonrpc":"2.0","method":"hpb_getBlockTransactionCountByNumber","params":["0xe8"],"id":1}'

// Result
{
  "id":1,
  "jsonrpc": "2.0",
  "result": "0xa" // 10
}

hpb_getUncleCountByBlockHash Returns the number of uncles in a block from a block matching the given block hash.

Parameters

1
2
3
4
DATA, 32 Bytes - hash of a block
params: [
   '0xb903239f8543d04b5dc1ba6579132b143087c68db1b2168786408fcbce568238'
]

Returns QUANTITY – integer of the number of uncles in this block.

Example

1
2
3
4
5
6
7
8
9
// Request
curl -H "Content-Type:application/json" -X POST --data '{"jsonrpc":"2.0","method":"hpb_getUncleCountByBlockHash","params":["0xb903239f8543d04b5dc1ba6579132b143087c68db1b2168786408fcbce568238"],"id"Block:1}'

// Result
{
  "id":1,
  "jsonrpc": "2.0",
  "result": "0x1" // 1
}

hpb_getUncleCountByBlockNumber Returns the number of uncles in a block from a block matching the given block number.

Parameters

1
2
3
4
QUANTITY - integer of a block number, or the string "latest", "earliest" or "pending"
params: [
   '0xe8', // 232
]

Returns QUANTITY – integer of the number of uncles in this block.

Example

1
2
3
4
5
6
7
8
9
// Request
curl -H "Content-Type:application/json" -X POST --data '{"jsonrpc":"2.0","method":"hpb_getUncleCountByBlockNumber","params":["0xe8"],"id":1}'

// Result
{
  "id":1,
  "jsonrpc": "2.0",
  "result": "0x1" // 1
}

hpb_getCode Returns code at a given address.

Parameters

1
2
3
4
5
6
DATA, 20 Bytes - address
QUANTITY|TAG - integer block number, or the string "latest", "earliest" or "pending"
params: [
   '0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b',
   '0x2'  // 2
]

Returns DATA – the code from the given address.

Example

1
2
3
4
5
6
7
8
9
// Request
curl -H "Content-Type:application/json" -X POST --data '{"jsonrpc":"2.0","method":"hpb_getCode","params":["0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b", "0x2"],"id":1}'

// Result
{
  "id":1,
  "jsonrpc": "2.0",
  "result": "0x600160008035811a818181146012578301005b601b6001356025565b8060005260206000f25b600060078202905091905056"
}

hpb_sendTransaction Creates new message call transaction or a contract creation, if the data field contains code.

Parameters

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Object - The transaction object
from: DATA, 20 Bytes - The address the transaction is send from.
to: DATA, 20 Bytes - (optional when creating new contract) The address the transaction is directed to.
gas: QUANTITY - (optional, default: 90000) Integer of the gas provided for the transaction execution. It will return unused gas.
gasPrice: QUANTITY - (optional, default: To-Be-Determined) Integer of the gasPrice used for each paid gas
value: QUANTITY - (optional) Integer of the value send with this transaction
data: DATA - (optional) The compiled code of a contract
nonce: QUANTITY - (optional) Integer of a nonce. This allows to overwrite your own pending transactions that use the same nonce.
params: [{
  "from": "0xb60e8dd61c5d32be8058bb8eb970870f07233155",
  "to": "0xd46e8dd67c5d32be8058bb8eb970870f072445675",
  "gas": "0x76c0", // 30400,
  "gasPrice": "0x9184e72a000", // 10000000000000
  "value": "0x9184e72a", // 2441406250
  "data": "0xd46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675"
}]

Returns DATA, 32 Bytes – the transaction hash, or the zero hash if the transaction is not yet available.

Use hpb_getTransactionReceipt to get the contract address, after the transaction was mined, when you created a contract.

Example

1
2
3
4
5
6
7
8
9
// Request
curl -H "Content-Type:application/json" -X POST --data '{"jsonrpc":"2.0","method":"hpb_sendTransaction","params":[{see above}],"id":1}'

// Result
{
  "id":1,
  "jsonrpc": "2.0",
  "result": "0xe670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d1527331"
}

hpb_sendRawTransaction Creates new message call transaction or a contract creation for signed transactions.

Parameters

1
2
3
4
5
Object - The transaction object
data: DATA, The signed transaction data.
params: [{
  "data": "0xd46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675"
}]

Returns DATA, 32 Bytes – the transaction hash, or the zero hash if the transaction is not yet available.

Use hpb_getTransactionReceipt to get the contract address, after the transaction was mined, when you created a contract.

Example

1
2
3
4
5
6
7
8
9
// Request
curl -H "Content-Type:application/json" -X POST --data '{"jsonrpc":"2.0","method":"hpb_sendRawTransaction","params":[{see above}],"id":1}'

// Result
{
  "id":1,
  "jsonrpc": "2.0",
  "result": "0xe670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d1527331"
}

hpb_call Executes a new message call immediately without creating a transaction on the block chain.

Parameters

1
2
3
4
5
6
7
8
9
Object - The transaction call object
from: DATA, 20 Bytes - (optional) The address the transaction is send from.
to: DATA, 20 Bytes - The address the transaction is directed to.
gas: QUANTITY - (optional) Integer of the gas provided for the transaction execution. hpb_call consumes zero gas, but this parameter may be needed by some executions.
gasPrice: QUANTITY - (optional) Integer of the gasPrice used for each paid gas
value: QUANTITY - (optional) Integer of the value send with this transaction
data: DATA - (optional) The compiled code of a contract
QUANTITY|TAG - integer block number, or the string "latest", "earliest" or "pending"

Returns DATA – the return value of executed contract.

Example

1
2
3
4
5
6
7
8
9
10
// Request
curl -H "Content-Type:application/json" -X POST --data '{"jsonrpc":"2.0","method":"hpb_call","params":[{see above}],"id":1}'

// Result
{
  "id":1,
  "jsonrpc": "2.0",
  "result": "0x0"
}

hpb_estimateGas Makes a call or transaction, which won’t be added to the blockchain and returns the used gas, which can be used for estimating the used gas.

Parameters See hpb_call parameters, expect that all properties are optional.

Returns QUANTITY – the amount of gas used.

Example

1
2
3
4
5
6
7
8
9
10
// Request
curl -H "Content-Type:application/json" -X POST --data '{"jsonrpc":"2.0","method":"hpb_estimateGas","params":[{see above}],"id":1}'

// Result
{
  "id":1,
  "jsonrpc": "2.0",
  "result": "0x5208" // 21000
}

hpb_getBlockByHash Returns information about a block by hash.

Parameters

1
2
3
4
5
6
7
DATA, 32 Bytes - Hash of a block.
Boolean - If true it returns the full transaction objects, if false only the hashes of the transactions.
params: [
   '0xe670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d1527331',
   true
]

Returns Object – A block object, or null when no block was found:

number: QUANTITY – the block number. null when its pending block. hash: DATA, 32 Bytes – hash of the block. null when its pending block. parentHash: DATA, 32 Bytes – hash of the parent block. nonce: DATA, 8 Bytes – hash of the generated proof-of-work. null when its pending block. sha3Uncles: DATA, 32 Bytes – SHA3 of the uncles data in the block. logsBloom: DATA, 256 Bytes – the bloom filter for the logs of the block. null when its pending block. transactionsRoot: DATA, 32 Bytes – the root of the transaction trie of the block. stateRoot: DATA, 32 Bytes – the root of the final state trie of the block. receiptsRoot: DATA, 32 Bytes – the root of the receipts trie of the block. miner: DATA, 20 Bytes – the address of the beneficiary to whom the mining rewards were given. difficulty: QUANTITY – integer of the difficulty for this block. totalDifficulty: QUANTITY – integer of the total difficulty of the chain until this block. extraData: DATA – the “extra data” field of this block. size: QUANTITY – integer the size of this block in bytes. gasLimit: QUANTITY – the maximum gas allowed in this block. gasUsed: QUANTITY – the total used gas by all transactions in this block. timestamp: QUANTITY – the unix timestamp for when the block was collated. transactions: Array – Array of transaction objects, or 32 Bytes transaction hashes depending on the last given parameter. uncles: Array – Array of uncle hashes. Example

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// Request
curl -H "Content-Type:application/json" -X POST --data '{"jsonrpc":"2.0","method":"hpb_getBlockByHash","params":["0xe670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d1527331", true],"id":1}'

// Result
{
"id":1,
"jsonrpc":"2.0",
"result": {
    "number": "0x1b4", // 436
    "hash": "0xe670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d1527331",
    "parentHash": "0x9646252be9520f6e71339a8df9c55e4d7619deeb018d2a3f2d21fc165dde5eb5",
    "nonce": "0xe04d296d2460cfb8472af2c5fd05b5a214109c25688d3704aed5484f9a7792f2",
    "sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
    "logsBloom": "0xe670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d1527331",
    "transactionsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
    "stateRoot": "0xd5855eb08b3387c0af375e9cdb6acfc05eb8f519e419b874b6ff2ffda7ed1dff",
    "miner": "0x4e65fda2159562a496f9f3522f89122a3088497a",
    "difficulty": "0x027f07", // 163591
    "totalDifficulty":  "0x027f07", // 163591
    "extraData": "0x0000000000000000000000000000000000000000000000000000000000000000",
    "size":  "0x027f07", // 163591
    "gasLimit": "0x9f759", // 653145
    "minGasPrice": "0x9f759", // 653145
    "gasUsed": "0x9f759", // 653145
    "timestamp": "0x54e34e8e" // 1424182926
    "transactions": [{...},{ ... }]
    "uncles": ["0x1606e5...", "0xd5145a9..."]
  }
}

hpb_getBlockByNumber Returns information about a block by block number.

Parameters

1
2
3
4
5
6
7
QUANTITY|TAG - integer of a block number, or the string "earliest", "latest" or "pending"
Boolean - If true it returns the full transaction objects, if false only the hashes of the transactions.
params: [
   '0x1b4', // 436
   true
]

Returns See hpb_getBlockByHash

Example

1
2
3
4
// Request
curl -H "Content-Type:application/json" -X POST --data '{"jsonrpc":"2.0","method":"hpb_getBlockByNumber","params":["0x1b4", true],"id":1}'
Result see hpb_getBlockByHash

hpb_getTransactionByHash Returns the information about a transaction requested by transaction hash.

Parameters

1
2
3
4
5
DATA, 32 Bytes - hash of a transaction
params: [
   "0xb903239f8543d04b5dc1ba6579132b143087c68db1b2168786408fcbce568238"
]

Returns Object – A transaction object, or null when no transaction was found:

hash: DATA, 32 Bytes – hash of the transaction. nonce: QUANTITY – the number of transactions made by the sender prior to this one. blockHash: DATA, 32 Bytes – hash of the block where this transaction was in. null when its pending. blockNumber: QUANTITY – block number where this transaction was in. null when its pending. transactionIndex: QUANTITY – integer of the transactions index position in the block. null when its pending. from: DATA, 20 Bytes – address of the sender. to: DATA, 20 Bytes – address of the receiver. null when its a contract creation transaction. value: QUANTITY – value transferred in Wei. gasPrice: QUANTITY – gas price provided by the sender in Wei. gas: QUANTITY – gas provided by the sender. input: DATA – the data send along with the transaction. Example

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// Request
curl -H "Content-Type:application/json" -X POST --data '{"jsonrpc":"2.0","method":"hpb_getTransactionByHash","params":["0xb903239f8543d04b5dc1ba6579132b143087c68db1b2168786408fcbce568238"],"id":1}'

// Result
{
"id":1,
"jsonrpc":"2.0",
"result": {
    "hash":"0xc6ef2fc5426d6ad6fd9e2a26abeab0aa2411b7ab17f30a99d3cb96aed1d1055b",
    "nonce":"0x",
    "blockHash": "0xbeab0aa2411b7ab17f30a99d3cb9c6ef2fc5426d6ad6fd9e2a26a6aed1d1055b",
    "blockNumber": "0x15df", // 5599
    "transactionIndex":  "0x1", // 1
    "from":"0x407d73d8a49eeb85d32cf465507dd71d507100c1",
    "to":"0x85h43d8a49eeb85d32cf465507dd71d507100c1",
    "value":"0x7f110" // 520464
    "gas": "0x7f110" // 520464
    "gasPrice":"0x09184e72a000",
    "input":"0x603880600c6000396000f300603880600c6000396000f3603880600c6000396000f360",
  }
}

hpb_getTransactionByBlockHashAndIndex Returns information about a transaction by block hash and transaction index position.

Parameters

1
2
3
4
5
6
7
DATA, 32 Bytes - hash of a block.
QUANTITY - integer of the transaction index position.
params: [
   '0xe670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d1527331',
   '0x0' // 0
]

Returns See hpb_getBlockByHash

Example

1
2
3
4
// Request
curl -H "Content-Type:application/json" -X POST --data '{"jsonrpc":"2.0","method":"hpb_getTransactionByBlockHashAndIndex","params":[0xc6ef2fc5426d6ad6fd9e2a26abeab0aa2411b7ab17f30a99d3cb96aed1d1055b, "0x0"],"id":1}'
Result see hpb_getTransactionByHash

hpb_getTransactionByBlockNumberAndIndex Returns information about a transaction by block number and transaction index position.

Parameters

1
2
3
4
5
6
7
8
QUANTITY|TAG - a block number, or the string "earliest", "latest" or "pending".
QUANTITY - the transaction index position.
params: [
   '0x29c', // 668
   '0x0' // 0
]


Returns See hpb_getBlockByHash

Example

1
2
3
4
// Request
curl -H "Content-Type:application/json" -X POST --data '{"jsonrpc":"2.0","method":"hpb_getTransactionByBlockNumberAndIndex","params":["0x29c", "0x0"],"id":1}'
Result see hpb_getTransactionByHash

hpb_getTransactionReceipt Returns the receipt of a transaction by transaction hash.

Note That the receipt is not available for pending transactions.

Parameters

1
2
3
4
5
DATA, 32 Bytes - hash of a transaction
params: [
   '0xb903239f8543d04b5dc1ba6579132b143087c68db1b2168786408fcbce568238'
]

Returns Object – A transaction receipt object, or null when no receipt was found:

transactionHash: DATA, 32 Bytes – hash of the transaction. transactionIndex: QUANTITY – integer of the transactions index position in the block. blockHash: DATA, 32 Bytes – hash of the block where this transaction was in. blockNumber: QUANTITY – block number where this transaction was in. cumulativeGasUsed: QUANTITY – The total amount of gas used when this transaction was executed in the block. gasUsed: QUANTITY – The amount of gas used by this specific transaction alone. contractAddress: DATA, 20 Bytes – The contract address created, if the transaction was a contract creation, otherwise null. logs: Array – Array of log objects, which this transaction generated. Example

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// Request
curl -H "Content-Type:application/json" -X POST --data '{"jsonrpc":"2.0","method":"hpb_getTransactionReceipt","params":["0xb903239f8543d04b5dc1ba6579132b143087c68db1b2168786408fcbce568238"],"id":1}'

// Result
{
"id":1,
"jsonrpc":"2.0",
"result": {
     transactionHash: '0xb903239f8543d04b5dc1ba6579132b143087c68db1b2168786408fcbce568238',
     transactionIndex:  '0x1', // 1
     blockNumber: '0xb', // 11
     blockHash: '0xc6ef2fc5426d6ad6fd9e2a26abeab0aa2411b7ab17f30a99d3cb96aed1d1055b',
     cumulativeGasUsed: '0x33bc', // 13244
     gasUsed: '0x4dc', // 1244
     contractAddress: '0xb60e8dd61c5d32be8058bb8eb970870f07233155' // or null, if none was created
     logs: [{
         // logs as returned by getFilterLogs, etc.
     }, ...]
  }
}

hpb_getUncleByBlockHashAndIndex Returns information about a uncle of a block by hash and uncle index position.

Parameters

1
2
3
4
5
6
7
DATA, 32 Bytes - hash a block.
QUANTITY - the uncle's index position.
params: [
   '0xc6ef2fc5426d6ad6fd9e2a26abeab0aa2411b7ab17f30a99d3cb96aed1d1055b',
   '0x0' // 0
]

Returns See hpb_getBlockByHash

Example

1
2
3
4
5
6
// Request
curl -H "Content-Type:application/json" -X POST --data '{"jsonrpc":"2.0","method":"hpb_getUncleByBlockHashAndIndex","params":["0xc6ef2fc5426d6ad6fd9e2a26abeab0aa2411b7ab17f30a99d3cb96aed1d1055b", "0x0"],"id":1}'
Result see hpb_getBlockByHash

Note: An uncle doesn't contain individual transactions.

hpb_getUncleByBlockNumberAndIndex Returns information about a uncle of a block by number and uncle index position.

Parameters

1
2
3
4
5
6
7
QUANTITY|TAG - a block number, or the string "earliest", "latest" or "pending".
QUANTITY - the uncle's index position.
params: [
   '0x29c', // 668
   '0x0' // 0
]

Returns See hpb_getBlockByHash

Note: An uncle doesn’t contain individual transactions.

Example

1
2
3
4
// Request
curl -H "Content-Type:application/json" -X POST --data '{"jsonrpc":"2.0","method":"hpb_getUncleByBlockNumberAndIndex","params":["0x29c", "0x0"],"id":1}'
Result see hpb_getBlockByHash

hpb_newFilter Creates a filter object, based on filter options, to notify when the state changes (logs). To check if the state has changed, call hpb_getFilterChanges.

Parameters

1
2
3
4
5
6
7
8
9
10
11
12
Object - The filter options:
fromBlock: QUANTITY|TAG - (optional, default: "latest") Integer block number, or "latest" for the last mined block or "pending", "earliest" for not yet mined transactions.
toBlock: QUANTITY|TAG - (optional, default: "latest") Integer block number, or "latest" for the last mined block or "pending", "earliest" for not yet mined transactions.
address: DATA|Array, 20 Bytes - (optional) Contract address or a list of addresses from which logs should originate.
topics: Array of DATA, - (optional) Array of 32 Bytes DATA topics.
params: [{
  "fromBlock": "0x1",
  "toBlock": "0x2",
  "address": "0x8888f1f195afa192cfee860698584c030f4c9db1",
  "topics": ["0x000000000000000000000000a94f5374fce5edbc8e2a8697c15331677e6ebf0b"]
}]

Returns QUANTITY – A filter id.

Example

1
2
3
4
5
6
7
8
9
10
// Request
curl -H "Content-Type:application/json" -X POST --data '{"jsonrpc":"2.0","method":"hpb_newFilter","params":[{"topics":["0x12341234"]}],"id":73}'

// Result
{
  "id":1,
  "jsonrpc": "2.0",
  "result": "0x1" // 1
}

hpb_newBlockFilter Creates a filter in the node, to notify when a new block arrives. To check if the state has changed, call hpb_getFilterChanges.

Parameters None

Returns QUANTITY – A filter id.

Example

1
2
3
4
5
6
7
8
9
10
// Request
curl -H "Content-Type:application/json" -X POST --data '{"jsonrpc":"2.0","method":"hpb_newBlockFilter","params":[],"id":73}'

// Result
{
  "id":1,
  "jsonrpc":  "2.0",
  "result": "0x1" // 1
}

hpb_newPendingTransactionFilter Creates a filter in the node, to notify when new pending transactions arrive. To check if the state has changed, call hpb_getFilterChanges.

Parameters None

Returns QUANTITY – A filter id.

Example

1
2
3
4
5
6
7
8
9
10
// Request
curl -H "Content-Type:application/json" -X POST --data '{"jsonrpc":"2.0","method":"hpb_newPendingTransactionFilter","params":[],"id":73}'

// Result
{
  "id":1,
  "jsonrpc":  "2.0",
  "result": "0x1" // 1
}

hpb_uninstallFilter Uninstalls a filter with given id. Should always be called when watch is no longer needed. Additonally Filters timeout when they aren’t requested with hpb_getFilterChanges for a period of time.

Parameters

1
2
3
4
5
QUANTITY - The filter id.
params: [
  "0xb" // 11
]

Returns Boolean – true if the filter was successfully uninstalled, otherwise false.

Example

1
2
3
4
5
6
7
8
9
10
// Request
curl -H "Content-Type:application/json" -X POST --data '{"jsonrpc":"2.0","method":"hpb_uninstallFilter","params":["0xb"],"id":73}'

// Result
{
  "id":1,
  "jsonrpc": "2.0",
  "result": true
}

hpb_getFilterChanges Polling method for a filter, which returns an array of logs which occurred since last poll.

Parameters

1
2
3
4
5
QUANTITY - the filter id.
params: [
  "0x16" // 22
]

Returns Array – Array of log objects, or an empty array if nothing has changed since last poll.

For filters created with hpb_newBlockFilter the return are block hashes (DATA, 32 Bytes), e.g. [“0x3454645634534…”]. For filters created with hpb_newPendingTransactionFilter the return are transaction hashes (DATA, 32 Bytes), e.g. [“0x6345343454645…”]. For filters created with hpb_newFilter logs are objects with following params:

type: TAG – pending when the log is pending. mined if log is already mined. logIndex: QUANTITY – integer of the log index position in the block. null when its pending log. transactionIndex: QUANTITY – integer of the transactions index position log was created from. null when its pending log. transactionHash: DATA, 32 Bytes – hash of the transactions this log was created from. null when its pending log. blockHash: DATA, 32 Bytes – hash of the block where this log was in. null when its pending. null when its pending log. blockNumber: QUANTITY – the block number where this log was in. null when its pending. null when its pending log. address: DATA, 20 Bytes – address from which this log originated. data: DATA – contains one or more 32 Bytes non-indexed arguments of the log. topics: Array of DATA – Array of 0 to 4 32 Bytes DATA of indexed log arguments. (In solidity: The first topic is the hash of the signature of the event (e.g. Deposit(address,bytes32,uint256)), except you declared the event with the anonymous specifier.) Example

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// Request
curl -H "Content-Type:application/json" -X POST --data '{"jsonrpc":"2.0","method":"hpb_getFilterChanges","params":["0x16"],"id":73}'

// Result
{
  "id":1,
  "jsonrpc":"2.0",
  "result": [{
    "logIndex": "0x1", // 1
    "blockNumber":"0x1b4" // 436
    "blockHash": "0x8216c5785ac562ff41e2dcfdf5785ac562ff41e2dcfdf829c5a142f1fccd7d",
    "transactionHash":  "0xdf829c5a142f1fccd7d8216c5785ac562ff41e2dcfdf5785ac562ff41e2dcf",
    "transactionIndex": "0x0", // 0
    "address": "0x16c5785ac562ff41e2dcfdf829c5a142f1fccd7d",
    "data":"0x0000000000000000000000000000000000000000000000000000000000000000",
    "topics": ["0x59ebeb90bc63057b6515673c3ecf9438e5058bca0f92585014eced636878c9a5"]
    },{
      ...
    }]
}

hpb_getFilterLogs Returns an array of all logs matching filter with given id.

Parameters

1
2
3
4
5
QUANTITY - The filter id.
params: [
  "0x16" // 22
]

Returns See hpb_getFilterChanges

Example

1
2
3
4
// Request
curl -H "Content-Type:application/json" -X POST --data '{"jsonrpc":"2.0","method":"hpb_getFilterLogs","params":["0x16"],"id":74}'
Result see hpb_getFilterChanges

hpb_getLogs Returns an array of all logs matching a given filter object.

Parameters

1
2
3
4
5
Object - the filter object, see hpb_newFilter parameters.
params: [{
  "topics": ["0x000000000000000000000000a94f5374fce5edbc8e2a8697c15331677e6ebf0b"]
}]

Returns See hpb_getFilterChanges

Example

1
2
3
4
// Request
curl -H "Content-Type:application/json" -X POST --data '{"jsonrpc":"2.0","method":"hpb_getLogs","params":[{"topics":["0x000000000000000000000000a94f5374fce5edbc8e2a8697c15331677e6ebf0b"]}],"id":74}'
Result see hpb_getFilterChanges

personal_newAccount Returns a new account public address

Parameters

1
2
3
4
5
DATA
params: [{
        '12345678'
    }]


Returns DATA – address:

Example

1
2
3
4
5
6
7
8
9
10
11
12
// Request
curl -H "Content-Type:application/json" -X POST --data '{"jsonrpc":"2.0","method":"personal_newAccount","params":['12345678'],"id":83}'

// Result
{
  "id":1,
  "jsonrpc":"2.0",
  "result": [
      "0x5670b4f2810115fd7cf198433345a7e767de82bf"
    ]
}

感谢HPB技术团队整理。

HPB68:HPB DAPP 介绍

首先Dapp是一种服务,最初在ETH上运行,现在大多数公链都支持此服务,HPB也同样支持,DAPP可以实现最终用户和提供商之间的直接交互(例如,在一些市场中连接买家和卖家,在文件存储中连接所有者和商店)。 HPB Dapps通常使用Javascript API通过HTML / Javascript Web应用程序与用户进行交互,以与HPB区块链进行通信。 Dapps通常在区块链上拥有自己的相关合约套件,用于编码业务逻辑并允许持久存储其共识关键状态。请记住,由于HPB网络上计算的冗余性,执行的GAS成本总是高于私有执行链。这激励了dapp开发人员限制他们执行的代码量以及他们存储在区块链上的数据量。

Dapp目录

ETH Dapps列在各个开发阶段(概念,工作原型,实时/部署),如果您正在开发dapp,请考虑在这些列表中添加条目:

所提供的分散服务覆盖范围广泛,包括金融,保险,预测市场,社交网络,分布式计算和存储,赌博,市场,物联网,治理,协作,开发和游戏。

将来,dapps可能会在dapp浏览器中集成的dapp stores中分发。

Dapp浏览器

开发者工具

Dapp开发需要了解Web3 Javascript API,JSON RPC API和Solidity编程语言。

注意

有一些开发工具可以帮助您利用下面列出的资源去开发,方便测试和部署dapps。

  • Web3 JavaScript API – 这是JavaScript SDK,用于连接HPB 节点。
  • JSON RPC API – 这是JSON RPC 2.0的API,用来跟HPB 节点交互. 这个API主要是给 Web3 JavaScript API用.
  • HPB Web3j Java SDK
  • Solidity Docs – Solidity是以太坊开发的智能合约语言,它编译为EVM(以太坊虚拟机)操作码。
  • Solium – 严格遵守官方Solidity Style Guide规定的Solidity。
  • HPB测试网络 – 测试网络帮助开发人员开发和测试HPB代码和网络交互,而无需在主网络上使用自己的HPB 代币,HPB 测试网络暂时没运行,敬请期待。
  • Dapp开发资源。这有助于您开发,调试和部署以太坊应用程序。

Dapp开发资源

常见例子

教程

MIX-IDE

Mix是官方的以太坊IDE,同时也用于HPB的dapp开发,它允许开发人员在HPB区块链之上构建和部署合同和分散的应用程序。它包括Solidity源代码调试器的IDE /框架。

下面是用于编写dapps的常用开发框架和IDE。

  • Truffle – 是以太坊的开发环境,测试框架和资产管道。

  • Dapple - Dapple是Solidity开发人员的工具,可帮助构建和管理类似以太坊区块链的复杂合同系统。

  • Populus -Populus是一个用python编写的智能合约开发框架。

  • Eris-PM - Eris Package Manager在私人和公共链上部署和测试智能合约系统。

  • Embark - Embark是一个用JavaScript编写的Ðapp开发框架。

感谢HPB技术团队整理。

HPB67:ETH DAPP到HPB主网平滑迁移攻略

1 概述

1.1 前言

本文档主要从技术角度对HPB区块链去中心化应用(以下简称“DAPP”)项目常用的演示案例,包括Web3js,JAVA

文档阅读人员:社区开发人员、测试人员、运维人员。

1.2 项目背景

为全面推进DAPP系统建设,落实软件产品线和领域工程的具体要求,形成自主产权基础框架和领域构件库,设立了DAPP项目。

2 把基于以太坊的ERC20的HPB代币平滑迁移到HPB区块链上

2.1 迁移流程如下

2.2 在太坊浏览器查询HPB ERC20 Token

进入以太坊浏览器查询HPB ERC20 Token

https://etherscan.io/tokens

在搜索框输入HPB,选择HPBCoin

2.3 复制HPB ERC20 Token源代码到remix

点击HPBERC20的智能合约地址

然后点击Code查看HPB ERC20的源代码

点击Copy复制源代码

打开solidity智能合约在线编译器

https://remix.ethereum.org/#optimize=true&version=soljson-v0.4.11+commit.68ef5810.js

粘贴代码到编辑器中,选择编译器编译版本为v0.4.11

2.4 重新编译HPB ERC20 Token源代码

点击查看详情

2.5 通过HPB版本的javaSDK部署合约到HPB区块链然后调用智能合约

通过生成智能合约对应的java包装类面向对象式的运行智能合约

分别新建HPBToken.abi和HPBToken.bin文件并把以上复制的abi和bin代码复制到对应的文件中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
引入HPB的java SDk

<dependency>

    <groupId>io.hpb.web3</groupId>

    <artifactId>web3-hpb</artifactId>

    <version>1.2.0</version>

</dependency> 

//新建生成合约包装类GenContract

import java.util.Arrays;

import io.hpb.web3.codegen.SolidityFunctionWrapperGenerator;

public class GenContract {

                  public static void main(String[] args) {

                                    try {

                                    String SOLIDITY_TYPES_ARG = "--solidityTypes";

                                    String packageName = "io.hpb.web3.contracts";

                                    String outDirPath = "D:/contracts/java/";

                                    String binDirPath = "D:/contracts/HPBToken.bin";

                                    String abiDirPath = "D:/contracts/HPBToken.abi";

                                                                                          SolidityFunctionWrapperGenerator.main(Arrays.asList(SOLIDITY_TYPES_ARG,
                                                                                      binDirPath,
                                                                                  abiDirPath,
                                                                                       "-p", packageName, "-o", outDirPath).toArray(new String[0]));

                                    } catch (Exception e) {

                                                      e.printStackTrace();
                                    }

                  }

}

   

//生成后的类为HPBToken.java

//删除掉所有构造方法

protected HPBToken(String contractAddress, Web3 web3, Credentials credentials,

            BigInteger gasPrice, BigInteger gasLimit) {

        super(BINARY, contractAddress, web3, credentials, gasPrice, gasLimit);

}

protected HPBToken(String contractAddress, Web3 web3, TransactionManager transactionManager,BigInteger gasPrice, BigInteger gasLimit) {

        super(BINARY, contractAddress, web3, transactionManager, gasPrice, gasLimit);

}

//添加新的构造方法

protected HPBToken(String contractAddress, Web3 web3, Credentials credentials,

        BigInteger gasPrice, BigInteger gasLimit) {

     super(BINARY, contractAddress, web3, new RawTransactionManager(web3, credentials), new StaticGasProvider(gasPrice, gasLimit));

}

 

protected HPBToken(String contractAddress, Web3 web3, TransactionManager transactionManager,BigInteger gasPrice, BigInteger gasLimit) {

     super(BINARY, contractAddress, web3, transactionManager, new StaticGasProvider(gasPrice, gasLimit));

}

protected HPBToken(String contractAddress,

            Web3 web3, TransactionManager transactionManager,ContractGasProvider gasProvider) {

                  super(BINARY, contractAddress, web3, transactionManager, gasProvider);

}

自行在本地建立HPB开发者节点,发布智能合约和调用智能合约,代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
private static final int WEB3J_TIMEOUT = 800;

                  public static void main(String[] args) throws Exception{

                                    BigInteger gasPrice = Convert.toWei("18", Convert.Unit.GWEI).toBigInteger();

                                    BigInteger gasLimit = new BigInteger("99000000");

                                    Credentials credentials = WalletUtils.loadCredentials(password,keyStorePath);

                                    Web3Service web3Service = buildService(clientAddress);

                                    Admin admin = Admin.build(web3Service);

                                    RawTransactionManager transactionManager=new RawTransactionManager(admin, credentials, ChainId.MAINNET);

                                    Address _target=new Address(address);

                                    HPBToken hpbTokenDeploy = HPBToken.deploy(admin, transactionManager, gasPrice, gasLimit, _target).

                                    sendAsync().get(WEB3J_TIMEOUT, TimeUnit.MINUTES);

                                    String contractAddress=hpbTokenDeploy.getContractAddress();

                                    log.info("发布智能合约成功,合约地址为:"+contractAddress);

                                    HPBToken hpbToken = HPBToken.load(contractAddress, admin, transactionManager, gasPrice, gasLimit);

                                    Bool bool = hpbToken.saleStarted().sendAsync().get(WEB3J_TIMEOUT, TimeUnit.MINUTES);

                                    log.info(bool);

TransactionReceipt receipt = hpbToken.transfer(new Address("0x09fe745cff05b35cb06da6768586279018c08d7f"), 

                                                                        new Uint256(Convert.toWei("10", Convert.Unit.HPB).toBigInteger())).sendAsync()

                                    .get(WEB3J_TIMEOUT, TimeUnit.MINUTES);

                                    log.info(receipt.isStatusOK());

                  }

                  private static Web3Service buildService(String clientAddress) {

                                    Web3Service Web3Service;

                                    if (clientAddress == null || clientAddress.equals("")) {

                                    Web3Service = new HttpService(createOkHttpClient());

                                    } else if (clientAddress.startsWith("http")) {

                                    Web3Service = new HttpService(clientAddress,       createOkHttpClient(), false);

                                    } else if (System.getProperty("os.name").toLowerCase().startsWith("win")) {

                                    Web3Service = new WindowsIpcService(clientAddress);

                                    } else {

                                   Web3Service = new UnixIpcService(clientAddress);

                                    }

 

                                    return Web3Service;

                  }

 

                  private static OkHttpClient createOkHttpClient() {

                          OkHttpClient.Builder builder = new OkHttpClient.Builder();

                           configureLogging(builder);

                           configureTimeouts(builder);

                           return builder.build();

                  }

 

                  private static void configureTimeouts(OkHttpClient.Builder builder) {

                           builder.connectTimeout(WEB3J_TIMEOUT, TimeUnit.SECONDS);

                           builder.readTimeout(WEB3J_TIMEOUT, TimeUnit.SECONDS); 
                           // Sets the socket timeout too

                           builder.writeTimeout(WEB3J_TIMEOUT, TimeUnit.SECONDS);

                  }


                  private static void configureLogging(OkHttpClient.Builder builder) {

                       if (log.isDebugEnabled()) {

                         HttpLoggingInterceptor logging = new HttpLoggingInterceptor(log::debug);
                                                   logging.setLevel(HttpLoggingInterceptor.Level.BODY);

                        builder.addInterceptor(logging);

                                    }

                  }

2.6 通过PB版本的Web3js部署合约到HPB区块链然后调用智能合约

Web3.js实现部署和调用合约代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
var Web3ForHpb = require('web3_hpb');

var web3Hpb = new Web3ForHpb();

web3Hpb.setProvider(new web3Hpb.providers.HttpProvider("http://localhost:8545"));

web3Hpb.hpb.contract(abi).new({

    data: '0x' + bytecode,

    from: "",

    gas: 1000000

}, (err, res) => {

    if (err) {

        console.log(err);

        return;

    }

    console.log(res.transactionHash);

    // If we have an address property, the contract was deployed

    if (res.address) {

        console.log('Contract address: ' + res.address);

    }

});
 var hpbTestContract = web3Hpb.hpb.contract(abi).at(contractAddress);

console.log(hpbTestContract.getContractAddr.call());

3 迁移总结

任何基于以太坊区块链的Dapp的合约代码都可以通过相同的流程平滑迁移到HPB的区块链上;复制原始智能合约代码,利用remix来重新编译,拷贝对应的编译好的bin和abi文件,通过HPB版本的javaSDK和HPB版本的web3js来发布和调用该DAPP的智能合约。

感谢HPB技术团队整理。

HPB66:HPB钱包和中间件接口介绍

为方便开发者更容易的开发或者使用HPB钱包,HPB的钱包开发者们准备了一份常用的API接口介绍。

1 Hpb Version Controller

1.1 查询版本号

描述:app钱包查询版本号。

请求说明:

1
2
 请求方式: POST 
 请求URL:http://47.75.96.163:9888/HpbComponent/cms/version

调用示例:

1
2
3
4
5
[

  "1","0"

]

请求参数说明:

参数名 是否必须 描述
1 设备类型:(0 安卓或1 IOS); |
0 参数2:language_type(0:中文或 1:英文); |

返回数据示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
[

  "000000",                                                                                                 //响应状态(000000:成功;999999:失败)

  "成功",                                                                                                                            //响应消息提示
  {
 
 "map": {},                                                                                                                     //预留map

  "id": 36,                                                                                                                         //当前版本id

  "verNo": "1.0.0",                                                                                                         //版本号

  "downloadUrl": "https://fir.im/mw6r",                             
//下载地址

  "mobileType": 1,                                                                                      //手机类型 0-安卓 1-IOS 2-其它

  "remark": "1.0.2测试1120180806111",                       
//备注

  "createTime": 1533547987870,                                      
//创建时间戳

  "updateTime": 1534570817329,                                     
//更新时间戳

  "state": "1",                                                                                                    //状态:1-生效;0-失效

  "userId": 1,                                                                                                 //用户id

  "isForceFlag": "0",                                                                                    //是否强制更新:1-是;0-否

  "langType": "0",                                                                                                          //语言类型:0-中文;1-英文

  "verContent": "a1.0.2"                                                         //版本内容

  }

]

2 Personal Controller

2.1 获取账户余额

描述:app钱包用户获取账户余额。

请求说明:

1
2
请求方式: POST 
请求URL:http://47.75.96.163:9888/HpbComponent/personal/getBalance

调用示例:

1
2
3
4
5
[

  "0x09a0e8893efd605e6aaae9b0c8285a3f16e5f198"

]

请求参数说明:

参数名 是否必须 描述
参数1 address(0x开头的地址,42位hash) |
|

返回数据示例:

1
2
3
4
5
6
7
8
9
[

  "000000",                                                                                                                      //响应状态(000000:成功;999999:失败)

  "成功",                                                                                                                                              //响应消息提示

  0                                                                                                   //余额

]

2.2 获取账户nonce

描述:app钱包用户获取账户的nonce。

请求说明:

1
2
请求方式: POST 
请求URL:http://47.75.96.163:9888/HpbComponent/personal/getNonce

调用示例:

1
2
3
4
5
[

  "0x09a0e8893efd605e6aaae9b0c8285a3f16e5f198"

]

请求参数说明:

参数名 是否必须 描述
参数1 address(0x开头的地址,42位hash) |

返回数据示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[

   "000000",                                                                                                                     //响应状态(000000:成功;999999:失败)

  "成功",                                                                                                                                              //响应消息提示

  {
  "gasLimit": "50000",                                                                               // gasLimit

  "nonce": 0,                                                                                                 //nonce

  "gasPrice": "18000000000"                                                                 // gasPrice  
  }                                                                                  

]

3 Personal Controller

3.1 查询交易

描述:app钱包根据交易hash查询交易。

请求说明:

1
2
请求方式: POST 
请求URL:http://47.75.96.163:9888/HpbComponent/transaction/getTransactionByHash

调用示例:

1
2
3
4
5
[

  " 0x78a7012f467035e4ca1a8f6dffe6e138e1a24e591ba4945de5ef74bbcb69cd63"

]

请求参数说明:

参数名 是否必须 描述
参数1 交易hash(0x开头的地址,64位hash) |

返回数据示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
[

  "000000",                                                                                  //响应状态(000000:成功;999999:失败)

  "成功",                                                                                                                                              //响应消息提示

  {

 "hash": "0xdd19d1946bc000294d5d5e2ee01943bdd07165576460bd20e739964029214071",                                                                                                                        //交易hash

  "nonce": 2,                                                             //nonce

  "blockHash": "0x638055808a31f15e0854baca5e688c4d8e15910c06c4ea56a389f567a00d8671",                                                                                                                        //所在块的hash   

"blockNumber": 150318,                                      
//所在块高

 "transactionIndex": 0,                                        
//交易在区块内的序号

  "from": "0x847af04fbd21a909726cf00aaa06acd820035d5a",                                                       //交易发起方

  "to": "0x3795435afaec3bfb2388a1e2ef58108f564d3e07",                      
//交易接收方

  "value": 0,                                                                                //发送金额

  "gasPrice": 18000000000,                                                 
// gasPrice

  "gas": 90000,                                                        
 // gas

  "input": "0x7b0d0a09226772616365506572696f64223a20223135222c0d0a092270726548617368223a2022222c0d0a092263757374636453616c6c6572223a2022313030373431222c0d0a0922696e7365727444617465223a2022323031382d30382d3136222c0d0a09226d656d6f223a2022222c0d0a0922636e616d6553656c6c6572223a2022e58d83e5b29be6b996e69e97e69ca8e58aa0e5b7a5e69c89e99990e585ace58fb8222c0d0a09226275737354797065223a202231323330303130222c0d0a092264656274456e64223a2022323031382d31302d3135222c0d0a0922646561644c696e65223a2022323031382d31302d3330222c0d0a092262696c6c7354797065223a20223031222c0d0a09226375737463644275796572223a2022313030373433222c0d0a092262696c6c73416d6f756e74223a202233303030302e3030222c0d0a092272656d61696e696e67416d6f756e74223a202233303030302e3030222c0d0a092262696c6c7344617465223a2022323031382d30382d3136222c0d0a09226d617374436f6e746e6f223a2022474e424c32303138303831363030303031222c0d0a092262696c6c734e6f223a2022505a485432303138303832313031222c0d0a092262696c6c73416d6f756e7456696577223a202233303030302e3030222c0d0a092262757373436f6e74636f6465223a20225357485432303138303832313031222c0d0a09226167696e67223a20223630222c0d0a0922636e616d654275796572223a2022e6b599e6b19fe697b6e997b4e69e97e7a791e68a80e69c89e99990e8b4a3e4bbbbe585ace58fb8222c0d0a0922737461747573223a20223031220d0a7d",                                                          
  //交易内附带信息(input字段)

   "creates": null,                                                      

   "publicKey": null,

   "raw": null,

   "r": "0xe417129af6776b6985ef95b92ef25b4e1c0025eb387b8e097aa182f89de889c7",

   "s": "0x5193ba9a5378f7d19f72a3e717dd5096fbc06f3a79c358c790475b385fe30225",

    "v": 37,

    "transactionIndexRaw": "0x0",

    "blockNumberRaw": "0x24b2e",

    "nonceRaw": "0x2",

    "valueRaw": "0x0",

    "gasPriceRaw": "0x430e23400",

    "gasRaw": "0x15f90"

  }                                                                

]

3.2 查询交易历史

描述:app钱包用户获取本地账户的交易历史。

请求说明:

1
2
3
4
请求方式: POST 
请求URL:http://47.75.96.163:9888/HpbComponent/transaction/getTransactionHistory


调用示例:

1
2
3
4
5
[

  " 0x847af04fbd21a909726cf00aaa06acd820035d5a","0","1"

]

请求参数说明:

参数名 是否必须 描述
参数1 address(0x开头的地址,42位hash), |
参数2 交易类型(0-所有 1-发送 2-接收), |
参数3 页码数 >0 |

返回数据示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
[

  "000000",                                                                                  

//响应状态(000000:成功;999999:失败)

  "成功",                                                                                                                                              

//响应消息提示

  {

 "pageNum": 1,                                                                        //当前页码数

 "pageSize": 10,                                                                        //当前页大小

 "size": 6,                                                                                   //数据量

 "startRow": 1,                                                                          //开始行

 "endRow": 6,                                                                            //结束行

  "total": 6,                                                                                  //总记录数

  "pages": 1,                                                                                //总页数

  "list": [                                                                                       //数据list

   {

  "map": {},                                                                                //预留map

  "transactionHash": "0xf467c92777a820cb92f75556b5d06f69b635197c997b910c7dc4219a83f85ef9",
                                                                                                               //交易hash

  "fromAccount": "0x847af04fbd21a909726cf00aaa06acd820035d5a",             

//发起方

 "toAccount": "0x3795435afaec3bfb2388a1e2ef58108f564d3e07",                    

//接收方

  "nonce": 4,                                                                                  //nonce

 "tValue": "0",                                                                            //金额

  "gas": "90000",                                                                      //gas

 "gasPrice": "18000000000",                                                //gasPrice

 "status": "0x1",                                                                    //状态

 "blockHash": "0x9163f7ff6b4611b3bd6957c4560ff3a45d4cc31f85753f6ec6819bd33d67eb34",                                                                                                   //所在块的hash

 "blockNumber": 150612,                                                  
 //块高

 "transactionIndex": null,                                                    //交易在块中的序号

 "tTimestap": 1534820055,                                                
//时间戳

  "gasUsed": "633",                                                               //gas费用

 "remark": null,                                                                     //

 "tInput": null,                                                                       //输入参数字段

 "actulTxFee": "11394000000000"

   }      

],

  "prePage": 0,                                                                             //前一页

  "nextPage": 0,                                                                           //下一页

  "isFirstPage": true,                                                                   //是否是第一页

  "isLastPage": true,                                                                   //是否是最后一页

  "hasPreviousPage": false,                                                      //是否有前一页

   "hasNextPage": false,                                                             //是否有下一页

   "navigatePages": 8,                                                                 //可显示的最大页数

   "navigatepageNums": [         //页数字段                                                 
      1
    ],

    "navigateFirstPage": 1,                                                               //第一页

    "navigateLastPage": 1,                                                            //最后一页

    "firstPage": 1,                                                                           //第一页

    "lastPage": 1                                                                             //最后一页

  }                                              

]

3.3 发送交易

描述:app钱包用户发起交易。

请求说明:

1
2
请求方式: POST 
请求URL:http://47.75.96.163:9888/HpbComponent/transaction/sendRawTransaction

调用示例:

1
2
3
4
5
[

  " 0xf467c92777a820cb92f75556b5d06f69b635197c997b910c7dc4219a83f85ef9"

]

请求参数说明:

参数名 是否必须 描述
参数1 签名后hash数据(0x开头hash数据,16进制数据,测试异常情况) |

返回数据示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
[
  "000000",                                                                                  //响应状态(000000:成功;999999:失败)

  "成功",                                                                                                                                              //响应消息提示

  {
  "hash": "0xdd19d1946bc000294d5d5e2ee01943bdd07165576460bd20e739964029214071",                                                                                                                                                          //交易hash

  "nonce": 2,                                                                                                  //nonce

  "blockHash": null,                                                                  //交易还在打包,块值为空

  "blockNumber": null,                                                            //交易还在打包,块值为空

  "transactionIndex": null,                                                      //交易还在打包

  "from": "0x847af04fbd21a909726cf00aaa06acd820035d5a",                                  //发送方

  "to": "0x3795435afaec3bfb2388a1e2ef58108f564d3e07",                      
//接收方

 "value": 0,                                                                                                  //值

 "gasPrice": 18000000000,                                                  //gasPrice

 "gas": 90000,                                                                          // gas number

 "input": null,                                                                            // input字段

 "creates": null,  
// null

  "publicKey": null,                                                                     // null

  }                                              

]

 

感谢HPB技术团队整理。

HPB65:HPB节点安全加固指南

第一章 阅读总览

1.1 适用范围

为了提高HPB节点服务器的安全性,HPB芯链决定采纳安全审计公司的服务器安全加固方案,适用于使用Linux版本操作系统的HPB节点服务器,本指南旨在指导节点用户对其服务器进行安全合规性检查和配置。

1.2 阅读建议

编号 内容 说明
1 服务器安全检测脚本使用指导 指导节点用户下载、运行服务器安全检测脚本,检查服务器安全配置。详情参考第二章。 |
2 检查项详情 详细介绍脚本里涉及到的22个检查项及其配置修改步骤。详情参考第三章。 |

第二章 服务器安全监测脚本使用指导

2.1 使用步骤

为了简化用户的操作步骤,HPB芯链将提供服务器安全检测脚本,用户运行脚本后将自动对服务器的Linux系统进行安全配置检查。

编号 步骤 说明
1 下载脚本 命令:”git clone *https://github.com/hpb-project/systemcheck*“ |
2 设置权限 命令:”cd systemcheck
命令:”chmod +x systemcheck.sh“ |
3 运行脚本 命令:”sudo ./systemcheck.sh
提示:用户需根据提示输入当前账户的登录密码;
出现”未安装chkconfig,是否安装(y/n)”时,用户需输入”y”。 |
4 查看结果 命令:“ vi servercheck.txt
提示:通过的检查项会提示”安全”,未通过的会提示”不安全”。
如需修改配置,用户可参考第三章检查项详情。
第n个检查项对应第3.n节。 |

HPB芯链建议用户将运行结果中未通过的检查项修改为安全配置,修改步骤详见第三章。

使用示例

(1) 步骤1 下载服务器安全检测脚本

打开终端,输入” git clone https://github.com/hpb-project/systemcheck*“;

1
2
3
4
5
6
7
8
9
hpb@dell-PowerEdge-R730:~$ git clone https://github.com/hpb-project/systemcheck
Cloning into 'systemcheck'...
remote: Enumerating objects: 8, done.
remote: Counting objects: 100% (8/8), done.
remote: Compressing objects: 100% (6/6), done.
Unpacking objects: 100% (8/8), done.
remote: Total 8 (delta 2), reused 8 (delta 2), pack-reused 0
Checking connectivity... done.
hpb@dell-PowerEdge-R730:~$

(2) 步骤2 设置文件权限

输入” cd systemcheck

1
2
hpb@dell-PowerEdge-R730:~$ cd systemcheck
hpb@dell-PowerEdge-R730:~/systemcheck$

继续输入设置文件权限

输入” chmod +x systemcheck.sh

1
2
hpb@dell-PowerEdge-R730:~$ cd systemcheck
hpb@dell-PowerEdge-R730:~/systemcheck$

(3) 步骤3 运行脚本

输入” sudo ./systemcheck.sh“,根据提示输入当前用户的登录密码,文件将会自动检测服务器配置;

1
2
3
4
5
6
7
8
9
10
11
hpb@dell-PowerEdge-R730:~/systemcheck$ sudo ./systemcheck.sh
[sudo] password for hpb:
开始检查...
 1.检查密码有效期设置
 2.检查密码强度检查配置
 3.检查空口令账号
 4.检查账户锁定配置
 5.检查除root之外的账户UID0
 6.检查环境变量包含父目录
 7.检查环境变量包含组权限为777的目录
……

用户需等待片刻,当提示” 未安装chkconfig,是否安装 (y/n) :“时,用户需输入”y”安装chkconfig;出现”检查完成, 请仔细阅读servercheck.txt文件”信息表示安全检测已完成。

1
2
3
4
5
6
7
8
9
10
检查运行的服务
未安装chkconfig,是否安装 (y/n) :y
Reading package lists... Done
Building dependency tree
Reading state information... Done
……
Setting up sysv-rc-conf (0.99-7) ...
安装成功
20.检查core dump 状态
检查完成, 请仔细阅读servercheck.txt文件

(4) 步骤4 查看运行结果

输入”vi servercheck.txt“,将会显示运行结果,结果中共有22个检查项,通过的检查项会提示”安全”,未通过的检查项会提示”不安全”,HPB芯链建议用户将未通过的检查项改为安全配置,用户可参考第三章查看具体检查项的修改步骤。 提示:第n项检查项对应第3.n节,共22个检查项。

1
2
3
4
5
6
7
8
9
10
hpb@dell-PowerEdge-R730:~/systemcheck$ vi servercheck.txt
1. 未配置密码超时时间,不安全
建议:
  执行 sed -i '/PASS_MAX_DAYS/s/99999/90/g' /etc/login.defs 设置密码的有效时间为90
2. 未配置密码强度检查,不安全
建议:
  执行 echo "passwd requisite pam_cracklib.so difok=3 minlen=8 ucrediit=-1 lcredit=-1 dcredit=-1">> /etc/pam.d/
systemd-auth 设置密码需要包含大小写字母及数字,且长度至少为8
3. 未发现空密码账户,安全
……

第三章 检查项详情

3.1 密码有效期设置

配置修改步骤

编号 步骤 说明
1 切换root用户 命令:” su root
提示:用户需根据提示输入root账户密码 |
2 设置密码有效期(90天) 命令:” sed -i \‘/PASS_MAX_DAYS/s/99999/90/g\’ /etc/login.defs“ |

配置修改示例

(1) 步骤一 切换成root用户 打开终端,输入”su root“,根据提示输入root账户密码;

1
2
3
hpb@dell-PowerEdge-R730:~$ su root
Password:
root@dell-PowerEdge-R730:/home/hpb#

(2) 步骤二 设置密码有效期 输入”sed -i \‘/PASS_MAX_DAYS/s/99999/90/g\’ /etc/login.defs“即可设置密码的有效时间为90天,该命令无返回信息。

1
root@dell-PowerEdge-R730:/home/hpb# sed -i '/PASS_MAX_DAYS/s/99999/90/g' /etc/login.defs

3.2 密码强度检查配置

配置修改步骤

编号 步骤 说明
1 切换root(已切换的用户可跳过) 命令:” su root
提示:用户需根据提示输入root账户密码 |
2 配置密码强度检查 命令:”echo \“passwd requisite pam_cracklib.so difok=3 minlen=8 ucrediit=-1 lcredit=-1 dcredit=-1\”>> /etc/pam.d/systemd-auth“ |

配置修改示例

(1) 步骤一 切换成root用户 打开终端,输入”su root“,根据提示输入root账户密码; 提示:已经切换成root用户的可以跳过该步骤。

1
2
3
hpb@dell-PowerEdge-R730:~$ su root
Password:
root@dell-PowerEdge-R730:/home/hpb#

(2) 步骤二 配置密码强度检查 输入” echo \“passwd requisite pam_cracklib.so difok=3 minlen=8 ucrediit=-1 lcredit=-1 dcredit=-1\”>> /etc/pam.d/systemd-auth“即可设置密码需要包含大小写字母及数字且长度至少为8,该命令无返回信息;

1
2
root@dell-PowerEdge-R730:/home/hpb#  echo "passwd requisite pam_cracklib.so difok=3 minlen=8 ucrediit=-1 lcredit=-1 dcredit=-1">> /etc/pam.d/systemd-auth
root@dell-PowerEdge-R730:/home/hpb#

3.3空口令账户

配置修改步骤

编号 步骤 说明
1 切换root(已切换的用户可跳过) 命令:” su root
提示:用户需根据提示输入root账户密码 |
2 设置账户密码 命令:”passwd 账户名
提示:用户需将账户名换成自己未设置密码的账户名;
按照提示输入两次新密码即可。 |

配置修改示例

(1) 步骤一 切换成root用户

打开终端,输入”su root“,根据提示输入root账户密码;

提示:已经切换成root用户的可以跳过该步骤。

1
2
3
hpb@dell-PowerEdge-R730:~$ su root
Password:
root@dell-PowerEdge-R730:/home/hpb#

(2) 步骤二 设置账户密码

输入”passwd 账户名“,根据提示输入新密码,重复输入后密码设置成功。

提示:用户需将账户名换成自己未设置密码的账户名,示例中账户为”test”。

1
2
3
4
root@dell-PowerEdge-R730:/home/hpb# passwd test
Enter new UNIX password:
Retype new UNIX password:
passwd: password updated successfully

3.4 账户锁定配置

配置修改步骤

编号 步骤 说明
1 切换root(已切换的用户可跳过) 命令:” su root
提示:用户需根据提示输入root账户密码 |
2 设置账户锁定策略 命令:”echo \“auth required pam_tally.so onerr=fail deny=10 unlock_time=300\” >> /etc/pam.d/systemd-auth“ |

配置修改示例

(1) 步骤一 切换成root用户

打开终端,输入”su root“,根据提示输入root账户密码;

提示:已经切换成root用户的可以跳过该步骤。

1
2
3
hpb@dell-PowerEdge-R730:~$ su root
Password:
root@dell-PowerEdge-R730:/home/hpb#

(2) 步骤二 设置账户锁定策略

输入” echo \“auth required pam_tally.so onerr=fail deny=10 unlock_time=300\” >> /etc/pam.d/systemd-auth“即可设置连续输错10次则锁定账户,该命令无返回信息;

提示:解锁账户的命令为” faillog -u <user> -r“。

1
2
root@dell-PowerEdge-R730:/home/hpb#  echo "auth required pam_tally.so onerr=fail deny=10 unlock_time=300" >> /etc/pam.d/systemd-auth
root@dell-PowerEdge-R730:/home/hpb#

3.5 UID为0的账户

配置修改步骤

编号 步骤 说明
1 切换root(已切换的用户可跳过) 命令:” su root
提示:用户需根据提示输入root账户密码 |
2 修改UID为0的账户 命令:” usermod -u <new-uid> <user>
命令:”groupmod -g <new-gid> <user>“ |

配置修改示例

(1) 步骤一 切换成root用户

打开终端,输入”su root“,根据提示输入root账户密码;

提示:已经切换成root用户的可以跳过该步骤。

1
2
3
hpb@dell-PowerEdge-R730:~$ su root
Password:
root@dell-PowerEdge-R730:/home/hpb#

(2) 步骤二 修改UID为0的账户

输入” usermod -u <new-uid> <user>“;继续输入”groupmod -g <new-gid> <user>“。

提示:<user>为账户名,需替换为UID为0的账户名;<new-uid>需替换为新uid;<new-gid>为参数。

3.6 环境变量包含父目录

如果环境变量中存在父目录,建议用户修改配置,环境变量中不要带有父目录。

3.7 环境变量包含组权限为777的目录

如果环境变量中包含组权限为777的目录,建议用户使用chmod命令修改运行结果中目录的权限。

3.8 远程连接安全性

如果远程连接安全性未通过检测,建议用户和管理员联系确认运行结果中的文件是否必要,如非必要,应当删除。

3.9 Umask配置

配置修改步骤

编号 步骤 说明
1 切换root(已切换的用户可跳过) 命令:” su root
提示:用户需根据提示输入root账户密码 |
2 umask未配置 命令:”echo \“umask 027\” >> /etc/profile
命令:”echo \“umask 027\” >> /etc/bash.bashrc“ |
2’ umask配置不安全 命令:”vi /etc/profile
移动光标找到umask参数,将其后的数字修改为”027”
命令:”vi /etc/bash.bashrc
移动光标找到umask参数,将其后的数字修改为”027” |

配置修改示例

(1) 步骤一 切换成root用户

打开终端,输入”su root“,根据提示输入root账户密码;

提示:已经切换成root用户的可以跳过该步骤。

1
2
3
hpb@dell-PowerEdge-R730:~$ su root
Password:
root@dell-PowerEdge-R730:/home/hpb#

(2) 步骤二 umask未配置

输入” echo \“umask 027\” >> /etc/profile“即可,该命令无返回信息; 输入” echo \“umask 027\” >> /etc/bash.bashrc“即可,该命令无返回信息;

1
2
root@dell-PowerEdge-R730:/home/hpb#  echo "umask 027" >> /etc/profile 
root@dell-PowerEdge-R730:/home/hpb# echo "umask 027" >> /etc/bash.bashrc

(3) 步骤二’ umask配置不安全

输入” vi /etc/profile“;按”↓”键将光标移动到umask参数上,将其紧跟的数字修改为”027”;

1
2
3
4
5
6
7
8
9
10
11
12
13
root@dell-PowerEdge-R730:/home/hpb# vi /etc/profile
if [ -d /etc/profile.d ]; then
  for i in /etc/profile.d/*.sh; do
    if [ -r $i ]; then
      . $i
    fi
  done
  unset i
fi
umask 027
TMOUT=180

:wq(先按下”ESC”键,再输入”:wq”就可以保存文件并退出)

输入” vi /etc/bash.bashrc“;按”↓”键将光标移动到umask参数上,将其紧跟的数字修改为”027”;

1
2
3
4
5
6
7
8
9
10
11
12
13
root@dell-PowerEdge-R730:/home/hpb# vi /etc/bash.bashrc
if [ -d /etc/profile.d ]; then
  for i in /etc/profile.d/*.sh; do
    if [ -r $i ]; then
      . $i
    fi
  done
  unset i
fi
umask 027
TMOUT=180

:wq(先按下”ESC”键,再输入”:wq”就可以保存文件并退出)

3.10 重要文件和目录的权限

用户需要仔细检查运行结果中显示的文件和目录的权限,如果权限太低,请及时修改。

3.11 未授权的SUID/SGID文件

用户需检查运行结果中显示的目录/文件是否可疑,如果可疑,请及时删除。

3.12 任何人都有写权限的目录

用户需检查运行结果中显示的目录是否有必要任何人都可写,如非必要,请及时修改权限

3.13 任何人都有写权限的文件

用户需检查运行结果中显示的文件是否有必要任何人都可写,如非必要,请及时修改权限

3.14 没有属主的文件

如果存在没有属主的文件,用户需为运行结果中显示的文件增加属主,如有可疑文件,请及时删除。

3.15 异常的隐藏文件

用户需检查运行结果中文件是否可疑,如果可疑,请及时删除

3.16 登录超时配置

配置修改步骤

编号 步骤 说明
1 切换root(已切换的用户可跳过) 命令:” su root
提示:用户需根据提示输入root账户密码 |
2 增加登录超时配置 命令:” echo \“TMOUT=180\” >> /etc/profile“ |

配置修改示例

(1) 步骤一 切换成root用户

打开终端,输入”su root“,根据提示输入root账户密码;

提示:已经切换成root用户的可以跳过该步骤。

1
2
3
hpb@dell-PowerEdge-R730:~$ su root
Password:
root@dell-PowerEdge-R730:/home/hpb#

(2) 步骤二 增加登录超时配置

输入” echo \“TMOUT=180\” >> /etc/profile“即可,该命令无返回信息;

1
2
root@dell-PowerEdge-R730:/home/hpb#  echo "TMOUT=180" >> /etc/profile
root@dell-PowerEdge-R730:/home/hpb#

3.17 ssh和telnet运行状态

如果ssh处于未运行状态,建议用户安装并开启ssh服务;

如果telnet处于运行状态,建议用户停止telnet服务。

3.18 Root远程登录限制

配置修改步骤

编号 步骤 说明
1 切换root(已切换的用户可跳过) 命令:” su root
提示:用户需根据提示输入root账户密码 |
2 不允许root远程登录 命令:” vi /etc/ssh/sshd_config
移动光标找到”PermitRootLogin”参数,将其后的”yes”改为”no”。
提示:如果该参数后为非”yes”的其他值,则无需修改。 |

配置修改示例

(1) 步骤一 切换成root用户

打开终端,输入”su root“,根据提示输入root账户密码;

提示:已经切换成root用户的可以跳过该步骤。

1
2
3
hpb@dell-PowerEdge-R730:~$ su root
Password:
root@dell-PowerEdge-R730:/home/hpb#

(2) 步骤二 不允许root远程登录

输入” vi /etc/ssh/sshd_config“,在打开的文件中移动光标到PermitRootLogin的位置,如果其紧跟的参数为”yes”,则需将”yes”改为”no”。

提示:如果其紧跟的参数为其他值,则可以不用修改配置。

1
2
3
4
5
6
7
8
root@dell-PowerEdge-R730:/home/hpb# vi /etc/ssh/sshd_config

# Authentication:
LoginGraceTime 120
PermitRootLogin prohibit-password
StrictModes yes

:wq(先按下”ESC”键,再输入”:wq”就可以保存文件并退出)

3.19 运行的服务

用户需检查运行结果中显示的服务,并尽量关闭不必要的服务。

提示:关闭服务的命令为” chkconfig –level \$level <服务名>

3.20 Core dupm状态

配置修改步骤

编号 步骤 说明
1 切换root(已切换的用户可跳过) 命令:” su root
提示:用户需根据提示输入root账户密码 |
2 修改limits文件 命令:”vi /etc/security/limits.conf
在文档末尾”End of file”前输入:
”* soft core 0
* hard core 0” |

配置修改示例

(1) 步骤一 切换成root用户

打开终端,输入”su root“,根据提示输入root账户密码;

提示:已经切换成root用户的可以跳过该步骤。

1
2
3
hpb@dell-PowerEdge-R730:~$ su root
Password:
root@dell-PowerEdge-R730:/home/hpb#

(2) 步骤二修改limits文件

输入”vi /etc/security/limits.conf“;

将光标移到文档末尾”End of file”的上一行, 输入”* soft core 0

​ * hard core 0”。

提示:如果无法键入,则按下字母”I”键即可开启”INSERT”输入状态。

1
2
3
4
5
6
7
8
9
root@dell-PowerEdge-R730:/home/hpb#

#ftp             hard    nproc           0
#ftp             -       chroot          /ftp
#@student        -       maxlogins       4
* soft core 0
* hard core 0
# End of file
:wq(先按下”ESC”键,再输入”:wq”就可以保存文件并退出)

3.21 rsyslog状态

配置修改步骤

编号 步骤 说明
1 切换root(已切换的用户可跳过) 命令:” su root
提示:用户需根据提示输入root账户密码 |
2 配置并启动rsyslog 命令:“vi /etc/rsyslog.conf“;
在文件末尾输入:
*.err;kern.debug;daemon.notice /var/adm/messages“ |
命令:“sudo mkdir /var/adm
命令:“sudo touch /var/adm/messages
命令:“sudo chmod 666 /var/adm/messages
命令:“sudo systemctl restart rsyslog” |

配置修改示例

(1) 步骤一 切换成root用户

打开终端,输入”su root“,根据提示输入root账户密码;

提示:已经切换成root用户的可以跳过该步骤。

1
2
3
hpb@dell-PowerEdge-R730:~$ su root
Password:
root@dell-PowerEdge-R730:/home/hpb#

(2) 步骤二 配置并启动rsyslog

输入”vi /etc/rsyslog.conf“ 打开rsyslog.conf文件; 按下字母”I”键即可打开输入”INSERT”状态;

用”↓”键移动光标到文件最后一行,输入:

*.err;kern.debug;daemon.notice /var/adm/messages”;

按下”ESC”键,再输入”:wq“就可以保存文件并退出;

1
2
3
4
5
6
7
8
9
root@dell-PowerEdge-R730:/home/hpb# vi /etc/rsyslog.conf 

#
# Include all config files in /etc/rsyslog.d/
#
$IncludeConfig /etc/rsyslog.d/*.conf
*.err;kern.debug;daemon.notice /var/adm/messages

:wq(先按下”ESC”键,再输入”:wq”就可以保存文件并退出)

继续输入”sudo mkdir /var/adm“,该命令无返回信息; 继续输入”sudo touch /var/adm/messages“ ,该命令无返回信息; 继续输入”sudo chmod 666 /var/adm/messages“ ,该命令无返回信息; 继续输入”sudo systemctl restart rsyslog“ ,该命令无返回信息.

1
2
3
4
root@dell-PowerEdge-R730:/home/hpb# sudo mkdir /var/adm
root@dell-PowerEdge-R730:/home/hpb# sudo touch /var/adm/messages
root@dell-PowerEdge-R730:/home/hpb# sudo chmod 666 /var/adm/messages
root@dell-PowerEdge-R730:/home/hpb# sudo systemctl restart rsyslog

3.22 Boe功能兼容性检测

未安装BOE板卡的服务器可跳过该检查项;当该检查项未通过时,用户需提供运行结果里显示的系统信息并通过”附录 技术支持”联系HPB工作人员以寻求帮助。

附录 技术支持

如果您需要更多的帮助,您需要联系HPB芯链工作人员获取更多的技术支持:

技术支持邮箱: node@hpb.io

HPB技术论坛:http://blockgeek.org/c/hpb

HPB官网地址:http://www.hpb.io/

电报:https://t.me/hpbglobal

脸书:HPB Blockchain

推特: \@HPBGlobal

Reddit: r/HPBGlobal

感谢HPB技术团队整理。