Commit 7362589a authored by kingwang's avatar kingwang Committed by 33cn

update_0513

parent 2ad7ca35
...@@ -145,7 +145,7 @@ docker-compose: ## build docker-compose for chain33 run ...@@ -145,7 +145,7 @@ docker-compose: ## build docker-compose for chain33 run
@cd build && if ! [ -d ci ]; then \ @cd build && if ! [ -d ci ]; then \
make -C ../ ; \ make -C ../ ; \
fi; \ fi; \
cp chain33* Dockerfile docker-compose* ci/ && cd ci/ && ./docker-compose-pre.sh run $(PROJ) $(DAPP) && cd ../.. cp chain33* Dockerfile docker-compose* system-test* ci/ && cd ci/ && ./docker-compose-pre.sh run $(PROJ) $(DAPP) && cd ../..
docker-compose-down: ## build docker-compose for chain33 run docker-compose-down: ## build docker-compose for chain33 run
@cd build && if [ -d ci ]; then \ @cd build && if [ -d ci ]; then \
......
...@@ -56,6 +56,11 @@ if [ -n "${DAPP}" ]; then ...@@ -56,6 +56,11 @@ if [ -n "${DAPP}" ]; then
fi fi
if [ -z "$DAPP" ]; then
# shellcheck source=/dev/null
source system-test-rpc.sh
fi
echo "=========== # env setting =============" echo "=========== # env setting ============="
echo "DAPP=$DAPP" echo "DAPP=$DAPP"
echo "DAPP_TEST_FILE=$DAPP_TEST_FILE" echo "DAPP_TEST_FILE=$DAPP_TEST_FILE"
...@@ -287,6 +292,10 @@ function transfer() { ...@@ -287,6 +292,10 @@ function transfer() {
hashes=("${hashes[@]}" "$hash") hashes=("${hashes[@]}" "$hash")
done done
#send from 14KEKbYtKKQm4wMthSK9J4La4nAiidGozt for test
hash=$(${CLI} send coins transfer -a 10000 -n test -t 12qyocayNF7Lv6C9qW4avxs2E7U41fKSfv -k CC38546E9E659D15E6B4893F0AB32A06D103931A8230B0BDE71459D2B27D6944)
echo "${hash}"
block_wait_by_height "$curHeight", 1 block_wait_by_height "$curHeight", 1
echo "len: ${#hashes[@]}" echo "len: ${#hashes[@]}"
...@@ -338,9 +347,15 @@ function base_config() { ...@@ -338,9 +347,15 @@ function base_config() {
transfer transfer
} }
function base_test() {
if [ "$DAPP" == "" ]; then
system_test_rpc "https://${1}:8801"
fi
}
function dapp_run() { function dapp_run() {
if [ -e "$DAPP_TEST_FILE" ]; then if [ -e "$DAPP_TEST_FILE" ]; then
${DAPP} "${CLI}" "${1}" ${DAPP} "${CLI}" "${1}" "${2}"
fi fi
} }
...@@ -358,7 +373,9 @@ function main() { ...@@ -358,7 +373,9 @@ function main() {
dapp_run config dapp_run config
### test cases ### ### test cases ###
dapp_run test ip=$(${CLI} net info | jq -r ".externalAddr[0:10]")
base_test "${ip}"
dapp_run test "${ip}"
### finish ### ### finish ###
check_docker_container check_docker_container
......
#!/usr/bin/env bash
# shellcheck disable=SC2128
MAIN_HTTP=""
CASE_ERR=""
#color
RED='\033[1;31m'
GRE='\033[1;32m'
NOC='\033[0m'
# $2=0 means true, other false
echo_rst() {
if [ "$2" -eq 0 ]; then
echo -e "${GRE}$1 ok${NOC}"
else
echo -e "${RED}$1 fail${NOC}"
CASE_ERR="err"
fi
}
chain33_lock() {
ok=$(curl -k -s --data-binary '{"jsonrpc":"2.0","id":2,"method":"Chain33.Lock","params":[]}' -H 'content-type:text/plain;' ${MAIN_HTTP} | jq -r ".result.isOK")
[ "$ok" == true ]
rst=$?
echo_rst "$FUNCNAME" "$rst"
}
chain33_unlock() {
ok=$(curl -k -s --data-binary '{"jsonrpc":"2.0","id":2,"method":"Chain33.UnLock","params":[{"passwd":"1314fuzamei","timeout":0}]}' -H 'content-type:text/plain;' ${MAIN_HTTP} | jq -r ".result.isOK")
[ "$ok" == true ]
rst=$?
echo_rst "$FUNCNAME" "$rst"
}
chain33_WalletTxList() {
req='"method":"Chain33.WalletTxList", "params":[{"fromTx":"", "count":2, "direction":1}]'
echo "#request: $req"
resp=$(curl -ksd "{$req}" "$1")
# echo "#response: $resp"
ok=$(jq '(.error|not) and (.result.txDetails|length == 2)' <<<"$resp")
[ "$ok" == true ]
echo_rst "$FUNCNAME" "$?"
}
chain33_ImportPrivkey() {
req='"method":"Chain33.ImportPrivkey", "params":[{"privkey":"0x88b2fb90411935872f0501dd13345aba19b5fac9b00eb0dddd7df977d4d5477e", "label":"testimportkey"}]'
echo "#request: $req"
resp=$(curl -ksd "{$req}" "$1")
# echo "#response: $resp"
ok=$(jq '(.error|not) and (.result.label=="testimportkey") and (.result.acc.addr == "1D9xKRnLvV2zMtSxSx33ow1GF4pcbLcNRt")' <<<"$resp")
[ "$ok" == true ]
echo_rst "$FUNCNAME" "$?"
}
chain33_DumpPrivkey() {
req='"method":"Chain33.DumpPrivkey", "params":[{"data":"1D9xKRnLvV2zMtSxSx33ow1GF4pcbLcNRt"}]'
echo "#request: $req"
resp=$(curl -ksd "{$req}" "$1")
# echo "#response: $resp"
ok=$(jq '(.error|not) and (.result.data=="0x88b2fb90411935872f0501dd13345aba19b5fac9b00eb0dddd7df977d4d5477e")' <<<"$resp")
[ "$ok" == true ]
echo_rst "$FUNCNAME" "$?"
}
chain33_SendToAddress() {
req='"method":"Chain33.SendToAddress", "params":[{"from":"12qyocayNF7Lv6C9qW4avxs2E7U41fKSfv","to":"1D9xKRnLvV2zMtSxSx33ow1GF4pcbLcNRt", "amount":100000000, "note":"test\n"}]'
echo "#request: $req"
resp=$(curl -ksd "{$req}" "$1")
# echo "#response: $resp"
ok=$(jq '(.error|not) and (.result.hash|length==66)' <<<"$resp")
[ "$ok" == true ]
echo_rst "$FUNCNAME" "$?"
}
chain33_SetTxFee() {
req='"method":"Chain33.SetTxFee", "params":[{"amount":100000}]'
echo "#request: $req"
resp=$(curl -ksd "{$req}" "$1")
# echo "#response: $resp"
ok=$(jq '(.error|not) and .result.isOK' <<<"$resp")
[ "$ok" == true ]
echo_rst "$FUNCNAME" "$?"
}
chain33_SetLabl() {
req='"method":"Chain33.SetLabl", "params":[{"addr":"1D9xKRnLvV2zMtSxSx33ow1GF4pcbLcNRt", "label":"updatetestimport"}]'
echo "#request: $req"
resp=$(curl -ksd "{$req}" "$1")
# echo "#response: $resp"
ok=$(jq '(.error|not) and (.result.label=="updatetestimport") and (.result.acc.addr == "1D9xKRnLvV2zMtSxSx33ow1GF4pcbLcNRt")' <<<"$resp")
[ "$ok" == true ]
echo_rst "$FUNCNAME" "$?"
}
chain33_GetPeerInfo() {
req='"method":"Chain33.GetPeerInfo", "params":[{}]'
echo "#request: $req"
resp=$(curl -ksd "{$req}" "$1")
# echo "#response: $resp"
ok=$(jq '(.error|not) and (.result.peers|length >= 1) and (.result.peers[0] |
[has("addr", "port", "name", "mempoolSize", "self", "header"), true] | unique | length == 1)' <<<"$resp")
[ "$ok" == true ]
echo_rst "$FUNCNAME" "$?"
}
chain33_GetHeaders() {
req='"method":"Chain33.GetHeaders", "params":[{"start":1, "end":2, "isDetail":true}]'
echo "#request: $req"
resp=$(curl -ksd "{$req}" "$1")
# echo "#response: $resp"
ok=$(jq '(.error|not) and (.result.items|length == 2) and (.result.items[0] |
[has("version","parentHash", "txHash", "stateHash", "height", "blockTime", "txCount", "hash", "difficulty"),true] |
unique | length == 1 )' <<<"$resp")
[ "$ok" == true ]
echo_rst "$FUNCNAME" "$?"
}
chain33_GetLastMemPool() {
req='"method":"Chain33.GetLastMemPool", "params":[{}]'
echo "#request: $req"
resp=$(curl -ksd "{$req}" "$1")
# echo "#response: $resp"
ok=$(jq '(.error|not) and (.result.txs|length >= 0)' <<<"$resp")
[ "$ok" == true ]
echo_rst "$FUNCNAME" "$?"
}
chain33_GetProperFee() {
req='"method":"Chain33.GetProperFee", "params":[{}]'
echo "#request: $req"
resp=$(curl -ksd "{$req}" "$1")
# echo "#response: $resp"
ok=$(jq '(.error|not) and (.result.properFee > 10000)' <<<"$resp")
[ "$ok" == true ]
echo_rst "$FUNCNAME" "$?"
}
chain33_GetBlockOverview() {
hash=$(curl -ksd '{"method":"Chain33.GetHeaders", "params":[{"start":1, "end":1, "isDetail":true}]}' ${MAIN_HTTP} | jq '.result.items[0].hash')
req='"method":"Chain33.GetBlockOverview", "params":[{"hash":'"$hash"'}]'
echo "#request: $req"
resp=$(curl -ksd "{$req}" "$1")
# echo "#response: $resp"
ok=$(jq '(.error|not) and
(.result| [has("head", "txCount", "txHashes"), true]|unique|length == 1) and
(.result.txCount == (.result.txHashes|length))' <<<"$resp")
[ "$ok" == true ]
echo_rst "$FUNCNAME" "$?"
}
chain33_GetAddrOverview() {
req='"method":"Chain33.GetAddrOverview", "params":[{"addr":"12qyocayNF7Lv6C9qW4avxs2E7U41fKSfv"}]'
echo "#request: $req"
resp=$(curl -ksd "{$req}" "$1")
# echo "#response: $resp"
ok=$(jq '(.error|not) and (.result|[has("reciver", "balance", "txCount"), true]|unique|length == 1)' <<<"$resp")
[ "$ok" == true ]
echo_rst "$FUNCNAME" "$?"
}
chain33_SetPasswd() {
req='"method":"Chain33.SetPasswd", "params":[{"oldPass":"1314fuzamei", "newPass":"1314fuzamei"}]'
echo "#request: $req"
resp=$(curl -ksd "{$req}" "$1")
# echo "#response: $resp"
ok=$(jq '(.error|not) and .result.isOK' <<<"$resp")
[ "$ok" == true ]
echo_rst "$FUNCNAME" "$?"
}
chain33_MergeBalance() {
req='"method":"Chain33.MergeBalance", "params":[{"to":"12qyocayNF7Lv6C9qW4avxs2E7U41fKSfv"}]'
echo "#request: $req"
resp=$(curl -ksd "{$req}" "$1")
# echo "#response: $resp"
ok=$(jq '(.error|not) and (.result.hashes|length > 0)' <<<"$resp")
[ "$ok" == true ]
echo_rst "$FUNCNAME" "$?"
}
function system_test_rpc() {
local ip=$1
MAIN_HTTP=$1
echo "=========== # system rpc test ============="
echo "ip=$MAIN_HTTP"
# set -x
set +e
chain33_lock
chain33_unlock
chain33_WalletTxList "$ip"
chain33_ImportPrivkey "$ip"
chain33_DumpPrivkey "$ip"
chain33_SendToAddress "$ip"
chain33_SetTxFee "$ip"
chain33_SetLabl "$ip"
chain33_GetPeerInfo "$ip"
chain33_GetHeaders "$ip"
chain33_GetLastMemPool "$ip"
chain33_GetProperFee "$ip"
chain33_GetBlockOverview "$ip"
chain33_GetAddrOverview "$ip"
#这两个测试放在最后
chain33_SetPasswd "$ip"
chain33_MergeBalance "$ip"
set -e
if [ -n "$CASE_ERR" ]; then
echo -e "${RED}======system rpc test fail=======${NOC}"
exit 1
else
echo -e "${GRE}======system rpc test pass=======${NOC}"
fi
}
#system_rpc_test
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
// Package version 软件版本号 // Package version 软件版本号
package version package version
const version = "6.1.1" const version = "6.1.0"
//var //var
var ( var (
......
// Copyright Fuzamei Corp. 2018 All Rights Reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package p256
import (
"bytes"
"crypto/rand"
"math"
"testing"
)
func TestH1(t *testing.T) {
for i := 0; i < 10000; i++ {
m := make([]byte, 100)
if _, err := rand.Read(m); err != nil {
t.Fatalf("Failed generating random message: %v", err)
}
x, y := H1(m)
if x == nil {
t.Errorf("H1(%v)=%v, want curve point", m, x)
}
if got := curve.Params().IsOnCurve(x, y); !got {
t.Errorf("H1(%v)=[%v, %v], is not on curve", m, x, y)
}
}
}
func TestH2(t *testing.T) {
l := 32
for i := 0; i < 10000; i++ {
m := make([]byte, 100)
if _, err := rand.Read(m); err != nil {
t.Fatalf("Failed generating random message: %v", err)
}
x := H2(m)
if got := len(x.Bytes()); got < 1 || got > l {
t.Errorf("len(h2(%v)) = %v, want: 1 <= %v <= %v", m, got, got, l)
}
}
}
func TestVRF(t *testing.T) {
k, pk := GenerateKey()
m1 := []byte("data1")
m2 := []byte("data2")
m3 := []byte("data2")
index1, proof1 := k.Evaluate(m1)
index2, proof2 := k.Evaluate(m2)
index3, proof3 := k.Evaluate(m3)
for _, tc := range []struct {
m []byte
index [32]byte
proof []byte
err error
}{
{m1, index1, proof1, nil},
{m2, index2, proof2, nil},
{m3, index3, proof3, nil},
{m3, index3, proof2, nil},
{m3, index3, proof1, ErrInvalidVRF},
} {
index, err := pk.ProofToHash(tc.m, tc.proof)
if got, want := err, tc.err; got != want {
t.Errorf("ProofToHash(%s, %x): %v, want %v", tc.m, tc.proof, got, want)
}
if err != nil {
continue
}
if got, want := index, tc.index; got != want {
t.Errorf("ProofToInex(%s, %x): %x, want %x", tc.m, tc.proof, got, want)
}
}
}
func TestRightTruncateProof(t *testing.T) {
k, pk := GenerateKey()
data := []byte("data")
_, proof := k.Evaluate(data)
proofLen := len(proof)
for i := 0; i < proofLen; i++ {
proof = proof[:len(proof)-1]
if _, err := pk.ProofToHash(data, proof); err == nil {
t.Errorf("Verify unexpectedly succeeded after truncating %v bytes from the end of proof", i)
}
}
}
func TestLeftTruncateProof(t *testing.T) {
k, pk := GenerateKey()
data := []byte("data")
_, proof := k.Evaluate(data)
proofLen := len(proof)
for i := 0; i < proofLen; i++ {
proof = proof[1:]
if _, err := pk.ProofToHash(data, proof); err == nil {
t.Errorf("Verify unexpectedly succeeded after truncating %v bytes from the beginning of proof", i)
}
}
}
func TestBitFlip(t *testing.T) {
k, pk := GenerateKey()
data := []byte("data")
_, proof := k.Evaluate(data)
for i := 0; i < len(proof)*8; i++ {
// Flip bit in position i.
if _, err := pk.ProofToHash(data, flipBit(proof, i)); err == nil {
t.Errorf("Verify unexpectedly succeeded after flipping bit %v of vrf", i)
}
}
}
func flipBit(a []byte, pos int) []byte {
index := int(math.Floor(float64(pos) / 8))
b := a[index]
b ^= (1 << uint(math.Mod(float64(pos), 8.0)))
var buf bytes.Buffer
buf.Write(a[:index])
buf.Write([]byte{b})
buf.Write(a[index+1:])
return buf.Bytes()
}
...@@ -11,6 +11,7 @@ import ( ...@@ -11,6 +11,7 @@ import (
"sync/atomic" "sync/atomic"
"github.com/33cn/chain33/client" "github.com/33cn/chain33/client"
"github.com/33cn/chain33/common"
log "github.com/33cn/chain33/common/log/log15" log "github.com/33cn/chain33/common/log/log15"
"github.com/33cn/chain33/common/merkle" "github.com/33cn/chain33/common/merkle"
"github.com/33cn/chain33/queue" "github.com/33cn/chain33/queue"
...@@ -518,3 +519,59 @@ func (bc *BaseClient) AddTxsToBlock(block *types.Block, txs []*types.Transaction ...@@ -518,3 +519,59 @@ func (bc *BaseClient) AddTxsToBlock(block *types.Block, txs []*types.Transaction
} }
return addedTx return addedTx
} }
//CheckTxExpire 此时的tx交易组都是展开的,过滤掉已经过期的tx交易,目前只有ticket共识需要在updateBlock时调用
func (bc *BaseClient) CheckTxExpire(txs []*types.Transaction, height int64, blocktime int64) (transactions []*types.Transaction) {
var txlist types.Transactions
var hasTxExpire bool
for i := 0; i < len(txs); i++ {
groupCount := txs[i].GroupCount
if groupCount == 0 {
if isExpire(txs[i:i+1], height, blocktime) {
txs[i] = nil
hasTxExpire = true
}
continue
}
//判断GroupCount 是否会产生越界
if i+int(groupCount) > len(txs) {
continue
}
//交易组有过期交易时需要将整个交易组都删除
grouptxs := txs[i : i+int(groupCount)]
if isExpire(grouptxs, height, blocktime) {
for j := i; j < i+int(groupCount); j++ {
txs[j] = nil
hasTxExpire = true
}
}
i = i + int(groupCount) - 1
}
//有过期交易时需要重新组装交易
if hasTxExpire {
for _, tx := range txs {
if tx != nil {
txlist.Txs = append(txlist.Txs, tx)
}
}
return txlist.GetTxs()
}
return txs
}
//检测交易数组是否过期,只要有一个过期就认为整个交易组过期
func isExpire(txs []*types.Transaction, height int64, blocktime int64) bool {
for _, tx := range txs {
if height > 0 && blocktime > 0 && tx.IsExpire(height, blocktime) {
log.Debug("isExpire", "height", height, "blocktime", blocktime, "hash", common.ToHex(tx.Hash()), "Expire", tx.Expire)
return true
}
}
return false
}
...@@ -115,6 +115,11 @@ func (client *Client) CreateBlock() { ...@@ -115,6 +115,11 @@ func (client *Client) CreateBlock() {
issleep = false issleep = false
//check dup //check dup
txs = client.CheckTxDup(txs) txs = client.CheckTxDup(txs)
//没有交易时不出块
if len(txs) == 0 {
issleep = true
continue
}
var newblock types.Block var newblock types.Block
newblock.ParentHash = lastBlock.Hash() newblock.ParentHash = lastBlock.Hash()
newblock.Height = lastBlock.Height + 1 newblock.Height = lastBlock.Height + 1
......
...@@ -6,23 +6,24 @@ package types ...@@ -6,23 +6,24 @@ package types
// Config 配置信息 // Config 配置信息
type Config struct { type Config struct {
Title string `protobuf:"bytes,1,opt,name=title" json:"title,omitempty"` Title string `protobuf:"bytes,1,opt,name=title" json:"title,omitempty"`
Version string `protobuf:"bytes,1,opt,name=version" json:"version,omitempty"` Version string `protobuf:"bytes,2,opt,name=version" json:"version,omitempty"`
Log *Log `protobuf:"bytes,2,opt,name=log" json:"log,omitempty"` Log *Log `protobuf:"bytes,3,opt,name=log" json:"log,omitempty"`
Store *Store `protobuf:"bytes,3,opt,name=store" json:"store,omitempty"` Store *Store `protobuf:"bytes,4,opt,name=store" json:"store,omitempty"`
Consensus *Consensus `protobuf:"bytes,5,opt,name=consensus" json:"consensus,omitempty"` Consensus *Consensus `protobuf:"bytes,5,opt,name=consensus" json:"consensus,omitempty"`
Mempool *Mempool `protobuf:"bytes,6,opt,name=mempool" json:"memPool,omitempty"` Mempool *Mempool `protobuf:"bytes,6,opt,name=mempool" json:"memPool,omitempty"`
BlockChain *BlockChain `protobuf:"bytes,7,opt,name=blockChain" json:"blockChain,omitempty"` BlockChain *BlockChain `protobuf:"bytes,7,opt,name=blockChain" json:"blockChain,omitempty"`
Wallet *Wallet `protobuf:"bytes,8,opt,name=wallet" json:"wallet,omitempty"` Wallet *Wallet `protobuf:"bytes,8,opt,name=wallet" json:"wallet,omitempty"`
P2P *P2P `protobuf:"bytes,9,opt,name=p2p" json:"p2p,omitempty"` P2P *P2P `protobuf:"bytes,9,opt,name=p2p" json:"p2p,omitempty"`
RPC *RPC `protobuf:"bytes,10,opt,name=rpc" json:"rpc,omitempty"` RPC *RPC `protobuf:"bytes,10,opt,name=rpc" json:"rpc,omitempty"`
Exec *Exec `protobuf:"bytes,11,opt,name=exec" json:"exec,omitempty"` Exec *Exec `protobuf:"bytes,11,opt,name=exec" json:"exec,omitempty"`
TestNet bool `protobuf:"varint,12,opt,name=testNet" json:"testNet,omitempty"` TestNet bool `protobuf:"varint,12,opt,name=testNet" json:"testNet,omitempty"`
FixTime bool `protobuf:"varint,13,opt,name=fixTime" json:"fixTime,omitempty"` FixTime bool `protobuf:"varint,13,opt,name=fixTime" json:"fixTime,omitempty"`
Pprof *Pprof `protobuf:"bytes,14,opt,name=pprof" json:"pprof,omitempty"` Pprof *Pprof `protobuf:"bytes,14,opt,name=pprof" json:"pprof,omitempty"`
Fork *ForkList `protobuf:"bytes,15,opt,name=fork" json:"fork,omitempty"` Fork *ForkList `protobuf:"bytes,15,opt,name=fork" json:"fork,omitempty"`
Health *HealthCheck `protobuf:"bytes,16,opt,name=health" json:"health,omitempty"` Health *HealthCheck `protobuf:"bytes,16,opt,name=health" json:"health,omitempty"`
CoinSymbol string `protobuf:"bytes,16,opt,name=coinSymbol" json:"coinSymbol,omitempty"` CoinSymbol string `protobuf:"bytes,17,opt,name=coinSymbol" json:"coinSymbol,omitempty"`
EnableParaFork bool `protobuf:"bytes,18,opt,name=enableParaFork" json:"enableParaFork,omitempty"`
} }
// ForkList fork列表配置 // ForkList fork列表配置
......
...@@ -271,8 +271,12 @@ func Init(t string, cfg *Config) { ...@@ -271,8 +271,12 @@ func Init(t string, cfg *Config) {
if cfg.Exec.MaxExecFee < cfg.Mempool.MaxTxFee { if cfg.Exec.MaxExecFee < cfg.Mempool.MaxTxFee {
panic("config must meet: mempool.maxTxFee <= exec.maxExecFee") panic("config must meet: mempool.maxTxFee <= exec.maxExecFee")
} }
setMinerExecs(cfg.Consensus.MinerExecs) if cfg.Consensus != nil {
setMinFee(cfg.Exec.MinExecFee) setMinerExecs(cfg.Consensus.MinerExecs)
}
if cfg.Exec != nil {
setMinFee(cfg.Exec.MinExecFee)
}
setChainConfig("FixTime", cfg.FixTime) setChainConfig("FixTime", cfg.FixTime)
if cfg.Exec.MaxExecFee > 0 { if cfg.Exec.MaxExecFee > 0 {
setChainConfig("MaxFee", cfg.Exec.MaxExecFee) setChainConfig("MaxFee", cfg.Exec.MaxExecFee)
...@@ -298,7 +302,9 @@ func Init(t string, cfg *Config) { ...@@ -298,7 +302,9 @@ func Init(t string, cfg *Config) {
//如果para 没有配置fork,那么默认所有的fork 为 0(一般只用于测试) //如果para 没有配置fork,那么默认所有的fork 为 0(一般只用于测试)
if isPara() && (cfg == nil || cfg.Fork == nil || cfg.Fork.System == nil) { if isPara() && (cfg == nil || cfg.Fork == nil || cfg.Fork.System == nil) {
//keep superManager same with mainnet //keep superManager same with mainnet
setForkForPara(title) if !cfg.EnableParaFork {
setForkForParaZero(title)
}
if mver[title] != nil { if mver[title] != nil {
mver[title].UpdateFork() mver[title].UpdateFork()
} }
......
...@@ -229,4 +229,7 @@ Enable=0 ...@@ -229,4 +229,7 @@ Enable=0
[fork.sub.manage] [fork.sub.manage]
Enable=0 Enable=0
ForkManageExec=100000 ForkManageExec=100000
[fork.sub.store-kvmvccmavl]
ForkKvmvccmavl=1
` `
...@@ -24,6 +24,7 @@ func TestConfigFlat(t *testing.T) { ...@@ -24,6 +24,7 @@ func TestConfigFlat(t *testing.T) {
} }
func TestConfigMverInit(t *testing.T) { func TestConfigMverInit(t *testing.T) {
RegisterDappFork("store-kvmvccmavl", "ForkKvmvccmavl", MaxHeight)
cfg, _ := InitCfg("testdata/local.mvertest.toml") cfg, _ := InitCfg("testdata/local.mvertest.toml")
Init(cfg.Title, cfg) Init(cfg.Title, cfg)
assert.Equal(t, MGStr("mver.consensus.name2", 0), "ticket-bityuan") assert.Equal(t, MGStr("mver.consensus.name2", 0), "ticket-bityuan")
...@@ -39,6 +40,7 @@ func TestConfigMverInit(t *testing.T) { ...@@ -39,6 +40,7 @@ func TestConfigMverInit(t *testing.T) {
assert.Equal(t, MGStr("mver.exec.sub.coins.name2", 9), "ticket-bityuanv5-enable") assert.Equal(t, MGStr("mver.exec.sub.coins.name2", 9), "ticket-bityuanv5-enable")
assert.Equal(t, MGStr("mver.exec.sub.coins.name2", 10), "ticket-bityuanv5") assert.Equal(t, MGStr("mver.exec.sub.coins.name2", 10), "ticket-bityuanv5")
assert.Equal(t, MGStr("mver.exec.sub.coins.name2", 11), "ticket-bityuanv5") assert.Equal(t, MGStr("mver.exec.sub.coins.name2", 11), "ticket-bityuanv5")
assert.Equal(t, int64(1), GetDappFork("store-kvmvccmavl", "ForkKvmvccmavl"))
} }
var chainBaseParam *ChainParam var chainBaseParam *ChainParam
...@@ -101,8 +103,4 @@ func TestInitChainParam(t *testing.T) { ...@@ -101,8 +103,4 @@ func TestInitChainParam(t *testing.T) {
"12qyocayNF7Lv6C9qW4avxs2E7U41fKSfv", "12qyocayNF7Lv6C9qW4avxs2E7U41fKSfv",
"1Q8hGLfoGe63efeWa8fJ4Pnukhkngt6poK", "1Q8hGLfoGe63efeWa8fJ4Pnukhkngt6poK",
}) })
cfg, _ = InitCfg("../cmd/chain33/bityuan.toml")
Init(cfg.Title, cfg)
assert.Equal(t, GetFundAddr(), "1JmFaA6unrCFYEWPGRi7uuXY1KthTJxJEP")
} }
...@@ -54,6 +54,9 @@ const ( ...@@ -54,6 +54,9 @@ const (
MinerAction = "miner" MinerAction = "miner"
Int1E4 int64 = 10000 Int1E4 int64 = 10000
Float1E4 float64 = 10000.0 Float1E4 float64 = 10000.0
AirDropMinIndex uint32 = 100000000 //通过钱包的seed生成一个空投地址,最小index索引
AirDropMaxIndex uint32 = 101000000 //通过钱包的seed生成一个空投地址,最大index索引
) )
//全局账户私钥/公钥 //全局账户私钥/公钥
......
...@@ -226,7 +226,7 @@ func setLocalFork() { ...@@ -226,7 +226,7 @@ func setLocalFork() {
} }
//paraName not used currently //paraName not used currently
func setForkForPara(paraName string) { func setForkForParaZero(paraName string) {
err := systemFork.CloneZero("chain33", paraName) err := systemFork.CloneZero("chain33", paraName)
if err != nil { if err != nil {
tlog.Error("setForkForPara", "error", err) tlog.Error("setForkForPara", "error", err)
...@@ -283,6 +283,7 @@ func initForkConfig(title string, forks *ForkList) { ...@@ -283,6 +283,7 @@ func initForkConfig(title string, forks *ForkList) {
if title == "chain33" { //chain33 fork is default set in code if title == "chain33" { //chain33 fork is default set in code
return return
} }
println(title)
chain33fork := systemFork.GetAll("chain33") chain33fork := systemFork.GetAll("chain33")
if chain33fork == nil { if chain33fork == nil {
panic("chain33 fork not init") panic("chain33 fork not init")
......
...@@ -19,3 +19,11 @@ func TestForks(t *testing.T) { ...@@ -19,3 +19,11 @@ func TestForks(t *testing.T) {
assert.Equal(t, systemFork.IsFork("local", 1, "ForkBlockHash"), true) assert.Equal(t, systemFork.IsFork("local", 1, "ForkBlockHash"), true)
assert.Equal(t, systemFork.IsFork("local", 1, "ForkTransferExec"), true) assert.Equal(t, systemFork.IsFork("local", 1, "ForkTransferExec"), true)
} }
func TestParaFork(t *testing.T) {
cfg, _ := InitCfg("testdata/guodun.toml")
Init(cfg.Title, cfg)
cfg, _ = InitCfg("testdata/guodun2.toml")
Init(cfg.Title, cfg)
}
...@@ -183,3 +183,6 @@ Enable=0 ...@@ -183,3 +183,6 @@ Enable=0
Enable=0 Enable=0
ForkManageExec=100000 ForkManageExec=100000
[fork.sub.store-kvmvccmavl]
ForkKvmvccmavl=1
Title="user.p.guodun."
TestNet=false
FixTime=false
EnableParaFork=true
[log]
# 日志级别,支持debug(dbug)/info/warn/error(eror)/crit
loglevel = "debug"
logConsoleLevel = "info"
# 日志文件名,可带目录,所有生成的日志文件都放到此目录下
logFile = "logs/chain33.log"
# 单个日志文件的最大值(单位:兆)
maxFileSize = 300
# 最多保存的历史日志文件个数
maxBackups = 100
# 最多保存的历史日志消息(单位:天)
maxAge = 28
# 日志文件名是否使用本地事件(否则使用UTC时间)
localTime = true
# 历史日志文件是否压缩(压缩格式为gz)
compress = true
# 是否打印调用源文件和行号
callerFile = false
# 是否打印调用方法
callerFunction = false
[blockchain]
defCacheSize=128
maxFetchBlockNum=128
timeoutSeconds=5
batchBlockNum=128
driver="leveldb"
dbPath="datadir"
dbCache=64
isStrongConsistency=false
singleMode=false
batchsync=false
isRecordBlockSequence=false
enableTxQuickIndex=false
[p2p]
port=13802
seeds=[]
enable=true
isSeed=false
serverStart=true
innerSeedEnable=true
useGithub=true
innerBounds=300
msgCacheSize=10240
driver="leveldb"
dbPath="datadir/addrbook"
dbCache=4
grpcLogFile="grpc33.log"
[rpc]
jrpcBindAddr="localhost:8801"
grpcBindAddr="localhost:8802"
whitelist=["127.0.0.1"]
jrpcFuncWhitelist=["*"]
grpcFuncWhitelist=["*"]
enableTLS=false
certFile="cert.pem"
keyFile="key.pem"
[mempool]
poolCacheSize=102400
minTxFee=100000
maxTxNumPerAccount=100
maxTxFee=1000000000
[consensus]
name="ticket"
minerstart=true
genesisBlockTime=1514533394
genesis="14KEKbYtKKQm4wMthSK9J4La4nAiidGozt"
[consensus.sub.ticket]
genesisBlockTime=1526486816
[[consensus.sub.ticket.genesis]]
minerAddr="184wj4nsgVxKyz2NhM3Yb5RK5Ap6AFRFq2"
returnAddr="1FB8L3DykVF7Y78bRfUrRcMZwesKue7CyR"
count=3000
[[consensus.sub.ticket.genesis]]
minerAddr="1M4ns1eGHdHak3SNc2UTQB75vnXyJQd91s"
returnAddr="1Lw6QLShKVbKM6QvMaCQwTh5Uhmy4644CG"
count=3000
[[consensus.sub.ticket.genesis]]
minerAddr="19ozyoUGPAQ9spsFiz9CJfnUCFeszpaFuF"
returnAddr="1PSYYfCbtSeT1vJTvSKmQvhz8y6VhtddWi"
count=3000
[[consensus.sub.ticket.genesis]]
minerAddr="1MoEnCDhXZ6Qv5fNDGYoW6MVEBTBK62HP2"
returnAddr="1BG9ZoKtgU5bhKLpcsrncZ6xdzFCgjrZud"
count=3000
[[consensus.sub.ticket.genesis]]
minerAddr="1FjKcxY7vpmMH6iB5kxNYLvJkdkQXddfrp"
returnAddr="1G7s64AgX1ySDcUdSW5vDa8jTYQMnZktCd"
count=3000
[[consensus.sub.ticket.genesis]]
minerAddr="12T8QfKbCRBhQdRfnAfFbUwdnH7TDTm4vx"
returnAddr="1FiDC6XWHLe7fDMhof8wJ3dty24f6aKKjK"
count=3000
[[consensus.sub.ticket.genesis]]
minerAddr="1bgg6HwQretMiVcSWvayPRvVtwjyKfz1J"
returnAddr="1AMvuuQ7V7FPQ4hkvHQdgNWy8wVL4d4hmp"
count=3000
[[consensus.sub.ticket.genesis]]
minerAddr="1EwkKd9iU1pL2ZwmRAC5RrBoqFD1aMrQ2"
returnAddr="1ExRRLoJXa8LzXdNxnJvBkVNZpVw3QWMi4"
count=3000
[[consensus.sub.ticket.genesis]]
minerAddr="1HFUhgxarjC7JLru1FLEY6aJbQvCSL58CB"
returnAddr="1KNGHukhbBnbWWnMYxu1C7YMoCj45Z3amm"
count=3000
[[consensus.sub.ticket.genesis]]
minerAddr="1C9M1RCv2e9b4GThN9ddBgyxAphqMgh5zq"
returnAddr="1AH9HRd4WBJ824h9PP1jYpvRZ4BSA4oN6Y"
count=4733
[store]
name="mavl"
driver="leveldb"
dbPath="datadir/mavltree"
dbCache=128
enableMavlPrefix=false
enableMVCC=false
[wallet]
minFee=100000
driver="leveldb"
dbPath="wallet"
dbCache=16
signType="secp256k1"
minerdisable=false
minerwhitelist=["*"]
[exec]
isFree=false
minExecFee=100000
maxExecFee=1000000000
enableStat=false
enableMVCC=false
[exec.sub.token]
saveTokenTxList=false
#系统中所有的fork,默认用chain33的测试网络的
#但是我们可以替换
[fork.system]
ForkChainParamV1= 0
ForkChainParamV2= -1
ForkStateDBSet=-1
ForkCheckTxDup=0
ForkBlockHash= 1
ForkMinerTime= 0
ForkTransferExec= 100000
ForkExecKey= 200000
ForkTxGroup= 200000
ForkResetTx0= 200000
ForkWithdraw= 200000
ForkExecRollback= 450000
ForkTxHeight= -1
ForkTxGroupPara= -1
ForkCheckBlockTime=1200000
ForkMultiSignAddress=1298600
ForkBlockCheck=1725000
ForkLocalDBAccess=1
ForkBase58AddressCheck=1800000
[fork.sub.coins]
Enable=0
[fork.sub.manage]
Enable=0
ForkManageExec=100000
Title="user.p.guodun2."
TestNet=false
FixTime=false
EnableParaFork=false
[log]
# 日志级别,支持debug(dbug)/info/warn/error(eror)/crit
loglevel = "debug"
logConsoleLevel = "info"
# 日志文件名,可带目录,所有生成的日志文件都放到此目录下
logFile = "logs/chain33.log"
# 单个日志文件的最大值(单位:兆)
maxFileSize = 300
# 最多保存的历史日志文件个数
maxBackups = 100
# 最多保存的历史日志消息(单位:天)
maxAge = 28
# 日志文件名是否使用本地事件(否则使用UTC时间)
localTime = true
# 历史日志文件是否压缩(压缩格式为gz)
compress = true
# 是否打印调用源文件和行号
callerFile = false
# 是否打印调用方法
callerFunction = false
[blockchain]
defCacheSize=128
maxFetchBlockNum=128
timeoutSeconds=5
batchBlockNum=128
driver="leveldb"
dbPath="datadir"
dbCache=64
isStrongConsistency=false
singleMode=false
batchsync=false
isRecordBlockSequence=false
enableTxQuickIndex=false
[p2p]
port=13802
seeds=[]
enable=true
isSeed=false
serverStart=true
innerSeedEnable=true
useGithub=true
innerBounds=300
msgCacheSize=10240
driver="leveldb"
dbPath="datadir/addrbook"
dbCache=4
grpcLogFile="grpc33.log"
[rpc]
jrpcBindAddr="localhost:8801"
grpcBindAddr="localhost:8802"
whitelist=["127.0.0.1"]
jrpcFuncWhitelist=["*"]
grpcFuncWhitelist=["*"]
enableTLS=false
certFile="cert.pem"
keyFile="key.pem"
[mempool]
poolCacheSize=102400
minTxFee=100000
maxTxNumPerAccount=100
maxTxFee=1000000000
[consensus]
name="ticket"
minerstart=true
genesisBlockTime=1514533394
genesis="14KEKbYtKKQm4wMthSK9J4La4nAiidGozt"
[consensus.sub.ticket]
genesisBlockTime=1526486816
[[consensus.sub.ticket.genesis]]
minerAddr="184wj4nsgVxKyz2NhM3Yb5RK5Ap6AFRFq2"
returnAddr="1FB8L3DykVF7Y78bRfUrRcMZwesKue7CyR"
count=3000
[[consensus.sub.ticket.genesis]]
minerAddr="1M4ns1eGHdHak3SNc2UTQB75vnXyJQd91s"
returnAddr="1Lw6QLShKVbKM6QvMaCQwTh5Uhmy4644CG"
count=3000
[[consensus.sub.ticket.genesis]]
minerAddr="19ozyoUGPAQ9spsFiz9CJfnUCFeszpaFuF"
returnAddr="1PSYYfCbtSeT1vJTvSKmQvhz8y6VhtddWi"
count=3000
[[consensus.sub.ticket.genesis]]
minerAddr="1MoEnCDhXZ6Qv5fNDGYoW6MVEBTBK62HP2"
returnAddr="1BG9ZoKtgU5bhKLpcsrncZ6xdzFCgjrZud"
count=3000
[[consensus.sub.ticket.genesis]]
minerAddr="1FjKcxY7vpmMH6iB5kxNYLvJkdkQXddfrp"
returnAddr="1G7s64AgX1ySDcUdSW5vDa8jTYQMnZktCd"
count=3000
[[consensus.sub.ticket.genesis]]
minerAddr="12T8QfKbCRBhQdRfnAfFbUwdnH7TDTm4vx"
returnAddr="1FiDC6XWHLe7fDMhof8wJ3dty24f6aKKjK"
count=3000
[[consensus.sub.ticket.genesis]]
minerAddr="1bgg6HwQretMiVcSWvayPRvVtwjyKfz1J"
returnAddr="1AMvuuQ7V7FPQ4hkvHQdgNWy8wVL4d4hmp"
count=3000
[[consensus.sub.ticket.genesis]]
minerAddr="1EwkKd9iU1pL2ZwmRAC5RrBoqFD1aMrQ2"
returnAddr="1ExRRLoJXa8LzXdNxnJvBkVNZpVw3QWMi4"
count=3000
[[consensus.sub.ticket.genesis]]
minerAddr="1HFUhgxarjC7JLru1FLEY6aJbQvCSL58CB"
returnAddr="1KNGHukhbBnbWWnMYxu1C7YMoCj45Z3amm"
count=3000
[[consensus.sub.ticket.genesis]]
minerAddr="1C9M1RCv2e9b4GThN9ddBgyxAphqMgh5zq"
returnAddr="1AH9HRd4WBJ824h9PP1jYpvRZ4BSA4oN6Y"
count=4733
[store]
name="mavl"
driver="leveldb"
dbPath="datadir/mavltree"
dbCache=128
enableMavlPrefix=false
enableMVCC=false
[wallet]
minFee=100000
driver="leveldb"
dbPath="wallet"
dbCache=16
signType="secp256k1"
minerdisable=false
minerwhitelist=["*"]
[exec]
isFree=false
minExecFee=100000
maxExecFee=1000000000
enableStat=false
enableMVCC=false
[exec.sub.token]
saveTokenTxList=false
...@@ -204,3 +204,5 @@ Enable=0 ...@@ -204,3 +204,5 @@ Enable=0
Enable=0 Enable=0
ForkManageExec=100000 ForkManageExec=100000
[fork.sub.store-kvmvccmavl]
ForkKvmvccmavl=1
\ No newline at end of file
...@@ -42,9 +42,10 @@ func TestCallCreateTxPara(t *testing.T) { ...@@ -42,9 +42,10 @@ func TestCallCreateTxPara(t *testing.T) {
} }
func TestExecName(t *testing.T) { func TestExecName(t *testing.T) {
assert.Equal(t, types.ExecName("coins"), "coins")
ti := types.GetTitle() ti := types.GetTitle()
defer types.SetTitleOnlyForTest(ti) defer types.SetTitleOnlyForTest(ti)
types.SetTitleOnlyForTest("local")
assert.Equal(t, types.ExecName("coins"), "coins")
types.SetTitleOnlyForTest("user.p.sto.") types.SetTitleOnlyForTest("user.p.sto.")
assert.Equal(t, types.ExecName("coins"), "user.p.sto.coins") assert.Equal(t, types.ExecName("coins"), "user.p.sto.coins")
//#在exec前面加一个 # 表示不重写执行器 //#在exec前面加一个 # 表示不重写执行器
......
...@@ -15,6 +15,7 @@ const ( ...@@ -15,6 +15,7 @@ const (
keyEncryptionCompFlag = "EncryptionFlag" // 中间有一段时间运行了一个错误的密码版本,导致有部分用户信息发生错误,需要兼容下 keyEncryptionCompFlag = "EncryptionFlag" // 中间有一段时间运行了一个错误的密码版本,导致有部分用户信息发生错误,需要兼容下
keyPasswordHash = "PasswordHash" keyPasswordHash = "PasswordHash"
keyWalletSeed = "walletseed" keyWalletSeed = "walletseed"
keyAirDropIndex = "AirDropIndex" //存储通过seed生成的空投地址信息
) )
// CalcAccountKey 用于所有Account账户的输出list,需要安装时间排序 // CalcAccountKey 用于所有Account账户的输出list,需要安装时间排序
...@@ -57,3 +58,8 @@ func CalcPasswordHash() []byte { ...@@ -57,3 +58,8 @@ func CalcPasswordHash() []byte {
func CalcWalletSeed() []byte { func CalcWalletSeed() []byte {
return []byte(keyWalletSeed) return []byte(keyWalletSeed)
} }
// CalcAirDropIndex 通过钱包Seed指定index生成的空投地址
func CalcAirDropIndex() []byte {
return []byte(keyAirDropIndex)
}
...@@ -22,6 +22,13 @@ var ( ...@@ -22,6 +22,13 @@ var (
storelog = log15.New("wallet", "store") storelog = log15.New("wallet", "store")
) )
//AddrInfo 通过seed指定index创建的账户信息,目前主要用于空投地址
type AddrInfo struct {
Index uint32 `json:"index,omitempty"`
Addr string `json:"addr,omitempty"`
Pubkey string `json:"pubkey,omitempty"`
}
// NewStore 新建存储对象 // NewStore 新建存储对象
func NewStore(db db.DB) *Store { func NewStore(db db.DB) *Store {
return &Store{db: db} return &Store{db: db}
...@@ -343,3 +350,34 @@ func (store *Store) HasSeed() (bool, error) { ...@@ -343,3 +350,34 @@ func (store *Store) HasSeed() (bool, error) {
} }
return true, nil return true, nil
} }
// GetAirDropIndex 获取指定index的空投地址
func (store *Store) GetAirDropIndex() (string, error) {
var airDrop AddrInfo
data, err := store.Get(CalcAirDropIndex())
if data == nil || err != nil {
if err != db.ErrNotFoundInDb {
storelog.Debug("GetAirDropIndex", "err", err)
}
return "", types.ErrAddrNotExist
}
err = json.Unmarshal(data, &airDrop)
if err != nil {
storelog.Error("GetWalletVersion unmarshal", "err", err)
return "", err
}
storelog.Debug("GetAirDropIndex ", "airDrop", airDrop)
return airDrop.Addr, nil
}
// SetAirDropIndex 存储指定index的空投地址信息
func (store *Store) SetAirDropIndex(airDropIndex *AddrInfo) error {
data, err := json.Marshal(airDropIndex)
if err != nil {
storelog.Error("SetAirDropIndex marshal", "err", err)
return err
}
storelog.Debug("SetAirDropIndex ", "airDropIndex", airDropIndex)
return store.GetDB().SetSync(CalcAirDropIndex(), data)
}
...@@ -142,20 +142,25 @@ func GetSeed(db dbm.DB, password string) (string, error) { ...@@ -142,20 +142,25 @@ func GetSeed(db dbm.DB, password string) (string, error) {
} }
//GetPrivkeyBySeed 通过seed生成子私钥十六进制字符串 //GetPrivkeyBySeed 通过seed生成子私钥十六进制字符串
func GetPrivkeyBySeed(db dbm.DB, seed string) (string, error) { func GetPrivkeyBySeed(db dbm.DB, seed string, specificIndex uint32) (string, error) {
var backupindex uint32 var backupindex uint32
var Hexsubprivkey string var Hexsubprivkey string
var err error var err error
var index uint32 var index uint32
//通过主私钥随机生成child私钥十六进制字符串 //通过主私钥随机生成child私钥十六进制字符串
backuppubkeyindex, err := db.Get([]byte(BACKUPKEYINDEX)) if specificIndex == 0 {
if backuppubkeyindex == nil || err != nil { backuppubkeyindex, err := db.Get([]byte(BACKUPKEYINDEX))
index = 0 if backuppubkeyindex == nil || err != nil {
} else { index = 0
if err = json.Unmarshal(backuppubkeyindex, &backupindex); err != nil { } else {
return "", err if err = json.Unmarshal(backuppubkeyindex, &backupindex); err != nil {
return "", err
}
index = backupindex + 1
} }
index = backupindex + 1 } else {
index = specificIndex
} }
if SignType != 1 && SignType != 2 { if SignType != 1 && SignType != 2 {
return "", types.ErrNotSupport return "", types.ErrNotSupport
...@@ -209,17 +214,19 @@ func GetPrivkeyBySeed(db dbm.DB, seed string) (string, error) { ...@@ -209,17 +214,19 @@ func GetPrivkeyBySeed(db dbm.DB, seed string) (string, error) {
Hexsubprivkey = secretKey Hexsubprivkey = secretKey
} }
// back up index in db // back up index in db
var pubkeyindex []byte if specificIndex == 0 {
pubkeyindex, err = json.Marshal(index) var pubkeyindex []byte
if err != nil { pubkeyindex, err = json.Marshal(index)
seedlog.Error("GetPrivkeyBySeed", "Marshal err ", err) if err != nil {
return "", types.ErrMarshal seedlog.Error("GetPrivkeyBySeed", "Marshal err ", err)
} return "", types.ErrMarshal
}
err = db.SetSync([]byte(BACKUPKEYINDEX), pubkeyindex) err = db.SetSync([]byte(BACKUPKEYINDEX), pubkeyindex)
if err != nil { if err != nil {
seedlog.Error("GetPrivkeyBySeed", "SetSync err ", err) seedlog.Error("GetPrivkeyBySeed", "SetSync err ", err)
return "", err return "", err
}
} }
return Hexsubprivkey, nil return Hexsubprivkey, nil
} }
......
...@@ -298,14 +298,14 @@ func (wallet *Wallet) getPrivKeyByAddr(addr string) (crypto.PrivKey, error) { ...@@ -298,14 +298,14 @@ func (wallet *Wallet) getPrivKeyByAddr(addr string) (crypto.PrivKey, error) {
//获取指定地址在钱包里的账户信息 //获取指定地址在钱包里的账户信息
Accountstor, err := wallet.walletStore.GetAccountByAddr(addr) Accountstor, err := wallet.walletStore.GetAccountByAddr(addr)
if err != nil { if err != nil {
walletlog.Error("ProcSendToAddress", "GetAccountByAddr err:", err) walletlog.Error("getPrivKeyByAddr", "GetAccountByAddr err:", err)
return nil, err return nil, err
} }
//通过password解密存储的私钥 //通过password解密存储的私钥
prikeybyte, err := common.FromHex(Accountstor.GetPrivkey()) prikeybyte, err := common.FromHex(Accountstor.GetPrivkey())
if err != nil || len(prikeybyte) == 0 { if err != nil || len(prikeybyte) == 0 {
walletlog.Error("ProcSendToAddress", "FromHex err", err) walletlog.Error("getPrivKeyByAddr", "FromHex err", err)
return nil, err return nil, err
} }
...@@ -313,12 +313,12 @@ func (wallet *Wallet) getPrivKeyByAddr(addr string) (crypto.PrivKey, error) { ...@@ -313,12 +313,12 @@ func (wallet *Wallet) getPrivKeyByAddr(addr string) (crypto.PrivKey, error) {
//通过privkey生成一个pubkey然后换算成对应的addr //通过privkey生成一个pubkey然后换算成对应的addr
cr, err := crypto.New(types.GetSignName("", SignType)) cr, err := crypto.New(types.GetSignName("", SignType))
if err != nil { if err != nil {
walletlog.Error("ProcSendToAddress", "err", err) walletlog.Error("getPrivKeyByAddr", "err", err)
return nil, err return nil, err
} }
priv, err := cr.PrivKeyFromBytes(privkey) priv, err := cr.PrivKeyFromBytes(privkey)
if err != nil { if err != nil {
walletlog.Error("ProcSendToAddress", "PrivKeyFromBytes err", err) walletlog.Error("getPrivKeyByAddr", "PrivKeyFromBytes err", err)
return nil, err return nil, err
} }
return priv, nil return priv, nil
......
...@@ -285,3 +285,12 @@ func (wallet *Wallet) execWallet(param *types.ChainExecutor, eventID int64) (rep ...@@ -285,3 +285,12 @@ func (wallet *Wallet) execWallet(param *types.ChainExecutor, eventID int64) (rep
//这里不判断类型是否可以调用,直接按照名字调用,如果发生panic,用recover 恢复 //这里不判断类型是否可以调用,直接按照名字调用,如果发生panic,用recover 恢复
return wcom.QueryData.Call(param.Driver, param.FuncName, paramIn) return wcom.QueryData.Call(param.Driver, param.FuncName, paramIn)
} }
// On_NewAccountByIndex 获取指定index的私钥,返回私钥的hex字符串ReqString
func (wallet *Wallet) On_NewAccountByIndex(req *types.Int32) (types.Message, error) {
reply, err := wallet.createNewAccountByIndex(uint32(req.Data))
if err != nil {
walletlog.Error("On_NewAccountByIndex", "err", err.Error())
}
return &types.ReplyString{Data: reply}, err
}
...@@ -268,7 +268,7 @@ func (wallet *Wallet) ProcCreateNewAccount(Label *types.ReqNewAccount) (*types.W ...@@ -268,7 +268,7 @@ func (wallet *Wallet) ProcCreateNewAccount(Label *types.ReqNewAccount) (*types.W
} }
for { for {
privkeyhex, err := GetPrivkeyBySeed(wallet.walletStore.GetDB(), seed) privkeyhex, err := GetPrivkeyBySeed(wallet.walletStore.GetDB(), seed, 0)
if err != nil { if err != nil {
walletlog.Error("ProcCreateNewAccount", "GetPrivkeyBySeed err", err) walletlog.Error("ProcCreateNewAccount", "GetPrivkeyBySeed err", err)
return nil, err return nil, err
...@@ -1317,3 +1317,162 @@ func isValidPassWord(password string) bool { ...@@ -1317,3 +1317,162 @@ func isValidPassWord(password string) bool {
} }
return char && digit return char && digit
} }
// CreateNewAccountByIndex 指定index创建公私钥对,主要用于空投地址。目前暂定一千万
func (wallet *Wallet) createNewAccountByIndex(index uint32) (string, error) {
wallet.mtx.Lock()
defer wallet.mtx.Unlock()
ok, err := wallet.CheckWalletStatus()
if !ok {
return "", err
}
if !isValidIndex(index) {
walletlog.Error("createNewAccountByIndex index err", "index", index)
return "", types.ErrInvalidParam
}
//空投地址是否已经存在,存在就直接返回存储的值即可
airDropAddr, err := wallet.walletStore.GetAirDropIndex()
if airDropAddr != "" && err == nil {
priv, err := wallet.getPrivKeyByAddr(airDropAddr)
if err != nil {
return "", err
}
return common.ToHex(priv.Bytes()), nil
}
var cointype uint32
var addr string
var privkeybyte []byte
var HexPubkey string
var isUsed bool
if SignType == 1 {
cointype = bipwallet.TypeBty
} else if SignType == 2 {
cointype = bipwallet.TypeYcc
} else {
cointype = bipwallet.TypeBty
}
//通过seed获取私钥, 首先通过钱包密码解锁seed然后通过seed生成私钥
seed, err := wallet.getSeed(wallet.Password)
if err != nil {
walletlog.Error("createNewAccountByIndex", "getSeed err", err)
return "", err
}
// 通过指定index生成公私钥对,并存入数据库中,如果账户已经存在就直接返回账户信息即可
privkeyhex, err := GetPrivkeyBySeed(wallet.walletStore.GetDB(), seed, index)
if err != nil {
walletlog.Error("createNewAccountByIndex", "GetPrivkeyBySeed err", err)
return "", err
}
privkeybyte, err = common.FromHex(privkeyhex)
if err != nil || len(privkeybyte) == 0 {
walletlog.Error("createNewAccountByIndex", "FromHex err", err)
return "", err
}
pub, err := bipwallet.PrivkeyToPub(cointype, privkeybyte)
if err != nil {
seedlog.Error("createNewAccountByIndex PrivkeyToPub", "err", err)
return "", types.ErrPrivkeyToPub
}
HexPubkey = hex.EncodeToString(pub)
addr, err = bipwallet.PubToAddress(cointype, pub)
if err != nil {
seedlog.Error("createNewAccountByIndex PubToAddress", "err", err)
return "", types.ErrPrivkeyToPub
}
//通过新生成的账户地址查询钱包数据库,如果查询返回的账户信息不为空,
//说明此账户已经被使用,不需要再次存储账户信息
account, err := wallet.walletStore.GetAccountByAddr(addr)
if account != nil && err == nil {
isUsed = true
}
//第一次创建此账户
if !isUsed {
Account := types.Account{
Addr: addr,
Currency: 0,
Balance: 0,
Frozen: 0,
}
//首先校验label是否已被使用
Label := "airdropaddr"
for {
i := 0
WalletAccStores, err := wallet.walletStore.GetAccountByLabel(Label)
if WalletAccStores != nil && err == nil {
walletlog.Debug("createNewAccountByIndex Label is exist in wallet!", "WalletAccStores", WalletAccStores)
i++
Label = Label + fmt.Sprintf("%d", i)
} else {
break
}
}
walletAccount := types.WalletAccount{
Acc: &Account,
Label: Label,
}
//使用钱包的password对私钥加密 aes cbc
Encrypted := wcom.CBCEncrypterPrivkey([]byte(wallet.Password), privkeybyte)
var WalletAccStore types.WalletAccountStore
WalletAccStore.Privkey = common.ToHex(Encrypted)
WalletAccStore.Label = Label
WalletAccStore.Addr = addr
//存储账户信息到wallet数据库中
err = wallet.walletStore.SetWalletAccount(false, Account.Addr, &WalletAccStore)
if err != nil {
return "", err
}
//获取地址对应的账户信息从account模块
addrs := make([]string, 1)
addrs[0] = addr
accounts, err := accountdb.LoadAccounts(wallet.api, addrs)
if err != nil {
walletlog.Error("createNewAccountByIndex", "LoadAccounts err", err)
return "", err
}
// 本账户是首次创建
if len(accounts[0].Addr) == 0 {
accounts[0].Addr = addr
}
walletAccount.Acc = accounts[0]
//从blockchain模块同步Account.Addr对应的所有交易详细信息
for _, policy := range wcom.PolicyContainer {
policy.OnCreateNewAccount(walletAccount.Acc)
}
}
//存贮空投地址的信息
airfrop := &wcom.AddrInfo{
Index: index,
Addr: addr,
Pubkey: HexPubkey,
}
err = wallet.walletStore.SetAirDropIndex(airfrop)
if err != nil {
walletlog.Error("createNewAccountByIndex", "SetAirDropIndex err", err)
}
return privkeyhex, nil
}
//isValidIndex校验index的合法性
func isValidIndex(index uint32) bool {
if types.AirDropMinIndex <= index && index <= types.AirDropMaxIndex {
return true
}
return false
}
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
package wallet package wallet
import ( import (
"encoding/hex"
"fmt" "fmt"
"testing" "testing"
"time" "time"
...@@ -17,6 +18,7 @@ import ( ...@@ -17,6 +18,7 @@ import (
_ "github.com/33cn/chain33/system" _ "github.com/33cn/chain33/system"
"github.com/33cn/chain33/types" "github.com/33cn/chain33/types"
"github.com/33cn/chain33/util" "github.com/33cn/chain33/util"
"github.com/33cn/chain33/wallet/bipwallet"
wcom "github.com/33cn/chain33/wallet/common" wcom "github.com/33cn/chain33/wallet/common"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
...@@ -188,6 +190,8 @@ func TestWallet(t *testing.T) { ...@@ -188,6 +190,8 @@ func TestWallet(t *testing.T) {
testWallet(t, wallet) testWallet(t, wallet)
testSendTx(t, wallet) testSendTx(t, wallet)
testCreateNewAccountByIndex(t, wallet)
} }
//ProcWalletLock //ProcWalletLock
...@@ -807,7 +811,7 @@ func testSendTx(t *testing.T, wallet *Wallet) { ...@@ -807,7 +811,7 @@ func testSendTx(t *testing.T, wallet *Wallet) {
wallet.WaitTxs([][]byte{hash}) wallet.WaitTxs([][]byte{hash})
hash, err = wallet.SendTransaction(&types.ReceiptAccountTransfer{}, []byte("test"), priv, ToAddr1) hash, err = wallet.SendTransaction(&types.ReceiptAccountTransfer{}, []byte("test"), priv, ToAddr1)
assert.NoError(t, err) assert.NoError(t, err)
t.Log(string(hash)) t.Log(common.ToHex(hash))
err = wallet.sendTransactionWait(&types.ReceiptAccountTransfer{}, []byte("test"), priv, ToAddr1) err = wallet.sendTransactionWait(&types.ReceiptAccountTransfer{}, []byte("test"), priv, ToAddr1)
assert.NoError(t, err) assert.NoError(t, err)
...@@ -816,3 +820,92 @@ func testSendTx(t *testing.T, wallet *Wallet) { ...@@ -816,3 +820,92 @@ func testSendTx(t *testing.T, wallet *Wallet) {
assert.Equal(t, types.ErrActionNotSupport, err) assert.Equal(t, types.ErrActionNotSupport, err)
} }
func testCreateNewAccountByIndex(t *testing.T, wallet *Wallet) {
println("testCreateNewAccountByIndex begin")
//首先创建一个airdropaddr标签的账户
reqNewAccount := &types.ReqNewAccount{Label: "airdropaddr"}
msg1 := wallet.client.NewMessage("wallet", types.EventNewAccount, reqNewAccount)
wallet.client.Send(msg1, true)
respp, err := wallet.client.Wait(msg1)
require.NoError(t, err)
walletAcc := respp.GetData().(*types.WalletAccount)
addrtmp := walletAcc.GetAcc().Addr
if walletAcc.GetLabel() != "airdropaddr" {
t.Error("testCreateNewAccountByIndex", "walletAcc.GetLabel()", walletAcc.GetLabel(), "Label", "airdropaddr")
}
//index参数的校验。目前只支持10000000
reqIndex := &types.Int32{Data: 0}
_, err = wallet.GetAPI().ExecWalletFunc("wallet", "NewAccountByIndex", reqIndex)
assert.Equal(t, types.ErrInvalidParam, err)
//创建一个空投地址
reqIndex = &types.Int32{Data: 100000000}
resp1, err := wallet.GetAPI().ExecWalletFunc("wallet", "NewAccountByIndex", reqIndex)
require.NoError(t, err)
pubkey := resp1.(*types.ReplyString)
//通过pubkey换算成addr然后获取账户信息
privkeybyte, err := common.FromHex(pubkey.Data)
require.NoError(t, err)
pub, err := bipwallet.PrivkeyToPub(bipwallet.TypeBty, privkeybyte)
require.NoError(t, err)
addr, err := bipwallet.PubToAddress(bipwallet.TypeBty, pub)
require.NoError(t, err)
if addr != "" {
//测试ProcGetAccountList函数
msgGetAccList := wallet.client.NewMessage("wallet", types.EventWalletGetAccountList, &types.ReqAccountList{})
wallet.client.Send(msgGetAccList, true)
resp, err := wallet.client.Wait(msgGetAccList)
assert.Nil(t, err)
accountlist := resp.GetData().(*types.WalletAccounts)
for _, acc := range accountlist.Wallets {
if addr == acc.Acc.Addr && addr != addrtmp {
if acc.GetLabel() != ("airdropaddr" + fmt.Sprintf("%d", 1)) {
t.Error("testCreateNewAccountByIndex", "addr", addr, "acc.GetLabel()", acc.GetLabel())
}
}
}
}
//已经存在,和上一次获取的地址是一致的
reqIndex = &types.Int32{Data: 100000000}
resp, err := wallet.GetAPI().ExecWalletFunc("wallet", "NewAccountByIndex", reqIndex)
require.NoError(t, err)
pubkey = resp.(*types.ReplyString)
//通过pubkey换算成addr然后获取账户信息
privkeybyte, err = common.FromHex(pubkey.Data)
require.NoError(t, err)
pub2, err := bipwallet.PrivkeyToPub(bipwallet.TypeBty, privkeybyte)
require.NoError(t, err)
addr2, err := bipwallet.PubToAddress(bipwallet.TypeBty, pub2)
require.NoError(t, err)
if addr != addr2 {
t.Error("TestProcCreateNewAccount", "addr", addr, "addr2", addr2)
}
privstr := "0x78a8c993abf85d2a452233033c19fac6b3bd4fe2c805615b337ef75dacd86ac9"
pubstr := "0277786ddef164b594f7db40d9a563f1ef1733cf34f1592f4c3bf1b344bd8f059b"
addrstr := "19QtNuUS9UN4hQPLrnYr3UhJsQYy4z4TMT"
privkeybyte, err = common.FromHex(privstr)
require.NoError(t, err)
pub3, err := bipwallet.PrivkeyToPub(bipwallet.TypeBty, privkeybyte)
require.NoError(t, err)
pubtmp := hex.EncodeToString(pub3)
if pubtmp != pubstr {
t.Error("TestProcCreateNewAccount", "pubtmp", pubtmp, "pubstr", pubstr)
}
addr3, err := bipwallet.PubToAddress(bipwallet.TypeBty, pub3)
require.NoError(t, err)
if addr3 != addrstr {
t.Error("TestProcCreateNewAccount", "addr3", addr3, "addrstr", addrstr)
}
println("TestProcCreateNewAccount end")
println("--------------------------")
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment