Commit ac7c7399 authored by liuyuhang's avatar liuyuhang

Merge branch 'master' into modify_pl_linter_warning

# Conflicts: # plugin/store/mpt/mpt_test.go
parents 92e84e9b f125f764
......@@ -21,10 +21,8 @@ build/main.sh
build/main*
build/para.sh
build/ci
build/tools/autotest/autotest
build/tools/autotest/*.toml
build/tools/autotest/chain33
build/tools/autotest/chain33-cli
build/autotest/*
!build/autotest/build.sh
.DS_Store
logs/
build/wallet
......
......@@ -26,7 +26,15 @@ jobs:
script:
- make test
- stage: auto-test
go: "1.9.x"
install: skip
before_script: make build_ci
script:
- make autotest dapp=all
- stage: coverage
if: branch = master
go: "1.9.x"
before_install:
- go get -t -v ./...
......@@ -35,10 +43,10 @@ jobs:
- make coverage
after_success:
- bash <(curl -s https://codecov.io/bash)
branches:
only: master
- stage: deploy
if: env(DAPP) IS present
sudo: required
services:
- docker
......@@ -55,5 +63,4 @@ jobs:
- sudo mv docker-compose /usr/local/bin
before_script: make build_ci
script:
# - make docker-compose && make docker-compose-down && make docker-compose DAPP=paracross && make docker-compose-down DAPP=paracross && make docker-compose DAPP=relay && make docker-compose-down DAPP=relay
- make docker-compose DAPP=all && make docker-compose-down DAPP=all && make clean
- make docker-compose DAPP=${DAPP} && make docker-compose-down DAPP=${DAPP} && make clean
// ci server: http://39.98.41.13:8080
// user/pass: jenkins/33fuzamei123
pipeline {
agent any
......@@ -14,7 +12,7 @@ pipeline {
retry(1)
timestamps()
gitLabConnection('gitlab33')
gitlabBuilds(builds: ['check', 'build', 'test', 'deploy'])
gitlabBuilds(builds: ['check'])
checkoutToSubdirectory "src/github.com/33cn/plugin"
}
......@@ -23,41 +21,8 @@ pipeline {
steps {
dir("${PROJ_DIR}"){
gitlabCommitStatus(name: 'check'){
sh "git branch;git status"
sh "make auto_ci branch=${env.gitlabSourceBranch}"
}
}
}
}
stage('build') {
steps {
dir("${env.PROJ_DIR}"){
gitlabCommitStatus(name: 'build'){
sh 'make checkgofmt'
sh 'make linter'
}
}
}
}
stage('test'){
agent {
docker{
image 'suyanlong/chain33-run:latest'
}
}
environment {
GOPATH = "${WORKSPACE}"
PROJ_DIR = "${WORKSPACE}/src/github.com/33cn/plugin"
}
steps {
dir("${env.PROJ_DIR}"){
gitlabCommitStatus(name: 'test'){
sh 'make test'
//sh 'export CC=clang-5.0 && make msan'
sh "git branch"
sh "make auto_ci branch=${env.ghprbSourceBranch} originx=${env.ghprbAuthorRepoGitUrl}"
}
}
}
......@@ -92,16 +57,16 @@ pipeline {
success {
echo 'I succeeeded!'
echo "email user: ${gitlabUserEmail}"
mail to: "${gitlabUserEmail}",
echo "email user: ${ghprbActualCommitAuthorEmail}"
mail to: "${ghprbActualCommitAuthorEmail}",
subject: "Successed Pipeline: ${currentBuild.fullDisplayName}",
body: "this is success with ${env.BUILD_URL}"
}
failure {
echo 'I failed '
echo "email user: ${gitlabUserEmail}"
mail to: "${gitlabUserEmail}",
echo "email user: ${ghprbActualCommitAuthorEmail}"
mail to: "${ghprbActualCommitAuthorEmail}",
subject: "Failed Pipeline: ${currentBuild.fullDisplayName}",
body: "Something is wrong with ${env.BUILD_URL}"
}
......
pipeline {
agent any
environment {
GOPATH = "${WORKSPACE}"
PROJ_DIR = "${WORKSPACE}/src/github.com/33cn/plugin"
}
options {
timeout(time: 2,unit: 'HOURS')
retry(1)
timestamps()
gitLabConnection('gitlab33')
gitlabBuilds(builds: ['check', 'build', 'test', 'deploy'])
checkoutToSubdirectory "src/github.com/33cn/plugin"
}
stages {
stage('check') {
steps {
dir("${PROJ_DIR}"){
gitlabCommitStatus(name: 'check'){
sh "git branch;git status"
sh "make auto_ci branch=${env.gitlabSourceBranch}"
}
}
}
}
stage('build') {
steps {
dir("${env.PROJ_DIR}"){
gitlabCommitStatus(name: 'build'){
sh 'make checkgofmt'
sh 'make linter'
}
}
}
}
stage('test'){
agent {
docker{
image 'suyanlong/chain33-run:latest'
}
}
environment {
GOPATH = "${WORKSPACE}"
PROJ_DIR = "${WORKSPACE}/src/github.com/33cn/plugin"
}
steps {
dir("${env.PROJ_DIR}"){
gitlabCommitStatus(name: 'test'){
sh 'make test'
//sh 'export CC=clang-5.0 && make msan'
}
}
}
}
stage('deploy') {
steps {
dir("${PROJ_DIR}"){
gitlabCommitStatus(name: 'deploy'){
sh 'make build_ci'
sh "cd build && mkdir ${env.BUILD_NUMBER} && cp ci/* ${env.BUILD_NUMBER} -r && cp chain33* Dockerfile* docker* *.sh ${env.BUILD_NUMBER}/ && cd ${env.BUILD_NUMBER}/ && ./docker-compose-pre.sh run ${env.BUILD_NUMBER} all "
}
}
}
post {
always {
dir("${PROJ_DIR}"){
sh "cd build/${env.BUILD_NUMBER} && ./docker-compose-pre.sh down ${env.BUILD_NUMBER} all && cd .. && rm -rf ${env.BUILD_NUMBER} && cd .. && make clean "
}
}
}
}
}
post {
always {
echo 'One way or another, I have finished'
// clean up our workspace
deleteDir()
}
success {
echo 'I succeeeded!'
echo "email user: ${gitlabUserEmail}"
mail to: "${gitlabUserEmail}",
subject: "Successed Pipeline: ${currentBuild.fullDisplayName}",
body: "this is success with ${env.BUILD_URL}"
}
failure {
echo 'I failed '
echo "email user: ${gitlabUserEmail}"
mail to: "${gitlabUserEmail}",
subject: "Failed Pipeline: ${currentBuild.fullDisplayName}",
body: "Something is wrong with ${env.BUILD_URL}"
}
}
}
......@@ -10,9 +10,8 @@ SRC_CLI := github.com/33cn/plugin/cli
APP := build/chain33
CHAIN33=github.com/33cn/chain33
CHAIN33_PATH=vendor/${CHAIN33}
AUTO_TEST := build/tools/autotest/autotest
SRC_AUTO_TEST := ${CHAIN33}/cmd/autotest
LDFLAGS := -ldflags "-w -s"
PKG_LIST_VET := `go list ./... | grep -v "vendor"`
PKG_LIST := `go list ./... | grep -v "vendor" | grep -v "chain33/test" | grep -v "mocks" | grep -v "pbft"`
PKG_LIST_Q := `go list ./... | grep -v "vendor" | grep -v "chain33/test" | grep -v "mocks" | grep -v "blockchain" | grep -v "pbft"`
BUILD_FLAGS = -ldflags "-X github.com/33cn/chain33/common/version.GitCommit=`git rev-parse --short=8 HEAD`"
......@@ -37,13 +36,25 @@ build_ci: depends ## Build the binary file for CI
para:
@go build -v -o build/$(NAME) -ldflags "-X $(SRC_CLI)/buildflags.ParaName=user.p.$(NAME). -X $(SRC_CLI)/buildflags.RPCAddr=http://localhost:8901" $(SRC_CLI)
vet:
@go vet ${PKG_LIST_VET}
autotest:## build autotest binary
@go build -v -i -o $(AUTO_TEST) $(SRC_AUTO_TEST)
@cp cmd/autotest/*.toml build/tools/autotest/
autotest: ## build autotest binary
@cd build/autotest && bash ./build.sh && cd ../../
@if [ -n "$(dapp)" ]; then \
cd build/tools/autotest && bash ./local-autotest.sh $(dapp) && cd ../../../; \
fi
rm -rf build/autotest/local \
&& cp -r $(CHAIN33_PATH)/build/autotest/local $(CHAIN33_PATH)/build/autotest/*.sh build/autotest/ \
&& cd build/autotest && bash ./copy-autotest.sh local && cd local && bash ./local-autotest.sh $(dapp) && cd ../../../; fi
autotest_ci: autotest ## autotest ci
@rm -rf build/autotest/jerkinsci \
&& cp -r $(CHAIN33_PATH)/build/autotest/jerkinsci $(CHAIN33_PATH)/build/autotest/*.sh build/autotest/ \
&& cd build/autotest && bash ./copy-autotest.sh jerkinsci/temp$(proj) \
&& cd jerkinsci && bash ./jerkins-ci-autotest.sh $(proj) && cd ../../../
autotest_tick: autotest ## run with ticket mining
@rm -rf build/autotest/gitlabci \
&& cp -r $(CHAIN33_PATH)/build/autotest/gitlabci $(CHAIN33_PATH)/build/autotest/*.sh build/autotest/ \
&& cd build/autotest && bash ./copy-autotest.sh gitlabci \
&& cd gitlabci && bash ./gitlab-ci-autotest.sh build && cd ../../../
update:
rm -rf ${CHAIN33_PATH}
......@@ -142,7 +153,7 @@ clean: ## Remove previous build
@rm -rf build/relayd*
@rm -rf build/*.log
@rm -rf build/logs
@rm -rf build/tools/autotest/autotest
@rm -rf build/autotest/autotest
@rm -rf build/ci
@rm -rf tool
@go clean
......@@ -224,7 +235,10 @@ auto_ci: clean fmt_proto fmt_shell protobuf
git add -u; \
git status; \
git commit -a -m "auto ci"; \
git push origin HEAD:$(branch); \
git remote add originx $(originx); \
git remote -v; \
git push --quiet --set-upstream originx HEAD:$(branch); \
git log -n 2; \
exit 1; \
fi;
......@@ -250,3 +264,22 @@ push:
git checkout ${b}
git merge master
git push origin ${b}
pull:
@remotelist=$$(git remote | grep ${name});if [ -z $$remotelist ]; then \
echo ${remotelist}; \
git remote add ${name} https://github.com/${name}/plugin.git ; \
fi;
git fetch ${name}
git checkout ${name}/${b}
git checkout -b ${name}-${b}
pullsync:
git fetch ${name}
git checkout ${name}-${b}
git merge ${name}/${b}
pullpush:
@if [ -n "$$m" ]; then \
git commit -a -m "${m}" ; \
fi;
make pullsync
git push ${name} ${name}-${b}:${b}
......@@ -70,3 +70,10 @@ make push b=branch_dev_name m="hello world"
```
如果m不设置,那么不会执行 git commit 的命令
#### 测试代码
类似plugin/dapp/relay,在cmd目录下编写自己插件的Makefile和build.sh
在build目录下写testcase和相关的Dockerfile和docker-compose配置文件,
testcase的规则参考plugin/dapp/testcase_compose_rule.md
用户可以在travis自己工程里面设置自己plugin的DAPP变量,如DAPP设置为relay,则travis里面run relay的testcase
#!/usr/bin/env bash
set -e
set -o pipefail
#set -o verbose
#set -o xtrace
sedfix=""
if [ "$(uname)" == "Darwin" ]; then
sedfix=".bak"
fi
AutoTestMain="../../vendor/github.com/33cn/chain33/cmd/autotest/main.go"
ImportPlugin='"github.com/33cn/plugin/plugin"'
function build_auto_test() {
cp "${AutoTestMain}" ./
sed -i $sedfix "/^package/a import _ ${ImportPlugin}" main.go
go build -v -i -o autotest
}
function clean_auto_test() {
rm -f ../autotest/main.go
}
trap "clean_auto_test" INT TERM EXIT
build_auto_test
This diff is collapsed.
......@@ -112,7 +112,7 @@ func TestFilterTxsForPara(t *testing.T) {
Receipts: receipts,
}
para := &ParaClient{}
para := &client{}
rst := para.FilterTxsForPara(detail)
filterTxs := []*types.Transaction{tx3, tx4, tx5, tx6, txA, txB, txC}
assert.Equal(t, filterTxs, rst)
......
......@@ -21,8 +21,8 @@ var (
consensusInterval = 16 //about 1 new block interval
)
type CommitMsgClient struct {
paraClient *ParaClient
type commitMsgClient struct {
paraClient *client
waitMainBlocks int32
commitMsgNotify chan int64
delMsgNotify chan int64
......@@ -33,7 +33,7 @@ type CommitMsgClient struct {
quit chan struct{}
}
func (client *CommitMsgClient) handler() {
func (client *commitMsgClient) handler() {
var isSync bool
var notification []int64 //记录每次系统重启后 min and current height
var finishHeight int64
......@@ -185,7 +185,7 @@ out:
client.paraClient.wg.Done()
}
func (client *CommitMsgClient) calcCommitMsgTxs(notifications []*pt.ParacrossNodeStatus) (*types.Transaction, int64, error) {
func (client *commitMsgClient) calcCommitMsgTxs(notifications []*pt.ParacrossNodeStatus) (*types.Transaction, int64, error) {
txs, count, err := client.batchCalcTxGroup(notifications)
if err != nil {
txs, err = client.singleCalcTx((notifications)[0])
......@@ -199,7 +199,7 @@ func (client *CommitMsgClient) calcCommitMsgTxs(notifications []*pt.ParacrossNod
return txs, int64(count), nil
}
func (client *CommitMsgClient) getTxsGroup(txsArr *types.Transactions) (*types.Transaction, error) {
func (client *commitMsgClient) getTxsGroup(txsArr *types.Transactions) (*types.Transaction, error) {
if len(txsArr.Txs) < 2 {
tx := txsArr.Txs[0]
tx.Sign(types.SECP256K1, client.privateKey)
......@@ -224,7 +224,7 @@ func (client *CommitMsgClient) getTxsGroup(txsArr *types.Transactions) (*types.T
return newtx, nil
}
func (client *CommitMsgClient) batchCalcTxGroup(notifications []*pt.ParacrossNodeStatus) (*types.Transaction, int, error) {
func (client *commitMsgClient) batchCalcTxGroup(notifications []*pt.ParacrossNodeStatus) (*types.Transaction, int, error) {
var rawTxs types.Transactions
for _, status := range notifications {
tx, err := paracross.CreateRawCommitTx4MainChain(status, pt.ParaX, 0)
......@@ -242,7 +242,7 @@ func (client *CommitMsgClient) batchCalcTxGroup(notifications []*pt.ParacrossNod
return txs, len(notifications), nil
}
func (client *CommitMsgClient) singleCalcTx(status *pt.ParacrossNodeStatus) (*types.Transaction, error) {
func (client *commitMsgClient) singleCalcTx(status *pt.ParacrossNodeStatus) (*types.Transaction, error) {
tx, err := paracross.CreateRawCommitTx4MainChain(status, pt.ParaX, 0)
if err != nil {
plog.Error("para get commit tx", "block height", status.Height)
......@@ -258,7 +258,7 @@ func (client *CommitMsgClient) singleCalcTx(status *pt.ParacrossNodeStatus) (*ty
// if sendCommitMsgTx block quite long, write channel will be block in handle(), addBlock will not send new msg until rpc send over
// if sendCommitMsgTx block quite long, if delMsg occur, after send over, ignore previous tx succ or fail, new msg will be rcv and sent
// if sendCommitMsgTx fail, wait 1s resend the failed tx, if new tx rcv from ch, send the new one.
func (client *CommitMsgClient) sendCommitMsg(ch chan *types.Transaction) {
func (client *commitMsgClient) sendCommitMsg(ch chan *types.Transaction) {
var err error
var tx *types.Transaction
resendTimer := time.After(time.Second * 1)
......@@ -286,7 +286,7 @@ out:
client.paraClient.wg.Done()
}
func (client *CommitMsgClient) sendCommitMsgTx(tx *types.Transaction) error {
func (client *commitMsgClient) sendCommitMsgTx(tx *types.Transaction) error {
if tx == nil {
return nil
}
......@@ -319,7 +319,7 @@ func checkTxInMainBlock(targetTx *types.Transaction, detail *types.BlockDetail)
//当前未考虑获取key非常多失败的场景, 如果获取height非常多,block模块会比较大,但是使用完了就释放了
//如果有必要也可以考虑每次最多取20个一个txgroup,发送共识部分循环获取发送也没问题
func (client *CommitMsgClient) getNodeStatus(start, end int64) ([]*pt.ParacrossNodeStatus, error) {
func (client *commitMsgClient) getNodeStatus(start, end int64) ([]*pt.ParacrossNodeStatus, error) {
var ret []*pt.ParacrossNodeStatus
if start == 0 {
geneStatus, err := client.getGenesisNodeStatus()
......@@ -402,7 +402,7 @@ func (client *CommitMsgClient) getNodeStatus(start, end int64) ([]*pt.ParacrossN
}
func (client *CommitMsgClient) getGenesisNodeStatus() (*pt.ParacrossNodeStatus, error) {
func (client *commitMsgClient) getGenesisNodeStatus() (*pt.ParacrossNodeStatus, error) {
var status pt.ParacrossNodeStatus
req := &types.ReqBlocks{Start: 0, End: 0}
msg := client.paraClient.GetQueueClient().NewMessage("blockchain", types.EventGetBlocks, req)
......@@ -425,7 +425,7 @@ func (client *CommitMsgClient) getGenesisNodeStatus() (*pt.ParacrossNodeStatus,
return &status, nil
}
func (client *CommitMsgClient) onBlockAdded(height int64) error {
func (client *commitMsgClient) onBlockAdded(height int64) error {
select {
case client.commitMsgNotify <- height:
case <-client.quit:
......@@ -434,14 +434,14 @@ func (client *CommitMsgClient) onBlockAdded(height int64) error {
return nil
}
func (client *CommitMsgClient) onBlockDeleted(height int64) {
func (client *commitMsgClient) onBlockDeleted(height int64) {
select {
case client.delMsgNotify <- height:
case <-client.quit:
}
}
func (client *CommitMsgClient) onMainBlockAdded(block *types.BlockDetail) {
func (client *commitMsgClient) onMainBlockAdded(block *types.BlockDetail) {
select {
case client.mainBlockAdd <- block:
case <-client.quit:
......@@ -449,7 +449,7 @@ func (client *CommitMsgClient) onMainBlockAdded(block *types.BlockDetail) {
}
//only sync once, as main usually sync, here just need the first sync status after start up
func (client *CommitMsgClient) mainSync() error {
func (client *commitMsgClient) mainSync() error {
req := &types.ReqNil{}
reply, err := client.paraClient.grpcClient.IsSync(context.Background(), req)
if err != nil {
......@@ -466,7 +466,7 @@ func (client *CommitMsgClient) mainSync() error {
}
func (client *CommitMsgClient) getConsensusHeight(consensusRst chan *pt.ParacrossStatus) {
func (client *commitMsgClient) getConsensusHeight(consensusRst chan *pt.ParacrossStatus) {
ticker := time.NewTicker(time.Second * time.Duration(consensusInterval))
isSync := false
defer ticker.Stop()
......@@ -486,7 +486,7 @@ out:
}
ret, err := client.paraClient.paraClient.GetTitle(context.Background(),
&types.ReqString{types.GetTitle()})
&types.ReqString{Data: types.GetTitle()})
if err != nil {
plog.Error("getConsensusHeight ", "err", err.Error())
continue
......@@ -499,7 +499,7 @@ out:
client.paraClient.wg.Done()
}
func (client *CommitMsgClient) fetchPrivacyKey(ch chan crypto.PrivKey) {
func (client *commitMsgClient) fetchPrivacyKey(ch chan crypto.PrivKey) {
defer client.paraClient.wg.Done()
if client.paraClient.authAccount == "" {
close(ch)
......@@ -544,7 +544,7 @@ out:
}
func CheckMinerTx(current *types.BlockDetail) error {
func checkMinerTx(current *types.BlockDetail) error {
//检查第一个笔交易的execs, 以及执行状态
if len(current.Block.Txs) == 0 {
return types.ErrEmptyTx
......
......@@ -42,7 +42,7 @@ func init() {
type suiteParaCommitMsg struct {
// Include our basic suite logic.
suite.Suite
para *ParaClient
para *client
grpcCli *typesmocks.Chain33Client
q queue.Queue
block *blockchain.BlockChain
......@@ -70,7 +70,7 @@ func (s *suiteParaCommitMsg) initEnv(cfg *types.Config, sub *types.ConfigSubModu
s.store = store.New(cfg.Store, sub.Store)
s.store.SetQueueClient(q.Client())
s.para = New(cfg.Consensus, sub.Consensus["para"]).(*ParaClient)
s.para = New(cfg.Consensus, sub.Consensus["para"]).(*client)
s.grpcCli = &typesmocks.Chain33Client{}
//data := &types.Int64{1}
s.grpcCli.On("GetLastBlockSequence", mock.Anything, mock.Anything).Return(nil, errors.New("nil"))
......@@ -97,7 +97,7 @@ func (s *suiteParaCommitMsg) initEnv(cfg *types.Config, sub *types.ConfigSubModu
}
func walletProcess(q queue.Queue, para *ParaClient) {
func walletProcess(q queue.Queue, para *client) {
defer para.wg.Done()
client := q.Client()
......@@ -109,7 +109,7 @@ func walletProcess(q queue.Queue, para *ParaClient) {
return
case msg := <-client.Recv():
if msg.Ty == types.EventDumpPrivkey {
msg.Reply(client.NewMessage("", types.EventHeader, &types.ReplyString{"6da92a632ab7deb67d38c0f6560bcfed28167998f6496db64c258d5e8393a81b"}))
msg.Reply(client.NewMessage("", types.EventHeader, &types.ReplyString{Data: "6da92a632ab7deb67d38c0f6560bcfed28167998f6496db64c258d5e8393a81b"}))
}
}
}
......
......@@ -16,37 +16,44 @@ import (
func init() {
drivers.Reg("pbft", NewPbft)
drivers.QueryData.Register("pbft", &PbftClient{})
drivers.QueryData.Register("pbft", &Client{})
}
type PbftClient struct {
// Client Pbft implementation
type Client struct {
*drivers.BaseClient
replyChan chan *types.ClientReply
requestChan chan *types.Request
isPrimary bool
}
func NewBlockstore(cfg *types.Consensus, replyChan chan *types.ClientReply, requestChan chan *types.Request, isPrimary bool) *PbftClient {
// NewBlockstore create Pbft Client
func NewBlockstore(cfg *types.Consensus, replyChan chan *types.ClientReply, requestChan chan *types.Request, isPrimary bool) *Client {
c := drivers.NewBaseClient(cfg)
client := &PbftClient{BaseClient: c, replyChan: replyChan, requestChan: requestChan, isPrimary: isPrimary}
client := &Client{BaseClient: c, replyChan: replyChan, requestChan: requestChan, isPrimary: isPrimary}
c.SetChild(client)
return client
}
func (client *PbftClient) ProcEvent(msg queue.Message) bool {
// ProcEvent method
func (client *Client) ProcEvent(msg queue.Message) bool {
return false
}
func (client *PbftClient) Propose(block *types.Block) {
op := &types.Operation{block}
// Propose method
func (client *Client) Propose(block *types.Block) {
op := &types.Operation{Value: block}
req := ToRequestClient(op, types.Now().String(), clientAddr)
client.requestChan <- req
}
func (client *PbftClient) CheckBlock(parent *types.Block, current *types.BlockDetail) error {
// CheckBlock method
func (client *Client) CheckBlock(parent *types.Block, current *types.BlockDetail) error {
return nil
}
func (client *PbftClient) SetQueueClient(c queue.Client) {
// SetQueueClient method
func (client *Client) SetQueueClient(c queue.Client) {
plog.Info("Enter SetQueue method of pbft consensus")
client.InitClient(c, func() {
......@@ -57,7 +64,8 @@ func (client *PbftClient) SetQueueClient(c queue.Client) {
go client.CreateBlock()
}
func (client *PbftClient) CreateBlock() {
// CreateBlock method
func (client *Client) CreateBlock() {
issleep := true
if !client.isPrimary {
return
......@@ -95,11 +103,13 @@ func (client *PbftClient) CreateBlock() {
}
}
func (client *PbftClient) GetGenesisBlockTime() int64 {
// GetGenesisBlockTime get genesis blocktime
func (client *Client) GetGenesisBlockTime() int64 {
return genesisBlockTime
}
func (client *PbftClient) CreateGenesisTx() (ret []*types.Transaction) {
// CreateGenesisTx get genesis tx
func (client *Client) CreateGenesisTx() (ret []*types.Transaction) {
var tx types.Transaction
tx.Execer = []byte("coins")
tx.To = genesis
......@@ -112,7 +122,7 @@ func (client *PbftClient) CreateGenesisTx() (ret []*types.Transaction) {
return
}
func (client *PbftClient) readReply() {
func (client *Client) readReply() {
data := <-client.replyChan
if data == nil {
......
......@@ -89,7 +89,7 @@ powLimitBits = "0x1f2fffff"
[consensus.sub.pbft]
genesis="14KEKbYtKKQm4wMthSK9J4La4nAiidGozt"
genesisBlockTime=1514533394
nodeId=1
nodeID=1
peersURL="127.0.0.1:8890"
clientAddr="127.0.0.1:8890"
......
......@@ -22,11 +22,12 @@ var (
type subConfig struct {
Genesis string `json:"genesis"`
GenesisBlockTime int64 `json:"genesisBlockTime"`
NodeId int64 `json:"nodeId"`
NodeID int64 `json:"nodeID"`
PeersURL string `json:"peersURL"`
ClientAddr string `json:"clientAddr"`
}
// NewPbft create pbft cluster
func NewPbft(cfg *pb.Consensus, sub []byte) queue.Module {
plog.Info("start to creat pbft node")
var subcfg subConfig
......@@ -40,14 +41,14 @@ func NewPbft(cfg *pb.Consensus, sub []byte) queue.Module {
if subcfg.GenesisBlockTime > 0 {
genesisBlockTime = subcfg.GenesisBlockTime
}
if int(subcfg.NodeId) == 0 || strings.Compare(subcfg.PeersURL, "") == 0 || strings.Compare(subcfg.ClientAddr, "") == 0 {
if int(subcfg.NodeID) == 0 || strings.Compare(subcfg.PeersURL, "") == 0 || strings.Compare(subcfg.ClientAddr, "") == 0 {
plog.Error("The nodeId, peersURL or clientAddr is empty!")
return nil
}
clientAddr = subcfg.ClientAddr
var c *PbftClient
replyChan, requestChan, isPrimary := NewReplica(uint32(subcfg.NodeId), subcfg.PeersURL, subcfg.ClientAddr)
var c *Client
replyChan, requestChan, isPrimary := NewReplica(uint32(subcfg.NodeID), subcfg.PeersURL, subcfg.ClientAddr)
c = NewBlockstore(cfg, replyChan, requestChan, isPrimary)
return c
}
......@@ -15,8 +15,7 @@ import (
"github.com/golang/protobuf/proto"
)
// Digest
// EQ Digest
func EQ(d1 []byte, d2 []byte) bool {
if len(d1) != len(d2) {
return false
......@@ -29,90 +28,91 @@ func EQ(d1 []byte, d2 []byte) bool {
return true
}
// Checkpoint
// ToCheckpoint method
func ToCheckpoint(sequence uint32, digest []byte) *types.Checkpoint {
return &types.Checkpoint{sequence, digest}
return &types.Checkpoint{Sequence: sequence, Digest: digest}
}
// Entry
// ToEntry method
func ToEntry(sequence uint32, digest []byte, view uint32) *types.Entry {
return &types.Entry{sequence, digest, view}
return &types.Entry{Sequence: sequence, Digest: digest, View: view}
}
// ViewChange
// ToViewChange method
func ToViewChange(viewchanger uint32, digest []byte) *types.ViewChange {
return &types.ViewChange{viewchanger, digest}
return &types.ViewChange{Viewchanger: viewchanger, Digest: digest}
}
// Summary
// ToSummary method
func ToSummary(sequence uint32, digest []byte) *types.Summary {
return &types.Summary{sequence, digest}
return &types.Summary{Sequence: sequence, Digest: digest}
}
// Request
// ToRequestClient method
func ToRequestClient(op *types.Operation, timestamp, client string) *types.Request {
return &types.Request{
Value: &types.Request_Client{
&types.RequestClient{op, timestamp, client}},
Client: &types.RequestClient{Op: op, Timestamp: timestamp, Client: client}},
}
}
// ToRequestPreprepare method
func ToRequestPreprepare(view, sequence uint32, digest []byte, replica uint32) *types.Request {
return &types.Request{
Value: &types.Request_Preprepare{
&types.RequestPrePrepare{view, sequence, digest, replica}},
Preprepare: &types.RequestPrePrepare{View: view, Sequence: sequence, Digest: digest, Replica: replica}},
}
}
// ToRequestPrepare method
func ToRequestPrepare(view, sequence uint32, digest []byte, replica uint32) *types.Request {
return &types.Request{
Value: &types.Request_Prepare{
&types.RequestPrepare{view, sequence, digest, replica}},
Prepare: &types.RequestPrepare{View: view, Sequence: sequence, Digest: digest, Replica: replica}},
}
}
// ToRequestCommit method
func ToRequestCommit(view, sequence, replica uint32) *types.Request {
return &types.Request{
Value: &types.Request_Commit{
&types.RequestCommit{view, sequence, replica}},
Commit: &types.RequestCommit{View: view, Sequence: sequence, Replica: replica}},
}
}
// ToRequestCheckpoint method
func ToRequestCheckpoint(sequence uint32, digest []byte, replica uint32) *types.Request {
return &types.Request{
Value: &types.Request_Checkpoint{
&types.RequestCheckpoint{sequence, digest, replica}},
Checkpoint: &types.RequestCheckpoint{Sequence: sequence, Digest: digest, Replica: replica}},
}
}
// ToRequestViewChange method
func ToRequestViewChange(view, sequence uint32, checkpoints []*types.Checkpoint, preps, prePreps []*types.Entry, replica uint32) *types.Request {
return &types.Request{
Value: &types.Request_Viewchange{
&types.RequestViewChange{view, sequence, checkpoints, preps, prePreps, replica}},
Viewchange: &types.RequestViewChange{View: view, Sequence: sequence, Checkpoints: checkpoints, Preps: preps, Prepreps: prePreps, Replica: replica}},
}
}
// ToRequestAck method
func ToRequestAck(view, replica, viewchanger uint32, digest []byte) *types.Request {
return &types.Request{
Value: &types.Request_Ack{
&types.RequestAck{view, replica, viewchanger, digest}},
Ack: &types.RequestAck{View: view, Replica: replica, Viewchanger: viewchanger, Digest: digest}},
}
}
// ToRequestNewView method
func ToRequestNewView(view uint32, viewChanges []*types.ViewChange, summaries []*types.Summary, replica uint32) *types.Request {
return &types.Request{
Value: &types.Request_Newview{
&types.RequestNewView{view, viewChanges, summaries, replica}},
Newview: &types.RequestNewView{View: view, Viewchanges: viewChanges, Summaries: summaries, Replica: replica}},
}
}
// Request Methods
// ReqDigest method
func ReqDigest(req *types.Request) []byte {
if req == nil {
return nil
......@@ -130,14 +130,12 @@ func ReqDigest(req *types.Request) []byte {
return lwm
}*/
// Reply
// ToReply method
func ToReply(view uint32, timestamp, client string, replica uint32, result *types.Result) *types.ClientReply {
return &types.ClientReply{view, timestamp, client, replica, result}
return &types.ClientReply{View: view, Timestamp: timestamp, Client: client, Replica: replica, Result: result}
}
// Reply Methods
// RepDigest method
func RepDigest(reply fmt.Stringer) []byte {
if reply == nil {
return nil
......@@ -146,8 +144,7 @@ func RepDigest(reply fmt.Stringer) []byte {
return bytes[:]
}
// Write proto message
// WriteMessage write proto message
func WriteMessage(addr string, msg proto.Message) error {
conn, err := net.Dial("tcp", addr)
defer conn.Close()
......@@ -163,8 +160,7 @@ func WriteMessage(addr string, msg proto.Message) error {
return err
}
// Read proto message
// ReadMessage read proto message
func ReadMessage(conn io.Reader, msg proto.Message) error {
var buf bytes.Buffer
n, err := io.Copy(&buf, conn)
......
......@@ -13,11 +13,13 @@ import (
"github.com/golang/protobuf/proto"
)
// constant
const (
CHECKPOINT_PERIOD uint32 = 128
CONSTANT_FACTOR uint32 = 2
CheckPointPeriod uint32 = 128
ConstantFactor uint32 = 2
)
// Replica struct
type Replica struct {
ID uint32
replicas map[uint32]string
......@@ -36,6 +38,7 @@ type Replica struct {
checkpoints []*pb.Checkpoint
}
// NewReplica create Replica instance
func NewReplica(id uint32, PeersURL string, addr string) (chan *pb.ClientReply, chan *pb.Request, bool) {
replyChan := make(chan *pb.ClientReply)
requestChan := make(chan *pb.Request)
......@@ -65,6 +68,7 @@ func NewReplica(id uint32, PeersURL string, addr string) (chan *pb.ClientReply,
}
// Startnode method
func (rep *Replica) Startnode(addr string) {
rep.acceptConnections(addr)
}
......@@ -104,7 +108,7 @@ func (rep *Replica) lowWaterMark() uint32 {
}
func (rep *Replica) highWaterMark() uint32 {
return rep.lowWaterMark() + CHECKPOINT_PERIOD*CONSTANT_FACTOR
return rep.lowWaterMark() + CheckPointPeriod*ConstantFactor
}
func (rep *Replica) sequenceInRange(sequence uint32) bool {
......@@ -133,9 +137,8 @@ func (rep *Replica) theLastReply() *pb.ClientReply {
func (rep *Replica) lastReplyToClient(client string) *pb.ClientReply {
if v, ok := rep.replies[client]; ok {
return v[len(rep.replies[client])-1]
} else {
return nil
}
return nil
}
func (rep *Replica) stateDigest() []byte {
......@@ -143,7 +146,7 @@ func (rep *Replica) stateDigest() []byte {
}
func (rep *Replica) isCheckpoint(sequence uint32) bool {
return sequence%CHECKPOINT_PERIOD == 0
return sequence%CheckPointPeriod == 0
}
func (rep *Replica) addCheckpoint(checkpoint *pb.Checkpoint) {
......@@ -735,7 +738,7 @@ func (rep *Replica) handleRequestCommit(REQ *pb.Request) {
op := req.GetClient().Op
timestamp := req.GetClient().Timestamp
client := req.GetClient().Client
result := &pb.Result{op.Value}
result := &pb.Result{Value: op.Value}
rep.executed = append(rep.executed, sequence)
reply := ToReply(view, timestamp, client, rep.ID, result)
......@@ -1036,7 +1039,7 @@ func (rep *Replica) correctSummaries(requests []*pb.Request, summaries []*pb.Sum
return
}
end := start + CHECKPOINT_PERIOD*CONSTANT_FACTOR
end := start + CheckPointPeriod*ConstantFactor
for seq := start; seq <= end; seq++ {
......@@ -1516,7 +1519,7 @@ FOR_LOOP_1:
summaries = append(summaries, summary)
start = summary.Sequence
end = start + CHECKPOINT_PERIOD*CONSTANT_FACTOR
end = start + CheckPointPeriod*ConstantFactor
// select summaries
// TODO: optimize
......
......@@ -96,7 +96,7 @@ func sendReplyList(q queue.Queue) {
count++
createReplyList("test" + strconv.Itoa(count))
msg.Reply(client.NewMessage("consensus", types.EventReplyTxList,
&types.ReplyTxList{transactions}))
&types.ReplyTxList{Txs: transactions}))
if count == 5 {
time.Sleep(5 * time.Second)
break
......@@ -125,7 +125,7 @@ func createReplyList(account string) {
var result []*types.Transaction
for j := 0; j < txSize; j++ {
//tx := &types.Transaction{}
val := &cty.CoinsAction_Transfer{&types.AssetsTransfer{Amount: 10}}
val := &cty.CoinsAction_Transfer{Transfer: &types.AssetsTransfer{Amount: 10}}
action := &cty.CoinsAction{Value: val, Ty: cty.CoinsActionTransfer}
tx := &types.Transaction{Execer: []byte("coins"), Payload: types.Encode(action), Fee: 0}
tx.To = "14qViLJfdGaP4EeHnDyJbEGQysnCpwn1gZ"
......
......@@ -24,10 +24,11 @@ var (
func init() {
drivers.Reg("raft", NewRaftCluster)
drivers.QueryData.Register("raft", &RaftClient{})
drivers.QueryData.Register("raft", &Client{})
}
type RaftClient struct {
// Client Raft implementation
type Client struct {
*drivers.BaseClient
proposeC chan<- *types.Block
commitC <-chan *types.Block
......@@ -38,18 +39,21 @@ type RaftClient struct {
once sync.Once
}
func NewBlockstore(cfg *types.Consensus, snapshotter *snap.Snapshotter, proposeC chan<- *types.Block, commitC <-chan *types.Block, errorC <-chan error, validatorC <-chan bool, stopC chan<- struct{}) *RaftClient {
// NewBlockstore create Raft Client
func NewBlockstore(cfg *types.Consensus, snapshotter *snap.Snapshotter, proposeC chan<- *types.Block, commitC <-chan *types.Block, errorC <-chan error, validatorC <-chan bool, stopC chan<- struct{}) *Client {
c := drivers.NewBaseClient(cfg)
client := &RaftClient{BaseClient: c, proposeC: proposeC, snapshotter: snapshotter, validatorC: validatorC, commitC: commitC, errorC: errorC, stopC: stopC}
client := &Client{BaseClient: c, proposeC: proposeC, snapshotter: snapshotter, validatorC: validatorC, commitC: commitC, errorC: errorC, stopC: stopC}
c.SetChild(client)
return client
}
func (client *RaftClient) GetGenesisBlockTime() int64 {
// GetGenesisBlockTime get genesis blocktime
func (client *Client) GetGenesisBlockTime() int64 {
return genesisBlockTime
}
func (client *RaftClient) CreateGenesisTx() (ret []*types.Transaction) {
// CreateGenesisTx get genesis tx
func (client *Client) CreateGenesisTx() (ret []*types.Transaction) {
var tx types.Transaction
tx.Execer = []byte(cty.CoinsX)
tx.To = genesis
......@@ -62,20 +66,22 @@ func (client *RaftClient) CreateGenesisTx() (ret []*types.Transaction) {
return
}
func (client *RaftClient) ProcEvent(msg queue.Message) bool {
// ProcEvent method
func (client *Client) ProcEvent(msg queue.Message) bool {
return false
}
func (client *RaftClient) CheckBlock(parent *types.Block, current *types.BlockDetail) error {
// CheckBlock method
func (client *Client) CheckBlock(parent *types.Block, current *types.BlockDetail) error {
return nil
}
func (client *RaftClient) getSnapshot() ([]byte, error) {
func (client *Client) getSnapshot() ([]byte, error) {
//这里可能导致死锁
return proto.Marshal(client.GetCurrentBlock())
}
func (client *RaftClient) recoverFromSnapshot(snapshot []byte) error {
func (client *Client) recoverFromSnapshot(snapshot []byte) error {
var block types.Block
if err := proto.Unmarshal(snapshot, &block); err != nil {
return err
......@@ -84,7 +90,8 @@ func (client *RaftClient) recoverFromSnapshot(snapshot []byte) error {
return nil
}
func (client *RaftClient) SetQueueClient(c queue.Client) {
// SetQueueClient method
func (client *Client) SetQueueClient(c queue.Client) {
rlog.Info("Enter SetQueue method of raft consensus")
client.InitClient(c, func() {
})
......@@ -93,12 +100,14 @@ func (client *RaftClient) SetQueueClient(c queue.Client) {
go client.pollingTask(c)
}
func (client *RaftClient) Close() {
// Close method
func (client *Client) Close() {
client.stopC <- struct{}{}
rlog.Info("consensus raft closed")
}
func (client *RaftClient) CreateBlock() {
// CreateBlock method
func (client *Client) CreateBlock() {
issleep := true
retry := 0
infoflag := 0
......@@ -187,12 +196,12 @@ func (client *RaftClient) CreateBlock() {
}
// 向raft底层发送block
func (client *RaftClient) propose(block *types.Block) {
func (client *Client) propose(block *types.Block) {
client.proposeC <- block
}
// 从receive channel中读leader发来的block
func (client *RaftClient) readCommits(commitC <-chan *types.Block, errorC <-chan error) {
func (client *Client) readCommits(commitC <-chan *types.Block, errorC <-chan error) {
var data *types.Block
var ok bool
for {
......@@ -216,7 +225,7 @@ func (client *RaftClient) readCommits(commitC <-chan *types.Block, errorC <-chan
}
//轮询任务,去检测本机器是否为validator节点,如果是,则执行打包任务
func (client *RaftClient) pollingTask(c queue.Client) {
func (client *Client) pollingTask(c queue.Client) {
ticker := time.NewTicker(100 * time.Millisecond)
defer ticker.Stop()
for {
......
......@@ -95,9 +95,9 @@ genesis="14KEKbYtKKQm4wMthSK9J4La4nAiidGozt"
genesisBlockTime=1514533394
# =============== raft共识配置参数 ===========================
# 共识节点ID,raft共识用到,不同的节点设置不同的nodeId(目前只支持1,2,3这种设置)
nodeId=1
nodeID=1
# raft共识用到,通过这个端口进行节点的增加和删除
raftApiPort=9121
raftAPIPort=9121
# raft共识用到,指示这个节点是否新增加节点
isNewJoinNode=false
# raft共识用到,指示raft集群中的服务器IP和端口
......
......@@ -20,17 +20,17 @@ var (
defaultSnapCount uint64 = 1000
snapshotCatchUpEntriesN uint64 = 1000
writeBlockSeconds int64 = 1
heartbeatTick int = 1
isLeader bool = false
heartbeatTick = 1
isLeader = false
confChangeC chan raftpb.ConfChange
)
type subConfig struct {
Genesis string `json:"genesis"`
GenesisBlockTime int64 `json:"genesisBlockTime"`
NodeId int64 `json:"nodeId"`
NodeID int64 `json:"nodeID"`
PeersURL string `json:"peersURL"`
RaftApiPort int64 `json:"raftApiPort"`
RaftAPIPort int64 `json:"raftAPIPort"`
IsNewJoinNode bool `json:"isNewJoinNode"`
ReadOnlyPeersURL string `json:"readOnlyPeersURL"`
AddPeersURL string `json:"addPeersURL"`
......@@ -39,6 +39,7 @@ type subConfig struct {
HeartbeatTick int32 `json:"heartbeatTick"`
}
// NewRaftCluster create raft cluster
func NewRaftCluster(cfg *types.Consensus, sub []byte) queue.Module {
rlog.Info("Start to create raft cluster")
var subcfg subConfig
......@@ -52,7 +53,7 @@ func NewRaftCluster(cfg *types.Consensus, sub []byte) queue.Module {
if subcfg.GenesisBlockTime > 0 {
genesisBlockTime = subcfg.GenesisBlockTime
}
if int(subcfg.NodeId) == 0 || strings.Compare(subcfg.PeersURL, "") == 0 {
if int(subcfg.NodeID) == 0 || strings.Compare(subcfg.PeersURL, "") == 0 {
rlog.Error("Please check whether the configuration of nodeId and peersURL is empty!")
//TODO 当传入的参数异常时,返回给主函数的是个nil,这时候需要做异常处理
return nil
......@@ -74,7 +75,7 @@ func NewRaftCluster(cfg *types.Consensus, sub []byte) queue.Module {
proposeC := make(chan *types.Block)
confChangeC = make(chan raftpb.ConfChange)
var b *RaftClient
var b *Client
getSnapshot := func() ([]byte, error) { return b.getSnapshot() }
// raft集群的建立,1. 初始化两条channel: propose channel用于客户端和raft底层交互, commit channel用于获取commit消息
// 2. raft集群中的节点之间建立http连接
......@@ -90,9 +91,9 @@ func NewRaftCluster(cfg *types.Consensus, sub []byte) queue.Module {
if len(addPeers) == 1 && addPeers[0] == "" {
addPeers = []string{}
}
commitC, errorC, snapshotterReady, validatorC, stopC := NewRaftNode(int(subcfg.NodeId), subcfg.IsNewJoinNode, peers, readOnlyPeers, addPeers, getSnapshot, proposeC, confChangeC)
commitC, errorC, snapshotterReady, validatorC, stopC := NewRaftNode(int(subcfg.NodeID), subcfg.IsNewJoinNode, peers, readOnlyPeers, addPeers, getSnapshot, proposeC, confChangeC)
//启动raft删除节点操作监听
go serveHttpRaftAPI(int(subcfg.RaftApiPort), confChangeC, errorC)
go serveHTTPRaftAPI(int(subcfg.RaftAPIPort), confChangeC, errorC)
// 监听commit channel,取block
b = NewBlockstore(cfg, <-snapshotterReady, proposeC, commitC, errorC, validatorC, stopC)
return b
......
......@@ -30,7 +30,7 @@ func (h *httpRaftAPI) ServeHTTP(w http.ResponseWriter, r *http.Request) {
return
}
nodeId, err := strconv.ParseUint(key[1:], 0, 64)
nodeID, err := strconv.ParseUint(key[1:], 0, 64)
if err != nil {
rlog.Error(fmt.Sprintf("Failed to convert ID for conf change (%v)", err.Error()))
http.Error(w, "Failed on POST", http.StatusBadRequest)
......@@ -39,14 +39,14 @@ func (h *httpRaftAPI) ServeHTTP(w http.ResponseWriter, r *http.Request) {
cc := raftpb.ConfChange{
Type: raftpb.ConfChangeAddNode,
NodeID: nodeId,
NodeID: nodeID,
Context: url,
}
h.confChangeC <- cc
// As above, optimistic that raft will apply the conf change
w.WriteHeader(http.StatusCreated)
case r.Method == "DELETE":
nodeId, err := strconv.ParseUint(key[1:], 0, 64)
nodeID, err := strconv.ParseUint(key[1:], 0, 64)
if err != nil {
rlog.Error(fmt.Sprintf("Failed to convert ID for conf change (%v)", err.Error()))
http.Error(w, "Failed on DELETE", http.StatusBadRequest)
......@@ -54,7 +54,7 @@ func (h *httpRaftAPI) ServeHTTP(w http.ResponseWriter, r *http.Request) {
}
cc := raftpb.ConfChange{
Type: raftpb.ConfChangeRemoveNode,
NodeID: nodeId,
NodeID: nodeID,
}
h.confChangeC <- cc
// As above, optimistic that raft will apply the conf change
......@@ -66,7 +66,7 @@ func (h *httpRaftAPI) ServeHTTP(w http.ResponseWriter, r *http.Request) {
}
}
func serveHttpRaftAPI(port int, confChangeC chan<- raftpb.ConfChange, errorC <-chan error) {
func serveHTTPRaftAPI(port int, confChangeC chan<- raftpb.ConfChange, errorC <-chan error) {
srv := http.Server{
Addr: "localhost:" + strconv.Itoa(port),
Handler: &httpRaftAPI{
......
......@@ -64,6 +64,7 @@ type raftNode struct {
restartC chan struct{}
}
// NewRaftNode create raft node
func NewRaftNode(id int, join bool, peers []string, readOnlyPeers []string, addPeers []string, getSnapshot func() ([]byte, error), proposeC <-chan *types.Block,
confChangeC <-chan raftpb.ConfChange) (<-chan *types.Block, <-chan error, <-chan *snap.Snapshotter, <-chan bool, chan<- struct{}) {
......@@ -212,7 +213,7 @@ func (rc *raftNode) serveChannels() {
defer ticker.Stop()
go func() {
var confChangeCount uint64 = 0
var confChangeCount uint64
// 通过propose和proposeConfchange方法往RaftNode发通知
for rc.proposeC != nil && rc.confChangeC != nil {
select {
......@@ -231,7 +232,7 @@ func (rc *raftNode) serveChannels() {
if !ok {
rc.confChangeC = nil
} else {
confChangeCount += 1
confChangeCount++
cc.ID = confChangeCount
rc.node.ProposeConfChange(context.TODO(), cc)
}
......
......@@ -34,8 +34,8 @@ import (
var (
random *rand.Rand
txNumber int = 10
loopCount int = 10
txNumber = 10
loopCount = 10
)
func init() {
......@@ -132,7 +132,7 @@ func sendReplyList(q queue.Queue) {
if msg.Ty == types.EventTxList {
count++
msg.Reply(client.NewMessage("consensus", types.EventReplyTxList,
&types.ReplyTxList{getReplyList(txNumber)}))
&types.ReplyTxList{Txs: getReplyList(txNumber)}))
if count >= loopCount {
time.Sleep(4 * time.Second)
break
......@@ -149,7 +149,7 @@ func prepareTxList() *types.Transaction {
key = generateKey(i, 32)
value = generateValue(i, 180)
nput := &pty.NormAction_Nput{&pty.NormPut{Key: key, Value: []byte(value)}}
nput := &pty.NormAction_Nput{Nput: &pty.NormPut{Key: key, Value: []byte(value)}}
action := &pty.NormAction{Value: nput, Ty: pty.NormActionPut}
tx := &types.Transaction{Execer: []byte("norm"), Payload: types.Encode(action), Fee: 0}
tx.To = address.ExecAddress("norm")
......
......@@ -45,7 +45,7 @@ func main() {
if isIndex {
fmt.Printf("Start dumping log entries from index %s.\n", *index)
walsnap.Index, err = strconv.ParseUint(*index, 10, 64)
walsnap.Index, _ = strconv.ParseUint(*index, 10, 64)
} else {
if *snapfile == "" {
ss := raftsnap.New(snapDir(dataDir))
......@@ -133,6 +133,7 @@ func genIDSlice(a []uint64) []types.ID {
return ids
}
// Block struct
type Block struct {
Version int64 `protobuf:"varint,1,opt,name=version" json:"version,omitempty"`
ParentHash []byte `protobuf:"bytes,2,opt,name=parentHash,proto3" json:"parentHash,omitempty"`
......@@ -144,6 +145,9 @@ type Block struct {
//Txs []*Transaction `protobuf:"bytes,7,rep,name=txs" json:"txs,omitempty"`
}
// Reset method
func (m *Block) Reset() { *m = Block{} }
func (m *Block) String() string { return proto.CompactTextString(m) }
// ProtoMessage method
func (*Block) ProtoMessage() {}
......@@ -98,6 +98,7 @@ func main() {
}
}
// LoadHelp show available commands
func LoadHelp() {
fmt.Println("Available Commands:")
fmt.Println("[ip] transferperf [from, to, amount, txNum, duration] : 转账性能测试")
......@@ -108,6 +109,7 @@ func LoadHelp() {
fmt.Println("[ip] normreadperf [num, interval, duration] : 常规读数据性能测试")
}
// TransferPerf run transfer performance
func TransferPerf(from string, to string, amount string, txNum string, duration string) {
txNumInt, err := strconv.Atoi(txNum)
if err != nil {
......@@ -139,6 +141,7 @@ func TransferPerf(from string, to string, amount string, txNum string, duration
}
}
// SendToAddress run transfer
func SendToAddress(from string, to string, amount string, note string) {
amountFloat64, err := strconv.ParseFloat(amount, 64)
if err != nil {
......@@ -162,6 +165,7 @@ func SendToAddress(from string, to string, amount string, note string) {
fmt.Println(string(data))
}
// NormPerf run norm performance
func NormPerf(size string, num string, interval string, duration string) {
var key string
var value string
......@@ -197,7 +201,7 @@ func NormPerf(size string, num string, interval string, duration string) {
ch := make(chan struct{}, numThread)
for i := 0; i < numThread; i++ {
go func() {
var result int64 = 0
var result int64
totalCount := 0
txCount := 0
_, priv := genaddress()
......@@ -228,7 +232,7 @@ func NormPerf(size string, num string, interval string, duration string) {
}
}
//zzh
// NormReadPerf run read performance
func NormReadPerf(num string, interval string, duration string) {
var numThread int
numInt, err := strconv.Atoi(num)
......@@ -260,7 +264,6 @@ func NormReadPerf(num string, interval string, duration string) {
f, err := os.Open("normperf.log")
if err != nil {
panic("open file failed.")
return
}
buf := bufio.NewReader(f)
cnt := 0
......@@ -277,7 +280,6 @@ func NormReadPerf(num string, interval string, duration string) {
f, err := os.Open("normperf.log")
if err != nil {
panic("open file failed.")
return
}
buf = bufio.NewReader(f)
}
......@@ -315,6 +317,7 @@ func NormReadPerf(num string, interval string, duration string) {
}
}
// RandStringBytes create random string
func RandStringBytes(n int) string {
b := make([]byte, n)
rand.Seed(types.Now().UnixNano())
......@@ -324,9 +327,10 @@ func RandStringBytes(n int) string {
return string(b)
}
// NormPut run put action
func NormPut(privkey string, key string, value string) {
fmt.Println(key, "=", value)
nput := &pty.NormAction_Nput{&pty.NormPut{Key: key, Value: []byte(value)}}
nput := &pty.NormAction_Nput{Nput: &pty.NormPut{Key: key, Value: []byte(value)}}
action := &pty.NormAction{Value: nput, Ty: pty.NormActionPut}
tx := &types.Transaction{Execer: []byte("norm"), Payload: types.Encode(action), Fee: fee}
tx.To = address.ExecAddress("norm")
......@@ -344,6 +348,7 @@ func NormPut(privkey string, key string, value string) {
}
}
// NormGet run query action
func NormGet(key string) {
in := &pty.NormGetKey{Key: key}
data, err := proto.Marshal(in)
......
......@@ -25,25 +25,28 @@ import (
var configPath = flag.String("f", "servers.toml", "configfile")
// ScpInfo struct
type ScpInfo struct {
UserName string
PassWord string
HostIp string
HostIP string
Port int
LocalFilePath string
RemoteDir string
}
// CmdInfo struct
type CmdInfo struct {
userName string
passWord string
hostIp string
hostIP string
port int
cmd string
remoteDir string
}
type tomlConfig struct {
// TomlConfig struct
type TomlConfig struct {
Title string
Servers map[string]ScpInfo
}
......@@ -117,8 +120,9 @@ func sftpconnect(user, password, host string, port int) (*sftp.Client, error) {
return sftpClient, nil
}
// ScpFileFromLocalToRemote copy local file to remote
func ScpFileFromLocalToRemote(si *ScpInfo) {
sftpClient, err := sftpconnect(si.UserName, si.PassWord, si.HostIp, si.Port)
sftpClient, err := sftpconnect(si.UserName, si.PassWord, si.HostIP, si.Port)
if err != nil {
fmt.Println("sftconnect have a err!")
log.Fatal(err)
......@@ -157,9 +161,10 @@ func ScpFileFromLocalToRemote(si *ScpInfo) {
fmt.Println("copy file to remote server finished!")
}
// RemoteExec run cmd in remote
func RemoteExec(cmdInfo *CmdInfo) error {
//A Session only accepts one call to Run, Start or Shell.
session, err := sshconnect(cmdInfo.userName, cmdInfo.passWord, cmdInfo.hostIp, cmdInfo.port)
session, err := sshconnect(cmdInfo.userName, cmdInfo.passWord, cmdInfo.hostIP, cmdInfo.port)
if err != nil {
return err
}
......@@ -180,8 +185,9 @@ func remoteScp(si *ScpInfo, reqnum chan struct{}) {
}
func InitCfg(path string) *tomlConfig {
var cfg tomlConfig
// InitCfg init config
func InitCfg(path string) *TomlConfig {
var cfg TomlConfig
if _, err := tml.DecodeFile(path, &cfg); err != nil {
fmt.Println(err)
os.Exit(0)
......@@ -243,6 +249,7 @@ func main() {
log.Printf("read common cost time %v\n", timeCommon.Sub(start))
}
// LoadHelp show available commands
func LoadHelp() {
fmt.Println("Available Commands:")
fmt.Println(" start : 启动服务 ")
......@@ -250,14 +257,14 @@ func LoadHelp() {
fmt.Println(" clear : 清空数据")
}
func startAll(conf *tomlConfig) {
func startAll(conf *TomlConfig) {
//fmt.Println(getCurrentDirectory())
arrMap := make(map[string]*CmdInfo)
//多协程启动部署
reqC := make(chan struct{}, len(conf.Servers))
for index, sc := range conf.Servers {
cmdInfo := &CmdInfo{}
cmdInfo.hostIp = sc.HostIp
cmdInfo.hostIP = sc.HostIP
cmdInfo.userName = sc.UserName
cmdInfo.port = sc.Port
cmdInfo.passWord = sc.PassWord
......@@ -276,11 +283,11 @@ func startAll(conf *tomlConfig) {
}
}
func stopAll(conf *tomlConfig) {
func stopAll(conf *TomlConfig) {
//执行速度快,不需要多起多协程工作
for _, sc := range conf.Servers {
cmdInfo := &CmdInfo{}
cmdInfo.hostIp = sc.HostIp
cmdInfo.hostIP = sc.HostIP
cmdInfo.userName = sc.UserName
cmdInfo.port = sc.Port
cmdInfo.passWord = sc.PassWord
......@@ -290,10 +297,10 @@ func stopAll(conf *tomlConfig) {
}
}
func clearAll(conf *tomlConfig) {
func clearAll(conf *TomlConfig) {
for _, sc := range conf.Servers {
cmdInfo := &CmdInfo{}
cmdInfo.hostIp = sc.HostIp
cmdInfo.hostIP = sc.HostIP
cmdInfo.userName = sc.UserName
cmdInfo.port = sc.Port
cmdInfo.passWord = sc.PassWord
......
This diff is collapsed.
......@@ -7,6 +7,8 @@ package ticket
import (
"testing"
"github.com/33cn/plugin/plugin/dapp/ticket/types"
_ "github.com/33cn/chain33/system"
"github.com/33cn/chain33/util/testnode"
_ "github.com/33cn/plugin/plugin/dapp/init"
......@@ -23,3 +25,20 @@ func TestTicket(t *testing.T) {
err := mock33.WaitHeight(100)
assert.Nil(t, err)
}
func TestTicketMap(t *testing.T) {
c := Client{}
ticketList := &types.ReplyTicketList{}
ticketList.Tickets = []*types.Ticket{
{TicketId: "1111"},
{TicketId: "2222"},
{TicketId: "3333"},
{TicketId: "4444"},
}
assert.Equal(t, c.getTicketCount(), int64(0))
c.setTicket(ticketList, nil)
assert.Equal(t, c.getTicketCount(), int64(4))
c.delTicket("3333")
assert.Equal(t, c.getTicketCount(), int64(3))
}
......@@ -19,43 +19,47 @@ import (
)
const (
ECDSA_RPIVATEKEY_LENGTH = 32
ECDSA_PUBLICKEY_LENGTH = 65
privateKeyECDSALength = 32
publicKeyECDSALength = 65
)
// Driver driver
type Driver struct{}
// Ctypto
// GenKey create private key
func (d Driver) GenKey() (crypto.PrivKey, error) {
privKeyBytes := [ECDSA_RPIVATEKEY_LENGTH]byte{}
copy(privKeyBytes[:], crypto.CRandBytes(ECDSA_RPIVATEKEY_LENGTH))
privKeyBytes := [privateKeyECDSALength]byte{}
copy(privKeyBytes[:], crypto.CRandBytes(privateKeyECDSALength))
priv, _ := privKeyFromBytes(elliptic.P256(), privKeyBytes[:])
copy(privKeyBytes[:], SerializePrivateKey(priv))
return PrivKeyECDSA(privKeyBytes), nil
}
// PrivKeyFromBytes create private key from bytes
func (d Driver) PrivKeyFromBytes(b []byte) (privKey crypto.PrivKey, err error) {
if len(b) != ECDSA_RPIVATEKEY_LENGTH {
if len(b) != privateKeyECDSALength {
return nil, errors.New("invalid priv key byte")
}
privKeyBytes := new([ECDSA_RPIVATEKEY_LENGTH]byte)
copy(privKeyBytes[:], b[:ECDSA_RPIVATEKEY_LENGTH])
privKeyBytes := new([privateKeyECDSALength]byte)
copy(privKeyBytes[:], b[:privateKeyECDSALength])
priv, _ := privKeyFromBytes(elliptic.P256(), privKeyBytes[:])
copy(privKeyBytes[:], SerializePrivateKey(priv))
return PrivKeyECDSA(*privKeyBytes), nil
}
// PubKeyFromBytes create public key from bytes
func (d Driver) PubKeyFromBytes(b []byte) (pubKey crypto.PubKey, err error) {
if len(b) != ECDSA_PUBLICKEY_LENGTH {
if len(b) != publicKeyECDSALength {
return nil, errors.New("invalid pub key byte")
}
pubKeyBytes := new([ECDSA_PUBLICKEY_LENGTH]byte)
pubKeyBytes := new([publicKeyECDSALength]byte)
copy(pubKeyBytes[:], b[:])
return PubKeyECDSA(*pubKeyBytes), nil
}
// SignatureFromBytes create signature from bytes
func (d Driver) SignatureFromBytes(b []byte) (sig crypto.Signature, err error) {
var certSignature crypto.CertSignature
_, err = asn1.Unmarshal(b, &certSignature)
......@@ -70,15 +74,17 @@ func (d Driver) SignatureFromBytes(b []byte) (sig crypto.Signature, err error) {
return SignatureECDSA(certSignature.Signature), nil
}
// PrivKey
type PrivKeyECDSA [ECDSA_RPIVATEKEY_LENGTH]byte
// PrivKeyECDSA PrivKey
type PrivKeyECDSA [privateKeyECDSALength]byte
// Bytes convert to bytes
func (privKey PrivKeyECDSA) Bytes() []byte {
s := make([]byte, ECDSA_RPIVATEKEY_LENGTH)
s := make([]byte, privateKeyECDSALength)
copy(s, privKey[:])
return s
}
// Sign create signature
func (privKey PrivKeyECDSA) Sign(msg []byte) crypto.Signature {
priv, pub := privKeyFromBytes(elliptic.P256(), privKey[:])
r, s, err := ecdsa.Sign(rand.Reader, priv, crypto.Sha256(msg))
......@@ -91,6 +97,7 @@ func (privKey PrivKeyECDSA) Sign(msg []byte) crypto.Signature {
return SignatureECDSA(ecdsaSigByte)
}
// PubKey convert to public key
func (privKey PrivKeyECDSA) PubKey() crypto.PubKey {
_, pub := privKeyFromBytes(elliptic.P256(), privKey[:])
var pubECDSA PubKeyECDSA
......@@ -98,6 +105,7 @@ func (privKey PrivKeyECDSA) PubKey() crypto.PubKey {
return pubECDSA
}
// Equals check privkey is equal
func (privKey PrivKeyECDSA) Equals(other crypto.PrivKey) bool {
if otherSecp, ok := other.(PrivKeyECDSA); ok {
return bytes.Equal(privKey[:], otherSecp[:])
......@@ -106,20 +114,23 @@ func (privKey PrivKeyECDSA) Equals(other crypto.PrivKey) bool {
return false
}
// String convert to string
func (privKey PrivKeyECDSA) String() string {
return fmt.Sprintf("PrivKeyECDSA{*****}")
}
// PubKey
// PubKeyECDSA PubKey
// prefixed with 0x02 or 0x03, depending on the y-cord.
type PubKeyECDSA [ECDSA_PUBLICKEY_LENGTH]byte
type PubKeyECDSA [publicKeyECDSALength]byte
// Bytes convert to bytes
func (pubKey PubKeyECDSA) Bytes() []byte {
s := make([]byte, ECDSA_PUBLICKEY_LENGTH)
s := make([]byte, publicKeyECDSALength)
copy(s, pubKey[:])
return s
}
// VerifyBytes verify signature
func (pubKey PubKeyECDSA) VerifyBytes(msg []byte, sig crypto.Signature) bool {
// unwrap if needed
if wrap, ok := sig.(SignatureS); ok {
......@@ -148,43 +159,48 @@ func (pubKey PubKeyECDSA) VerifyBytes(msg []byte, sig crypto.Signature) bool {
return ecdsa.Verify(pub, crypto.Sha256(msg), r, s)
}
// String convert to string
func (pubKey PubKeyECDSA) String() string {
return fmt.Sprintf("PubKeyECDSA{%X}", pubKey[:])
}
// Must return the full bytes in hex.
// KeyString Must return the full bytes in hex.
// Used for map keying, etc.
func (pubKey PubKeyECDSA) KeyString() string {
return fmt.Sprintf("%X", pubKey[:])
}
// Equals check public key is equal
func (pubKey PubKeyECDSA) Equals(other crypto.PubKey) bool {
if otherSecp, ok := other.(PubKeyECDSA); ok {
return bytes.Equal(pubKey[:], otherSecp[:])
} else {
return false
}
return false
}
type ECDSASignature struct {
type signatureECDSA struct {
R, S *big.Int
}
// Signature
// SignatureECDSA Signature
type SignatureECDSA []byte
// SignatureS signature struct
type SignatureS struct {
crypto.Signature
}
// Bytes convert signature to bytes
func (sig SignatureECDSA) Bytes() []byte {
s := make([]byte, len(sig))
copy(s, sig[:])
return s
}
// IsZero check signature is zero
func (sig SignatureECDSA) IsZero() bool { return len(sig) == 0 }
// String convert signature to string
func (sig SignatureECDSA) String() string {
fingerprint := make([]byte, len(sig[:]))
copy(fingerprint, sig[:])
......@@ -192,6 +208,7 @@ func (sig SignatureECDSA) String() string {
}
// Equals check signature equals
func (sig SignatureECDSA) Equals(other crypto.Signature) bool {
if otherEd, ok := other.(SignatureECDSA); ok {
return bytes.Equal(sig[:], otherEd[:])
......@@ -199,7 +216,10 @@ func (sig SignatureECDSA) Equals(other crypto.Signature) bool {
return false
}
// Name name
const Name = "auth_ecdsa"
// ID id
const ID = 257
func init() {
......
......@@ -13,12 +13,14 @@ import (
"math/big"
)
// MarshalECDSASignature marshal ECDSA signature
func MarshalECDSASignature(r, s *big.Int) ([]byte, error) {
return asn1.Marshal(ECDSASignature{r, s})
return asn1.Marshal(signatureECDSA{r, s})
}
// UnmarshalECDSASignature unmarshal ECDSA signature
func UnmarshalECDSASignature(raw []byte) (*big.Int, *big.Int, error) {
sig := new(ECDSASignature)
sig := new(signatureECDSA)
_, err := asn1.Unmarshal(raw, sig)
if err != nil {
return nil, nil, fmt.Errorf("failed unmashalling signature [%s]", err)
......@@ -41,6 +43,7 @@ func UnmarshalECDSASignature(raw []byte) (*big.Int, *big.Int, error) {
return sig.R, sig.S, nil
}
// ToLowS convert to low int
func ToLowS(k *ecdsa.PublicKey, s *big.Int) *big.Int {
lowS := IsLowS(s)
if !lowS {
......@@ -52,6 +55,7 @@ func ToLowS(k *ecdsa.PublicKey, s *big.Int) *big.Int {
return s
}
// IsLowS check is low int
func IsLowS(s *big.Int) bool {
return s.Cmp(new(big.Int).Rsh(elliptic.P256().Params().N, 1)) != 1
}
......@@ -78,16 +82,18 @@ func parsePubKey(pubKeyStr []byte, curve elliptic.Curve) (key *ecdsa.PublicKey,
return &pubkey, nil
}
// SerializePublicKey serialize public key
func SerializePublicKey(p *ecdsa.PublicKey) []byte {
b := make([]byte, 0, ECDSA_PUBLICKEY_LENGTH)
b := make([]byte, 0, publicKeyECDSALength)
b = append(b, 0x4)
b = paddedAppend(32, b, p.X.Bytes())
return paddedAppend(32, b, p.Y.Bytes())
}
// SerializePrivateKey serialize private key
func SerializePrivateKey(p *ecdsa.PrivateKey) []byte {
b := make([]byte, 0, ECDSA_RPIVATEKEY_LENGTH)
return paddedAppend(ECDSA_RPIVATEKEY_LENGTH, b, p.D.Bytes())
b := make([]byte, 0, privateKeyECDSALength)
return paddedAppend(privateKeyECDSALength, b, p.D.Bytes())
}
func paddedAppend(size uint, dst, src []byte) []byte {
......
......@@ -13,10 +13,10 @@ type sm2Driver struct {
sm2.Driver
}
const Name = "auth_sm2"
const ID = 258
const name = "auth_sm2"
const id = 258
func init() {
crypto.Register(Name, &sm2Driver{})
crypto.RegisterType(Name, ID)
crypto.Register(name, &sm2Driver{})
crypto.RegisterType(name, id)
}
......@@ -23,12 +23,19 @@ import (
var (
alog = log.New("module", "authority")
OrgName = "Chain33"
cpuNum = runtime.NumCPU()
// OrgName 默认证书组织名
OrgName = "Chain33"
// Author 全局证书校验器
Author = &Authority{}
// IsAuthEnable 是否开启全局校验开关
IsAuthEnable = false
)
// Authority 证书校验器主要结构
type Authority struct {
// 证书文件路径
cryptoPath string
......@@ -44,16 +51,14 @@ type Authority struct {
HistoryCertCache *HistoryCertData
}
/** 历史变更记录 **/
// HistoryCertData 历史变更记录
type HistoryCertData struct {
CryptoCfg *core.AuthConfig
CurHeight int64
NxtHeight int64
}
/**
初始化auth
*/
// Init 初始化auth
func (auth *Authority) Init(conf *ty.Authority) error {
if conf == nil || !conf.Enable {
return nil
......@@ -93,9 +98,7 @@ func (auth *Authority) Init(conf *ty.Authority) error {
return nil
}
/**
store数据转成authConfig数据
*/
// newAuthConfig store数据转成authConfig数据
func newAuthConfig(store *types.HistoryCertStore) *core.AuthConfig {
ret := &core.AuthConfig{}
ret.RootCerts = make([][]byte, len(store.Rootcerts))
......@@ -116,9 +119,7 @@ func newAuthConfig(store *types.HistoryCertStore) *core.AuthConfig {
return ret
}
/**
从数据库中的记录数据恢复证书,用于证书回滚
*/
// ReloadCert 从数据库中的记录数据恢复证书,用于证书回滚
func (auth *Authority) ReloadCert(store *types.HistoryCertStore) error {
if !IsAuthEnable {
return nil
......@@ -147,9 +148,7 @@ func (auth *Authority) ReloadCert(store *types.HistoryCertStore) error {
return nil
}
/**
从新的authdir下的文件更新证书,用于证书更新
*/
// ReloadCertByHeght 从新的authdir下的文件更新证书,用于证书更新
func (auth *Authority) ReloadCertByHeght(currentHeight int64) error {
if !IsAuthEnable {
return nil
......@@ -178,9 +177,7 @@ func (auth *Authority) ReloadCertByHeght(currentHeight int64) error {
return nil
}
/**
并发校验证书
*/
// ValidateCerts 并发校验证书
func (auth *Authority) ValidateCerts(task []*types.Signature) bool {
//FIXME 有并发校验的场景需要考虑竞争,暂时没有并发校验的场景
done := make(chan struct{})
......@@ -242,9 +239,7 @@ func (auth *Authority) task(done <-chan struct{}, taskes <-chan *types.Signature
}
}
/**
检验证书
*/
// Validate 检验证书
func (auth *Authority) Validate(signature *types.Signature) error {
// 从proto中解码signature
cert, err := auth.validator.GetCertFromSignature(signature.Signature)
......@@ -270,9 +265,7 @@ func (auth *Authority) Validate(signature *types.Signature) error {
return nil
}
/**
历史数据转成store可存储的历史数据
*/
// ToHistoryCertStore 历史数据转成store可存储的历史数据
func (certdata *HistoryCertData) ToHistoryCertStore(store *types.HistoryCertStore) {
if store == nil {
alog.Error("Convert cert data to cert store failed")
......@@ -298,19 +291,21 @@ func (certdata *HistoryCertData) ToHistoryCertStore(store *types.HistoryCertStor
store.NxtHeight = certdata.NxtHeight
}
// User 用户关联的证书私钥信息
type User struct {
Id string
ID string
Cert []byte
Key crypto.PrivKey
}
//userloader, SKD加载user使用
// UserLoader SKD加载user使用
type UserLoader struct {
configPath string
userMap map[string]*User
signType int
}
// Init userloader初始化
func (loader *UserLoader) Init(configPath string, signType string) error {
loader.configPath = configPath
loader.userMap = make(map[string]*User)
......@@ -381,9 +376,10 @@ func (loader *UserLoader) genCryptoPriv(keyBytes []byte) (crypto.PrivKey, error)
return priv, nil
}
func (load *UserLoader) Get(userName string) (*User, error) {
// Get 根据用户名获取user结构
func (loader *UserLoader) Get(userName string) (*User, error) {
keyvalue := fmt.Sprintf("%s@%s-cert.pem", userName, OrgName)
user, ok := load.userMap[keyvalue]
user, ok := loader.userMap[keyvalue]
if !ok {
return nil, types.ErrInvalidParam
}
......
......@@ -42,7 +42,7 @@ var (
txs = []*types.Transaction{tx1, tx2, tx3, tx4, tx5, tx6, tx7, tx8, tx9, tx10, tx11, tx12}
privRaw, _ = common.FromHex("CC38546E9E659D15E6B4893F0AB32A06D103931A8230B0BDE71459D2B27D6944")
tr = &cty.CoinsAction_Transfer{&types.AssetsTransfer{Amount: int64(1e8)}}
tr = &cty.CoinsAction_Transfer{Transfer: &types.AssetsTransfer{Amount: int64(1e8)}}
secpp256, _ = crypto.New(types.GetSignName("", types.SECP256K1))
privKey, _ = secpp256.PrivKeyFromBytes(privRaw)
tx14 = &types.Transaction{
......@@ -55,7 +55,7 @@ var (
)
var USERNAME = "User"
var SIGNTYPE = ct.AUTH_SM2
var SIGNTYPE = ct.AuthSM2
func signtx(tx *types.Transaction, priv crypto.PrivKey, cert []byte) {
tx.Sign(int32(SIGNTYPE), priv)
......@@ -197,7 +197,7 @@ func TestChckSignWithNoneAuth(t *testing.T) {
TestCase04 不带证书,SM2签名验证
*/
func TestChckSignWithSm2(t *testing.T) {
sm2, err := crypto.New(types.GetSignName("cert", ct.AUTH_SM2))
sm2, err := crypto.New(types.GetSignName("cert", ct.AuthSM2))
assert.Nil(t, err)
privKeysm2, _ := sm2.PrivKeyFromBytes(privRaw)
tx15 := &types.Transaction{Execer: []byte("coins"),
......@@ -213,7 +213,7 @@ func TestChckSignWithSm2(t *testing.T) {
types.SetMinFee(0)
defer types.SetMinFee(prev)
tx15.Sign(ct.AUTH_SM2, privKeysm2)
tx15.Sign(ct.AuthSM2, privKeysm2)
if !tx15.CheckSign() {
t.Error("check signature failed")
return
......@@ -224,7 +224,7 @@ func TestChckSignWithSm2(t *testing.T) {
TestCase05 不带证书,secp256r1签名验证
*/
func TestChckSignWithEcdsa(t *testing.T) {
ecdsacrypto, _ := crypto.New(types.GetSignName("cert", ct.AUTH_ECDSA))
ecdsacrypto, _ := crypto.New(types.GetSignName("cert", ct.AuthECDSA))
privKeyecdsa, _ := ecdsacrypto.PrivKeyFromBytes(privRaw)
tx16 := &types.Transaction{Execer: []byte("coins"),
Payload: types.Encode(&cty.CoinsAction{Value: tr, Ty: cty.CoinsActionTransfer}),
......@@ -239,7 +239,7 @@ func TestChckSignWithEcdsa(t *testing.T) {
types.SetMinFee(0)
defer types.SetMinFee(prev)
tx16.Sign(ct.AUTH_ECDSA, privKeyecdsa)
tx16.Sign(ct.AuthECDSA, privKeyecdsa)
if !tx16.CheckSign() {
t.Error("check signature failed")
return
......
......@@ -44,8 +44,8 @@ type tbsCertificate struct {
Validity validity
Subject asn1.RawValue
PublicKey publicKeyInfo
UniqueId asn1.BitString `asn1:"optional,tag:1"`
SubjectUniqueId asn1.BitString `asn1:"optional,tag:2"`
UniqueID asn1.BitString `asn1:"optional,tag:1"`
SubjectUniqueID asn1.BitString `asn1:"optional,tag:2"`
Extensions []pkix.Extension `asn1:"optional,explicit,tag:3"`
}
......@@ -58,10 +58,10 @@ func isECDSASignedCert(cert *x509.Certificate) bool {
func sanitizeECDSASignedCert(cert *x509.Certificate, parentCert *x509.Certificate) (*x509.Certificate, error) {
if cert == nil {
return nil, errors.New("Certificate must be different from nil.")
return nil, errors.New("Certificate must be different from nil")
}
if parentCert == nil {
return nil, errors.New("Parent certificate must be different from nil.")
return nil, errors.New("Parent certificate must be different from nil")
}
expectedSig, err := signatureToLowS(parentCert.PublicKey.(*ecdsa.PublicKey), cert.Signature)
......@@ -109,11 +109,12 @@ func certFromX509Cert(cert *x509.Certificate) (certificate, error) {
return newCert, nil
}
// ParseECDSAPubKey2SM2PubKey 将ECDSA的公钥转成SM2公钥
func ParseECDSAPubKey2SM2PubKey(key *ecdsa.PublicKey) *sm2.PublicKey {
sm2Key := &sm2.PublicKey{
key.Curve,
key.X,
key.Y,
Curve: key.Curve,
X: key.X,
Y: key.Y,
}
return sm2Key
......
......@@ -54,6 +54,7 @@ const (
crlsfolder = "crls"
)
// GetAuthConfig 获取证书文件配置
func GetAuthConfig(dir string) (*AuthConfig, error) {
cacertDir := filepath.Join(dir, cacerts)
intermediatecertsDir := filepath.Join(dir, intermediatecerts)
......
......@@ -38,6 +38,7 @@ type ecdsaValidator struct {
CRL []*pkix.CertificateList
}
// NewEcdsaValidator 创建ecdsa校验器
func NewEcdsaValidator() Validator {
return &ecdsaValidator{}
}
......@@ -148,7 +149,7 @@ func (validator *ecdsaValidator) Validate(certByte []byte, pubKey []byte) error
}
if !bytes.Equal(pubKey, ecdsa_util.SerializePublicKey(certPubKey)) {
return fmt.Errorf("Invalid public key.")
return fmt.Errorf("Invalid public key")
}
cert, err = validator.sanitizeCert(cert)
......@@ -212,7 +213,7 @@ func (validator *ecdsaValidator) getValidationChain(cert *x509.Certificate, isIn
parentPosition = 0
}
if validator.certificationTreeInternalNodesMap[string(validationChain[parentPosition].Raw)] {
return nil, fmt.Errorf("Invalid validation chain. Parent certificate should be a leaf of the certification tree [%v].", cert.Raw)
return nil, fmt.Errorf("Invalid validation chain. Parent certificate should be a leaf of the certification tree [%v]", cert.Raw)
}
return validationChain, nil
}
......@@ -403,7 +404,7 @@ func (validator *ecdsaValidator) getValidityOptsForCert(cert *x509.Certificate)
return tempOpts
}
func (Validator *ecdsaValidator) GetCertFromSignature(signature []byte) ([]byte, error) {
func (validator *ecdsaValidator) GetCertFromSignature(signature []byte) ([]byte, error) {
cert, _, err := utils.DecodeCertFromSignature(signature)
if err != nil {
authLogger.Error(fmt.Sprintf("unmashal certificate from signature failed. %s", err.Error()))
......
......@@ -10,13 +10,14 @@ import (
ty "github.com/33cn/plugin/plugin/dapp/cert/types"
)
// GetLocalValidator 根据类型获取校验器
func GetLocalValidator(authConfig *AuthConfig, signType int) (Validator, error) {
var lclValidator Validator
var err error
if signType == ty.AUTH_ECDSA {
if signType == ty.AuthECDSA {
lclValidator = NewEcdsaValidator()
} else if signType == ty.AUTH_SM2 {
} else if signType == ty.AuthSM2 {
lclValidator = NewGmValidator()
} else {
return nil, ty.ErrUnknowAuthSignType
......
......@@ -33,6 +33,7 @@ type gmValidator struct {
CRL []*pkix.CertificateList
}
// NewGmValidator 创建国密证书校验器
func NewGmValidator() Validator {
return &gmValidator{}
}
......@@ -90,7 +91,7 @@ func (validator *gmValidator) Validate(certByte []byte, pubKey []byte) error {
}
if !bytes.Equal(pubKey, sm2_util.SerializePublicKey(ParseECDSAPubKey2SM2PubKey(certPubKey))) {
return fmt.Errorf("Invalid public key.")
return fmt.Errorf("Invalid public key")
}
validationChain, err := validator.getCertificationChain(cert)
......@@ -150,7 +151,7 @@ func (validator *gmValidator) getValidationChain(cert *sm2.Certificate, isInterm
parentPosition = 0
}
if validator.certificationTreeInternalNodesMap[string(validationChain[parentPosition].Raw)] {
return nil, fmt.Errorf("Invalid validation chain. Parent certificate should be a leaf of the certification tree [%v].", cert.Raw)
return nil, fmt.Errorf("Invalid validation chain. Parent certificate should be a leaf of the certification tree [%v]", cert.Raw)
}
return validationChain, nil
}
......@@ -335,7 +336,7 @@ func (validator *gmValidator) getValidityOptsForCert(cert *sm2.Certificate) sm2.
return tempOpts
}
func (Validator *gmValidator) GetCertFromSignature(signature []byte) ([]byte, error) {
func (validator *gmValidator) GetCertFromSignature(signature []byte) ([]byte, error) {
// 从proto中解码signature
cert, _, err := utils.DecodeCertFromSignature(signature)
if err != nil {
......
......@@ -7,6 +7,7 @@ package core
type noneValidator struct {
}
// NewNoneValidator 创建none校验器
func NewNoneValidator() (Validator, error) {
return &noneValidator{}, nil
}
......@@ -19,6 +20,6 @@ func (validator *noneValidator) Validate(certByte []byte, pubKey []byte) error {
return nil
}
func (Validator *noneValidator) GetCertFromSignature(signature []byte) ([]byte, error) {
func (validator *noneValidator) GetCertFromSignature(signature []byte) ([]byte, error) {
return []byte(""), nil
}
......@@ -4,6 +4,7 @@
package core
// Validator 证书校验器
type Validator interface {
Setup(config *AuthConfig) error
......@@ -12,6 +13,7 @@ type Validator interface {
GetCertFromSignature(signature []byte) ([]byte, error)
}
// AuthConfig 校验器配置
type AuthConfig struct {
RootCerts [][]byte
IntermediateCerts [][]byte
......
......@@ -17,12 +17,17 @@ import (
)
const (
// CANAME 默认CA名称
CANAME = "ca"
// CONFIGFILENAME 配置文件名
CONFIGFILENAME = "chain33.cryptogen.toml"
// OUTPUTDIR 证书文件输出路径
OUTPUTDIR = "./authdir/crypto"
// ORGNAME 默认组织名
ORGNAME = "Chain33"
)
// Config 证书生成工具配置
type Config struct {
Name []string
SignType string
......
......@@ -7,10 +7,13 @@ package csp
import "crypto"
const (
// ECDSAP256KeyGen ECDSA类型
ECDSAP256KeyGen = 1
// SM2P256KygGen SM2类型
SM2P256KygGen = 2
)
// Key 通用key接口
type Key interface {
Bytes() ([]byte, error)
SKI() []byte
......@@ -19,25 +22,30 @@ type Key interface {
PublicKey() (Key, error)
}
// SignerOpts 签名器参数接口
type SignerOpts interface {
crypto.SignerOpts
}
// CSP 证书生成器接口
type CSP interface {
KeyGen(opts int) (k Key, err error)
Sign(k Key, digest []byte, opts SignerOpts) (signature []byte, err error)
}
// KeyStore key存储接口
type KeyStore interface {
ReadOnly() bool
StoreKey(k Key) (err error)
}
// Signer 签名器接口
type Signer interface {
Sign(k Key, digest []byte, opts SignerOpts) (signature []byte, err error)
}
// KeyGenerator key生成器接口
type KeyGenerator interface {
KeyGen(opts int) (k Key, err error)
}
......@@ -11,6 +11,7 @@ import (
"github.com/pkg/errors"
)
// New 创建新的证书生成结构
func New(keyStore KeyStore) (CSP, error) {
signers := make(map[reflect.Type]Signer)
signers[reflect.TypeOf(&ecdsaPrivateKey{})] = &ecdsaSigner{}
......@@ -58,10 +59,10 @@ func (csp *cspimpl) KeyGen(opts int) (k Key, err error) {
func (csp *cspimpl) Sign(k Key, digest []byte, opts SignerOpts) (signature []byte, err error) {
if k == nil {
return nil, errors.New("Invalid Key. It must not be nil.")
return nil, errors.New("Invalid Key. It must not be nil")
}
if len(digest) == 0 {
return nil, errors.New("Invalid digest. Cannot be empty.")
return nil, errors.New("Invalid digest. Cannot be empty")
}
keyType := reflect.TypeOf(k)
......
......@@ -32,10 +32,12 @@ func signECDSA(k *ecdsa.PrivateKey, digest []byte, opts SignerOpts) (signature [
return MarshalECDSASignature(r, s)
}
// ECDSASignature ECDSA签名结构
type ECDSASignature struct {
R, S *big.Int
}
// MarshalECDSASignature 编码ECDSA类型签名
func MarshalECDSASignature(r, s *big.Int) ([]byte, error) {
return asn1.Marshal(ECDSASignature{r, s})
}
......
......@@ -18,7 +18,7 @@ type ecdsaPrivateKey struct {
}
func (k *ecdsaPrivateKey) Bytes() (raw []byte, err error) {
return nil, errors.New("Not supported.")
return nil, errors.New("Not supported")
}
func (k *ecdsaPrivateKey) SKI() (ski []byte) {
......
......@@ -22,6 +22,7 @@ import (
var logger = log.New("tools", "cryptogen")
// NewFileBasedKeyStore 创建key存储器
func NewFileBasedKeyStore(pwd []byte, path string, readOnly bool) (KeyStore, error) {
ks := &fileBasedKeyStore{}
return ks, ks.Init(pwd, path, readOnly)
......@@ -40,14 +41,14 @@ type fileBasedKeyStore struct {
func (ks *fileBasedKeyStore) Init(pwd []byte, path string, readOnly bool) error {
if len(path) == 0 {
return errors.New("An invalid KeyStore path provided. Path cannot be an empty string.")
return errors.New("An invalid KeyStore path provided. Path cannot be an empty string")
}
ks.m.Lock()
defer ks.m.Unlock()
if ks.isOpen {
return errors.New("KeyStore already initilized.")
return errors.New("KeyStore already initilized")
}
ks.path = path
......@@ -74,11 +75,11 @@ func (ks *fileBasedKeyStore) ReadOnly() bool {
func (ks *fileBasedKeyStore) StoreKey(k Key) (err error) {
if ks.readOnly {
return errors.New("Read only KeyStore.")
return errors.New("Read only KeyStore")
}
if k == nil {
return errors.New("Invalid key. It must be different from nil.")
return errors.New("Invalid key. It must be different from nil")
}
switch k.(type) {
case *ecdsaPrivateKey:
......
......@@ -27,10 +27,12 @@ func signSM2(k *sm2.PrivateKey, digest []byte, opts SignerOpts) (signature []byt
return MarshalSM2Signature(r, s)
}
// SM2Signature SM2签名结构
type SM2Signature struct {
R, S *big.Int
}
// MarshalSM2Signature 编码SM2起签名
func MarshalSM2Signature(r, s *big.Int) ([]byte, error) {
return asn1.Marshal(SM2Signature{r, s})
}
......
......@@ -13,14 +13,17 @@ import (
"github.com/tjfoc/gmsm/sm2"
)
// SM2PrivateKey sm2私钥结构
type SM2PrivateKey struct {
PrivKey *sm2.PrivateKey
}
// Bytes sm2私钥转成byte
func (k *SM2PrivateKey) Bytes() (raw []byte, err error) {
return nil, errors.New("Not supported.")
return nil, errors.New("Not supported")
}
// SKI sm2私钥ski
func (k *SM2PrivateKey) SKI() (ski []byte) {
if k.PrivKey == nil {
return nil
......@@ -33,22 +36,27 @@ func (k *SM2PrivateKey) SKI() (ski []byte) {
return hash.Sum(nil)
}
// Symmetric sm2私钥Symmetric
func (k *SM2PrivateKey) Symmetric() bool {
return false
}
// Private sm2私钥
func (k *SM2PrivateKey) Private() bool {
return true
}
// PublicKey sm2私钥对应公钥
func (k *SM2PrivateKey) PublicKey() (Key, error) {
return &SM2PublicKey{&k.PrivKey.PublicKey}, nil
}
// SM2PublicKey sm2公钥结构
type SM2PublicKey struct {
PubKey *sm2.PublicKey
}
// Bytes sm2公钥转成byte
func (k *SM2PublicKey) Bytes() (raw []byte, err error) {
raw, err = sm2.MarshalSm2PublicKey(k.PubKey)
if err != nil {
......@@ -57,6 +65,7 @@ func (k *SM2PublicKey) Bytes() (raw []byte, err error) {
return
}
// SKI sm2公钥ski
func (k *SM2PublicKey) SKI() (ski []byte) {
if k.PubKey == nil {
return nil
......@@ -69,14 +78,17 @@ func (k *SM2PublicKey) SKI() (ski []byte) {
return hash.Sum(nil)
}
// Symmetric sm2公钥Symmetric
func (k *SM2PublicKey) Symmetric() bool {
return false
}
// Private 是否sm2私钥
func (k *SM2PublicKey) Private() bool {
return false
}
// PublicKey sm2公钥
func (k *SM2PublicKey) PublicKey() (Key, error) {
return k, nil
}
......@@ -20,15 +20,16 @@ type cspCryptoSigner struct {
pk interface{}
}
// New 创建签名器
func New(csp lccsp.CSP, key lccsp.Key) (crypto.Signer, error) {
if csp == nil {
return nil, errors.New("bccsp instance must be different from nil.")
return nil, errors.New("bccsp instance must be different from nil")
}
if key == nil {
return nil, errors.New("key must be different from nil.")
return nil, errors.New("key must be different from nil")
}
if key.Symmetric() {
return nil, errors.New("key must be asymmetric.")
return nil, errors.New("key must be asymmetric")
}
pub, err := key.PublicKey()
......
......@@ -44,18 +44,19 @@ func oidFromNamedCurve(curve elliptic.Curve) (asn1.ObjectIdentifier, bool) {
return nil, false
}
// PrivateKeyToPEM 私钥转pem
func PrivateKeyToPEM(privateKey interface{}, pwd []byte) ([]byte, error) {
if len(pwd) != 0 {
return privateKeyToEncryptedPEM(privateKey, pwd)
}
if privateKey == nil {
return nil, errors.New("Invalid key. It must be different from nil.")
return nil, errors.New("Invalid key. It must be different from nil")
}
switch k := privateKey.(type) {
case *ecdsa.PrivateKey:
if k == nil {
return nil, errors.New("Invalid ecdsa private key. It must be different from nil.")
return nil, errors.New("Invalid ecdsa private key. It must be different from nil")
}
oidNamedCurve, ok := oidFromNamedCurve(k.Curve)
......@@ -95,7 +96,7 @@ func PrivateKeyToPEM(privateKey interface{}, pwd []byte) ([]byte, error) {
), nil
case *sm2.PrivateKey:
if k == nil {
return nil, errors.New("Invalid sm2 private key. It must be different from nil.")
return nil, errors.New("Invalid sm2 private key. It must be different from nil")
}
return sm2.WritePrivateKeytoMem(k, nil)
default:
......@@ -105,13 +106,13 @@ func PrivateKeyToPEM(privateKey interface{}, pwd []byte) ([]byte, error) {
func privateKeyToEncryptedPEM(privateKey interface{}, pwd []byte) ([]byte, error) {
if privateKey == nil {
return nil, errors.New("Invalid private key. It must be different from nil.")
return nil, errors.New("Invalid private key. It must be different from nil")
}
switch k := privateKey.(type) {
case *ecdsa.PrivateKey:
if k == nil {
return nil, errors.New("Invalid ecdsa private key. It must be different from nil.")
return nil, errors.New("Invalid ecdsa private key. It must be different from nil")
}
raw, err := x509.MarshalECPrivateKey(k)
......@@ -137,19 +138,20 @@ func privateKeyToEncryptedPEM(privateKey interface{}, pwd []byte) ([]byte, error
}
}
// PublicKeyToPEM 公钥转pem
func PublicKeyToPEM(publicKey interface{}, pwd []byte) ([]byte, error) {
if len(pwd) != 0 {
return publicKeyToEncryptedPEM(publicKey, pwd)
}
if publicKey == nil {
return nil, errors.New("Invalid public key. It must be different from nil.")
return nil, errors.New("Invalid public key. It must be different from nil")
}
switch k := publicKey.(type) {
case *ecdsa.PublicKey:
if k == nil {
return nil, errors.New("Invalid ecdsa public key. It must be different from nil.")
return nil, errors.New("Invalid ecdsa public key. It must be different from nil")
}
PubASN1, err := x509.MarshalPKIXPublicKey(k)
if err != nil {
......@@ -164,7 +166,7 @@ func PublicKeyToPEM(publicKey interface{}, pwd []byte) ([]byte, error) {
), nil
case *sm2.PublicKey:
if k == nil {
return nil, errors.New("Invalid sm2 public key. It must be different from nil.")
return nil, errors.New("Invalid sm2 public key. It must be different from nil")
}
return sm2.WritePublicKeytoMem(k, nil)
......@@ -175,16 +177,16 @@ func PublicKeyToPEM(publicKey interface{}, pwd []byte) ([]byte, error) {
func publicKeyToEncryptedPEM(publicKey interface{}, pwd []byte) ([]byte, error) {
if publicKey == nil {
return nil, errors.New("Invalid public key. It must be different from nil.")
return nil, errors.New("Invalid public key. It must be different from nil")
}
if len(pwd) == 0 {
return nil, errors.New("Invalid password. It must be different from nil.")
return nil, errors.New("Invalid password. It must be different from nil")
}
switch k := publicKey.(type) {
case *ecdsa.PublicKey:
if k == nil {
return nil, errors.New("Invalid ecdsa public key. It must be different from nil.")
return nil, errors.New("Invalid ecdsa public key. It must be different from nil")
}
raw, err := x509.MarshalPKIXPublicKey(k)
if err != nil {
......@@ -209,9 +211,10 @@ func publicKeyToEncryptedPEM(publicKey interface{}, pwd []byte) ([]byte, error)
}
}
// DERToPublicKey DER字符转成公钥
func DERToPublicKey(raw []byte) (pub interface{}, err error) {
if len(raw) == 0 {
return nil, errors.New("Invalid DER. It must be different from nil.")
return nil, errors.New("Invalid DER. It must be different from nil")
}
key, err := x509.ParsePKIXPublicKey(raw)
......@@ -222,6 +225,7 @@ func DERToPublicKey(raw []byte) (pub interface{}, err error) {
return key, err
}
// Clone 克隆结构
func Clone(src []byte) []byte {
clone := make([]byte, len(src))
copy(clone, src)
......
......@@ -6,6 +6,7 @@ package generator
import "crypto/x509"
// CAGenerator CA生成器接口
type CAGenerator interface {
SignCertificate(baseDir, name string, sans []string, pub interface{}) (*x509.Certificate, error)
......
......@@ -25,12 +25,14 @@ import (
"github.com/tjfoc/gmsm/sm2"
)
// EcdsaCA ecdsa CA结构
type EcdsaCA struct {
Name string
Signer crypto.Signer
SignCert *x509.Certificate
}
// SM2CA SM2 CA结构
type SM2CA struct {
Name string
Signer crypto.Signer
......@@ -38,10 +40,11 @@ type SM2CA struct {
Sm2Key csp.Key
}
// NewCA 根据类型生成CA生成器
func NewCA(baseDir, name string, signType int) (generator.CAGenerator, error) {
if signType == ty.AUTH_ECDSA {
if signType == ty.AuthECDSA {
return newEcdsaCA(baseDir, name)
} else if signType == ty.AUTH_SM2 {
} else if signType == ty.AuthSM2 {
return newSM2CA(baseDir, name)
} else {
return nil, fmt.Errorf("Invalid sign type")
......@@ -92,6 +95,7 @@ func newEcdsaCA(baseDir, name string) (*EcdsaCA, error) {
return ca, nil
}
// SignCertificate 证书签名
func (ca *EcdsaCA) SignCertificate(baseDir, name string, sans []string, pub interface{}) (*x509.Certificate, error) {
template := x509Template()
template.KeyUsage = x509.KeyUsageDigitalSignature
......@@ -112,6 +116,7 @@ func (ca *EcdsaCA) SignCertificate(baseDir, name string, sans []string, pub inte
return cert, nil
}
// GenerateLocalUser 生成本地用户
func (ca *EcdsaCA) GenerateLocalUser(baseDir, name string) error {
err := createFolderStructure(baseDir, true)
if err != nil {
......@@ -229,6 +234,7 @@ func newSM2CA(baseDir, name string) (*SM2CA, error) {
return ca, nil
}
// SignCertificate 证书签名
func (ca *SM2CA) SignCertificate(baseDir, name string, sans []string, pub interface{}) (*x509.Certificate, error) {
template := x509Template()
template.KeyUsage = x509.KeyUsageDigitalSignature
......@@ -250,6 +256,7 @@ func (ca *SM2CA) SignCertificate(baseDir, name string, sans []string, pub interf
return utils.ParseSm2CertificateToX509(cert), nil
}
// GenerateLocalUser 生成本地用户
func (ca *SM2CA) GenerateLocalUser(baseDir, name string) error {
err := createFolderStructure(baseDir, true)
if err != nil {
......
......@@ -11,6 +11,7 @@ import (
"github.com/tjfoc/gmsm/sm2"
)
// CreateCertificateToMem 证书转mem
func CreateCertificateToMem(template, parent *sm2.Certificate, key csp.Key) (cert []byte, err error) {
pk := key.(*csp.SM2PrivateKey).PrivKey
......@@ -25,6 +26,7 @@ func CreateCertificateToMem(template, parent *sm2.Certificate, key csp.Key) (cer
return
}
// CreateCertificateToPem 证书转pem
func CreateCertificateToPem(FileName string, template, parent *sm2.Certificate, key csp.Key) (bool, error) {
pk := key.(*csp.SM2PrivateKey).PrivKey
......@@ -44,6 +46,7 @@ func CreateCertificateToPem(FileName string, template, parent *sm2.Certificate,
return result, err
}
// ParseX509CertificateToSm2 解析x509格式为sm2格式证书
func ParseX509CertificateToSm2(x509Cert *x509.Certificate) *sm2.Certificate {
sm2cert := &sm2.Certificate{
Raw: x509Cert.Raw,
......@@ -103,6 +106,7 @@ func ParseX509CertificateToSm2(x509Cert *x509.Certificate) *sm2.Certificate {
return sm2cert
}
// ParseSm2CertificateToX509 解析sm2格式证书为x509格式
func ParseSm2CertificateToX509(sm2Cert *sm2.Certificate) *x509.Certificate {
if sm2Cert == nil {
return nil
......
......@@ -19,7 +19,7 @@ import (
func getCSPFromOpts(KeyStorePath string) (csp.CSP, error) {
if KeyStorePath == "" {
return nil, errors.New("Invalid config. It must not be nil.")
return nil, errors.New("Invalid config. It must not be nil")
}
fks, err := csp.NewFileBasedKeyStore(nil, KeyStorePath, false)
......@@ -30,6 +30,7 @@ func getCSPFromOpts(KeyStorePath string) (csp.CSP, error) {
return csp.New(fks)
}
// GeneratePrivateKey 生成私钥
func GeneratePrivateKey(keystorePath string, opt int) (csp.Key, crypto.Signer, error) {
var err error
var priv csp.Key
......@@ -48,6 +49,7 @@ func GeneratePrivateKey(keystorePath string, opt int) (csp.Key, crypto.Signer, e
return priv, s, err
}
// GetECPublicKey 获取ecdsa公钥
func GetECPublicKey(priv csp.Key) (*ecdsa.PublicKey, error) {
pubKey, err := priv.PublicKey()
if err != nil {
......@@ -66,6 +68,7 @@ func GetECPublicKey(priv csp.Key) (*ecdsa.PublicKey, error) {
return ecPubKey.(*ecdsa.PublicKey), nil
}
// GetSM2PublicKey 获取sm2公钥
func GetSM2PublicKey(priv csp.Key) (*sm2.PublicKey, error) {
pubKey, err := priv.PublicKey()
if err != nil {
......
......@@ -5,16 +5,14 @@
package utils
import (
"bufio"
"encoding/pem"
"fmt"
"io"
"io/ioutil"
"os"
"github.com/33cn/chain33/util"
)
// DirMissingOrEmpty 路径是否为空
func DirMissingOrEmpty(path string) (bool, error) {
dirExists, err := DirExists(path)
if err != nil {
......@@ -34,6 +32,7 @@ func DirMissingOrEmpty(path string) (bool, error) {
return false, nil
}
// DirExists 目录是否存在
func DirExists(path string) (bool, error) {
_, err := os.Stat(path)
if err == nil {
......@@ -45,6 +44,7 @@ func DirExists(path string) (bool, error) {
return false, err
}
// DirEmpty 目录是否为空
func DirEmpty(path string) (bool, error) {
f, err := os.Open(path)
if err != nil {
......@@ -59,6 +59,7 @@ func DirEmpty(path string) (bool, error) {
return false, err
}
// ReadFile 读取文件
func ReadFile(file string) ([]byte, error) {
fileCont, err := ioutil.ReadFile(file)
if err != nil {
......@@ -68,6 +69,7 @@ func ReadFile(file string) ([]byte, error) {
return fileCont, nil
}
// ReadPemFile 读取pem文件
func ReadPemFile(file string) ([]byte, error) {
bytes, err := ReadFile(file)
if err != nil {
......@@ -82,35 +84,7 @@ func ReadPemFile(file string) ([]byte, error) {
return bytes, nil
}
func CheckFileIsExist(filename string) bool {
var exist = true
if _, err := os.Stat(filename); os.IsNotExist(err) {
exist = false
}
return exist
}
// DeleteFile 删除文件
func DeleteFile(file string) error {
return os.Remove(file)
}
func WriteStringToFile(file, content string) (writeLen int, err error) {
var f *os.File
if err = util.MakeDir(file); err != nil {
return
}
util.DeleteFile(file)
if CheckFileIsExist(file) {
f, err = os.OpenFile(file, os.O_APPEND, 0666)
} else {
f, err = os.Create(file)
}
if err != nil {
return
}
defer f.Close()
w := bufio.NewWriter(f)
writeLen, err = w.WriteString(content)
w.Flush()
return
}
......@@ -25,6 +25,7 @@ import (
"github.com/tjfoc/gmsm/sm2"
)
// SKI 计算ski
func SKI(curve elliptic.Curve, x, y *big.Int) (ski []byte) {
raw := elliptic.Marshal(curve, x, y)
......@@ -33,6 +34,7 @@ func SKI(curve elliptic.Curve, x, y *big.Int) (ski []byte) {
return hash.Sum(nil)
}
// GetPublicKeySKIFromCert 从cert字节中获取公钥ski
func GetPublicKeySKIFromCert(cert []byte, signType int) (string, error) {
dcert, _ := pem.Decode(cert)
if dcert == nil {
......@@ -41,14 +43,14 @@ func GetPublicKeySKIFromCert(cert []byte, signType int) (string, error) {
var ski []byte
switch signType {
case ty.AUTH_ECDSA:
case ty.AuthECDSA:
x509Cert, err := x509.ParseCertificate(dcert.Bytes)
if err != nil {
return "", errors.Errorf("Unable to parse cert from decoded bytes: %s", err)
}
ecdsaPk := x509Cert.PublicKey.(*ecdsa.PublicKey)
ski = SKI(ecdsaPk.Curve, ecdsaPk.X, ecdsaPk.Y)
case ty.AUTH_SM2:
case ty.AuthSM2:
sm2Cert, err := sm2.ParseCertificate(dcert.Bytes)
if err != nil {
return "", errors.Errorf("Unable to parse cert from decoded bytes: %s", err)
......@@ -62,6 +64,7 @@ func GetPublicKeySKIFromCert(cert []byte, signType int) (string, error) {
return hex.EncodeToString(ski), nil
}
// EncodeCertToSignature 证书编码进签名
func EncodeCertToSignature(signByte []byte, cert []byte) ([]byte, error) {
certSign := crypto.CertSignature{}
certSign.Signature = append(certSign.Signature, signByte...)
......@@ -69,6 +72,7 @@ func EncodeCertToSignature(signByte []byte, cert []byte) ([]byte, error) {
return asn1.Marshal(certSign)
}
// DecodeCertFromSignature 从签名中解码证书
func DecodeCertFromSignature(signByte []byte) ([]byte, []byte, error) {
var certSignature crypto.CertSignature
_, err := asn1.Unmarshal(signByte, &certSignature)
......@@ -79,6 +83,7 @@ func DecodeCertFromSignature(signByte []byte) ([]byte, []byte, error) {
return certSignature.Cert, certSignature.Signature, nil
}
// PrivKeyByteFromRaw pem结构转成byte类型私钥
func PrivKeyByteFromRaw(raw []byte, signType int) ([]byte, error) {
block, _ := pem.Decode(raw)
if block == nil {
......@@ -86,13 +91,13 @@ func PrivKeyByteFromRaw(raw []byte, signType int) ([]byte, error) {
}
switch signType {
case ty.AUTH_ECDSA:
case ty.AuthECDSA:
key, err := x509.ParsePKCS8PrivateKey(block.Bytes)
if err != nil {
return nil, err
}
return ecdsa_util.SerializePrivateKey(key.(*ecdsa.PrivateKey)), nil
case ty.AUTH_SM2:
case ty.AuthSM2:
key, err := sm2.ParsePKCS8PrivateKey(block.Bytes, nil)
if err != nil {
return nil, err
......
......@@ -20,6 +20,7 @@ func init() {
ety.InitFuncList(types.ListMethod(&Cert{}))
}
// Init 初始化
func Init(name string, sub []byte) {
driverName = name
var cfg ct.Authority
......@@ -30,10 +31,12 @@ func Init(name string, sub []byte) {
drivers.Register(driverName, newCert, types.GetDappFork(driverName, "Enable"))
}
// GetName 获取cert执行器名
func GetName() string {
return newCert().GetName()
}
// Cert cert执行器
type Cert struct {
drivers.DriverBase
}
......@@ -45,10 +48,12 @@ func newCert() drivers.Driver {
return c
}
// GetDriverName 获取cert执行器名
func (c *Cert) GetDriverName() string {
return driverName
}
// CheckTx cert执行器tx证书校验
func (c *Cert) CheckTx(tx *types.Transaction, index int) error {
// 基类检查
err := c.DriverBase.CheckTx(tx, index)
......@@ -86,7 +91,12 @@ func (c *Cert) CheckTx(tx *types.Transaction, index int) error {
根据前缀查找证书变更记录,cert回滚、重启、同步用到
*/
func (c *Cert) loadHistoryByPrefix() error {
parm := &types.LocalDBList{[]byte("LODB-cert-"), nil, 0, 0}
parm := &types.LocalDBList{
Prefix: []byte("LODB-cert-"),
Key: nil,
Direction: 0,
Count: 0,
}
result, err := c.DriverBase.GetApi().LocalList(parm)
if err != nil {
return err
......@@ -115,7 +125,7 @@ func (c *Cert) loadHistoryByPrefix() error {
*/
func (c *Cert) loadHistoryByHeight() error {
key := calcCertHeightKey(c.GetHeight())
parm := &types.LocalDBGet{[][]byte{key}}
parm := &types.LocalDBGet{Keys: [][]byte{key}}
result, err := c.DriverBase.GetApi().LocalGet(parm)
if err != nil {
return err
......
......@@ -16,6 +16,7 @@ func calcCertHeightKey(height int64) []byte {
return []byte(fmt.Sprintf("LODB-cert-%d", height))
}
// ExecLocal_New 启用证书交易执行
func (c *Cert) ExecLocal_New(payload *ct.CertNew, tx *types.Transaction, receiptData *types.ReceiptData, index int) (*types.LocalDBSet, error) {
if !authority.IsAuthEnable {
clog.Error("Authority is not available. Please check the authority config or authority initialize error logs.")
......@@ -27,17 +28,24 @@ func (c *Cert) ExecLocal_New(payload *ct.CertNew, tx *types.Transaction, receipt
authority.Author.HistoryCertCache.CurHeight = c.GetHeight()
authority.Author.HistoryCertCache.ToHistoryCertStore(historityCertdata)
key := calcCertHeightKey(c.GetHeight())
set.KV = append(set.KV, &types.KeyValue{key, types.Encode(historityCertdata)})
set.KV = append(set.KV, &types.KeyValue{
Key: key,
Value: types.Encode(historityCertdata),
})
// 构造非证书历史数据
noneCertdata := &types.HistoryCertStore{}
noneCertdata.NxtHeight = historityCertdata.CurHeigth
noneCertdata.CurHeigth = 0
set.KV = append(set.KV, &types.KeyValue{calcCertHeightKey(0), types.Encode(noneCertdata)})
set.KV = append(set.KV, &types.KeyValue{
Key: calcCertHeightKey(0),
Value: types.Encode(noneCertdata),
})
return &set, nil
}
// ExecLocal_Update 更新证书交易执行
func (c *Cert) ExecLocal_Update(payload *ct.CertUpdate, tx *types.Transaction, receiptData *types.ReceiptData, index int) (*types.LocalDBSet, error) {
if !authority.IsAuthEnable {
clog.Error("Authority is not available. Please check the authority config or authority initialize error logs.")
......@@ -50,17 +58,24 @@ func (c *Cert) ExecLocal_Update(payload *ct.CertUpdate, tx *types.Transaction, r
historityCertdata := &types.HistoryCertStore{}
authority.Author.HistoryCertCache.NxtHeight = c.GetHeight()
authority.Author.HistoryCertCache.ToHistoryCertStore(historityCertdata)
set.KV = append(set.KV, &types.KeyValue{key, types.Encode(historityCertdata)})
set.KV = append(set.KV, &types.KeyValue{
Key: key,
Value: types.Encode(historityCertdata),
})
// 证书更新
historityCertdata = &types.HistoryCertStore{}
authority.Author.ReloadCertByHeght(c.GetHeight())
authority.Author.HistoryCertCache.ToHistoryCertStore(historityCertdata)
setKey := calcCertHeightKey(c.GetHeight())
set.KV = append(set.KV, &types.KeyValue{setKey, types.Encode(historityCertdata)})
set.KV = append(set.KV, &types.KeyValue{
Key: setKey,
Value: types.Encode(historityCertdata),
})
return &set, nil
}
// ExecLocal_Normal 非证书变更交易执行
func (c *Cert) ExecLocal_Normal(payload *ct.CertNormal, tx *types.Transaction, receiptData *types.ReceiptData, index int) (*types.LocalDBSet, error) {
if !authority.IsAuthEnable {
clog.Error("Authority is not available. Please check the authority config or authority initialize error logs.")
......
......@@ -5,7 +5,9 @@
package types
var (
// CertX cert执行器名
CertX = "cert"
// ExecerCert cert执行器字节
ExecerCert = []byte(CertX)
actionName = map[string]int32{
"New": CertActionNew,
......
......@@ -7,8 +7,12 @@ package types
import "errors"
var (
// ErrValidateCertFailed cert校验失败
ErrValidateCertFailed = errors.New("ErrValidateCertFailed")
// ErrGetHistoryCertData 获取证书错误
ErrGetHistoryCertData = errors.New("ErrGetHistoryCertData")
// ErrUnknowAuthSignType 无效签名类型
ErrUnknowAuthSignType = errors.New("ErrUnknowAuthSignType")
// ErrInitializeAuthority 初始化校验器失败
ErrInitializeAuthority = errors.New("ErrInitializeAuthority")
)
......@@ -12,10 +12,8 @@ const (
CertActionUpdate = 2
CertActionNormal = 3
SignNameAuthECDSA = "auth_ecdsa"
AUTH_ECDSA = 257
SignNameAuthSM2 = "auth_sm2"
AUTH_SM2 = 258
AuthECDSA = 257
AuthSM2 = 258
)
func init() {
......@@ -25,28 +23,34 @@ func init() {
types.RegisterDappFork(CertX, "Enable", 0)
}
// CertType cert执行器类型结构
type CertType struct {
types.ExecTypeBase
}
// NewType 新建cert类型结构
func NewType() *CertType {
c := &CertType{}
c.SetChild(c)
return c
}
// GetPayload 获取payload
func (b *CertType) GetPayload() types.Message {
return &CertAction{}
}
// GetName 获取执行器名
func (b *CertType) GetName() string {
return CertX
}
// GetLogMap 获取logmap
func (b *CertType) GetLogMap() map[int64]*types.LogInfo {
return nil
}
// GetTypeMap 获取类型map
func (b *CertType) GetTypeMap() map[string]int32 {
return actionName
}
......@@ -28,6 +28,7 @@ import (
"github.com/spf13/cobra"
)
//EvmCmd 是Evm命令行入口
func EvmCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "evm",
......@@ -36,32 +37,32 @@ func EvmCmd() *cobra.Command {
}
cmd.AddCommand(
CreateContractCmd(),
CallContractCmd(),
EstimateContractCmd(),
CheckContractAddrCmd(),
EvmDebugCmd(),
EvmTransferCmd(),
EvmWithdrawCmd(),
GetEvmBalanceCmd(),
EvmToolsCmd(),
createContractCmd(),
callContractCmd(),
estimateContractCmd(),
checkContractAddrCmd(),
evmDebugCmd(),
evmTransferCmd(),
evmWithdrawCmd(),
getEvmBalanceCmd(),
evmToolsCmd(),
)
return cmd
}
// some tools for evm op
func EvmToolsCmd() *cobra.Command {
func evmToolsCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "tool",
Short: "Some tools for evm op",
}
cmd.AddCommand(EvmToolsAddressCmd())
cmd.AddCommand(evmToolsAddressCmd())
return cmd
}
// transfer address format between ethereum and chain33
func EvmToolsAddressCmd() *cobra.Command {
func evmToolsAddressCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "address",
Short: "Transfer address format between ethereum and local (you should input one address of them)",
......@@ -105,7 +106,7 @@ func transferAddress(cmd *cobra.Command, args []string) {
addr = *addrP
fmt.Println(fmt.Sprintf("Local Address: %v", local))
}
fmt.Println(fmt.Sprintf("Ethereum Address: %v", ChecksumAddr(addr.Bytes())))
fmt.Println(fmt.Sprintf("Ethereum Address: %v", checksumAddr(addr.Bytes())))
return
}
......@@ -113,7 +114,7 @@ func transferAddress(cmd *cobra.Command, args []string) {
}
// get balance of an execer
func GetEvmBalanceCmd() *cobra.Command {
func getEvmBalanceCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "balance",
Short: "Get balance of a evm contract address",
......@@ -161,10 +162,15 @@ func evmBalance(cmd *cobra.Command, args []string) {
ctx.Run()
}
// AccountResult 账户余额查询出来之后进行单位转换
type AccountResult struct {
// 货币
Currency int32 `json:"currency,omitempty"`
// 余额
Balance string `json:"balance,omitempty"`
// 冻结余额
Frozen string `json:"frozen,omitempty"`
// 账户地址
Addr string `json:"addr,omitempty"`
}
......@@ -182,7 +188,7 @@ func parseGetBalanceRes(arg interface{}) (interface{}, error) {
}
// 创建EVM合约
func CreateContractCmd() *cobra.Command {
func createContractCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "create",
Short: "Create a new EVM contract",
......@@ -319,7 +325,7 @@ func createEvmTransferTx(cmd *cobra.Command, caller, execName, expire, rpcLaddr
}
// 调用EVM合约
func CallContractCmd() *cobra.Command {
func callContractCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "call",
Short: "Call the EVM contract",
......@@ -431,7 +437,7 @@ func addEstimateFlags(cmd *cobra.Command) {
}
// 估算合约消耗
func EstimateContractCmd() *cobra.Command {
func estimateContractCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "estimate",
Short: "Estimate the gas cost of calling or creating a contract",
......@@ -442,7 +448,7 @@ func EstimateContractCmd() *cobra.Command {
}
// 检查地址是否为EVM合约
func CheckContractAddrCmd() *cobra.Command {
func checkContractAddrCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "check",
Short: "Check if the address is a valid EVM contract",
......@@ -485,34 +491,34 @@ func checkContractAddr(cmd *cobra.Command, args []string) {
}
// 查询或设置EVM调试开关
func EvmDebugCmd() *cobra.Command {
func evmDebugCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "debug",
Short: "Query or set evm debug status",
}
cmd.AddCommand(
EvmDebugQueryCmd(),
EvmDebugSetCmd(),
EvmDebugClearCmd())
evmDebugQueryCmd(),
evmDebugSetCmd(),
evmDebugClearCmd())
return cmd
}
func EvmDebugQueryCmd() *cobra.Command {
func evmDebugQueryCmd() *cobra.Command {
return &cobra.Command{
Use: "query",
Short: "Query evm debug status",
Run: evmDebugQuery,
}
}
func EvmDebugSetCmd() *cobra.Command {
func evmDebugSetCmd() *cobra.Command {
return &cobra.Command{
Use: "set",
Short: "Set evm debug to ON",
Run: evmDebugSet,
}
}
func EvmDebugClearCmd() *cobra.Command {
func evmDebugClearCmd() *cobra.Command {
return &cobra.Command{
Use: "clear",
Short: "Set evm debug to OFF",
......@@ -521,17 +527,17 @@ func EvmDebugClearCmd() *cobra.Command {
}
func evmDebugQuery(cmd *cobra.Command, args []string) {
evmDebugRpc(cmd, 0)
evmDebugRPC(cmd, 0)
}
func evmDebugSet(cmd *cobra.Command, args []string) {
evmDebugRpc(cmd, 1)
evmDebugRPC(cmd, 1)
}
func evmDebugClear(cmd *cobra.Command, args []string) {
evmDebugRpc(cmd, -1)
evmDebugRPC(cmd, -1)
}
func evmDebugRpc(cmd *cobra.Command, flag int32) {
func evmDebugRPC(cmd *cobra.Command, flag int32) {
var debugReq = evmtypes.EvmDebugReq{Optype: flag}
var debugResp evmtypes.EvmDebugResp
rpcLaddr, _ := cmd.Flags().GetString("rpc_laddr")
......@@ -545,7 +551,7 @@ func evmDebugRpc(cmd *cobra.Command, flag int32) {
}
// 向EVM合约地址转账
func EvmTransferCmd() *cobra.Command {
func evmTransferCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "transfer",
Short: "Transfer to evm contract address",
......@@ -593,7 +599,7 @@ func evmTransfer(cmd *cobra.Command, args []string) {
}
// 向EVM合约地址转账
func EvmWithdrawCmd() *cobra.Command {
func evmWithdrawCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "withdraw",
Short: "Withdraw from evm contract address to caller's balance",
......@@ -662,7 +668,7 @@ func sendQuery(rpcAddr, funcName string, request interface{}, result proto.Messa
}
// 这里实现 EIP55中提及的以太坊地址表示方式(增加Checksum)
func ChecksumAddr(address []byte) string {
func checksumAddr(address []byte) string {
unchecksummed := hex.EncodeToString(address[:])
sha := sha3.NewKeccak256()
sha.Write([]byte(unchecksummed))
......
......@@ -24,7 +24,7 @@ import (
var (
evmDebug = false
// 本合约地址
// EvmAddress 本合约地址
EvmAddress = address.ExecAddress(types.ExecName(evmtypes.ExecutorName))
)
......@@ -35,6 +35,7 @@ func init() {
ety.InitFuncList(types.ListMethod(&EVMExecutor{}))
}
// Init 初始化本合约对象
func Init(name string, sub []byte) {
driverName = name
drivers.Register(driverName, newEVMDriver, types.GetDappFork(driverName, "Enable"))
......@@ -43,6 +44,7 @@ func Init(name string, sub []byte) {
state.InitForkData()
}
// GetName 返回本合约名称
func GetName() string {
return newEVMDriver().GetName()
}
......@@ -53,13 +55,14 @@ func newEVMDriver() drivers.Driver {
return evm
}
// EVM执行器结构
// EVMExecutor EVM执行器结构
type EVMExecutor struct {
drivers.DriverBase
vmCfg *runtime.Config
mStateDB *state.MemoryStateDB
}
// NewEVMExecutor 新创建执行器对象
func NewEVMExecutor() *EVMExecutor {
exec := &EVMExecutor{}
......@@ -70,15 +73,18 @@ func NewEVMExecutor() *EVMExecutor {
return exec
}
// GetFuncMap 获取方法列表
func (evm *EVMExecutor) GetFuncMap() map[string]reflect.Method {
ety := types.LoadExecutorType(driverName)
return ety.GetExecFuncMap()
}
// GetDriverName 获取本合约驱动名称
func (evm *EVMExecutor) GetDriverName() string {
return evmtypes.ExecutorName
}
// Allow 允许哪些交易在本命执行器执行
func (evm *EVMExecutor) Allow(tx *types.Transaction, index int) error {
err := evm.DriverBase.Allow(tx, index)
if err == nil {
......@@ -94,6 +100,7 @@ func (evm *EVMExecutor) Allow(tx *types.Transaction, index int) error {
return types.ErrNotAllow
}
// IsFriend 是否允许对应的KEY
func (evm *EVMExecutor) IsFriend(myexec, writekey []byte, othertx *types.Transaction) bool {
if othertx == nil {
return false
......@@ -115,11 +122,12 @@ func (evm *EVMExecutor) getNewAddr(txHash []byte) common.Address {
return common.NewAddress(txHash)
}
// CheckTx 校验交易
func (evm *EVMExecutor) CheckTx(tx *types.Transaction, index int) error {
return nil
}
//获取运行状态名
// GetActionName 获取运行状态名
func (evm *EVMExecutor) GetActionName(tx *types.Transaction) string {
if bytes.Equal(tx.Execer, []byte(types.ExecName(evmtypes.ExecutorName))) {
return types.ExecName(evmtypes.ExecutorName)
......@@ -127,15 +135,17 @@ func (evm *EVMExecutor) GetActionName(tx *types.Transaction) string {
return tx.ActionName()
}
// GetMStateDB 获取内部状态数据库
func (evm *EVMExecutor) GetMStateDB() *state.MemoryStateDB {
return evm.mStateDB
}
// GetVMConfig 获取VM配置
func (evm *EVMExecutor) GetVMConfig() *runtime.Config {
return evm.vmCfg
}
// 构造一个新的EVM上下文对象
// NewEVMContext 构造一个新的EVM上下文对象
func (evm *EVMExecutor) NewEVMContext(msg *common.Message) runtime.Context {
return runtime.Context{
CanTransfer: CanTransfer,
......
......@@ -18,6 +18,7 @@ import (
evmtypes "github.com/33cn/plugin/plugin/dapp/evm/types"
)
// Exec 本合约执行逻辑
func (evm *EVMExecutor) Exec(tx *types.Transaction, index int) (*types.Receipt, error) {
evm.CheckInit()
// 先转换消息
......@@ -33,12 +34,12 @@ func (evm *EVMExecutor) Exec(tx *types.Transaction, index int) (*types.Receipt,
env := runtime.NewEVM(context, evm.mStateDB, *evm.vmCfg)
isCreate := strings.Compare(msg.To().String(), EvmAddress) == 0
var (
ret = []byte("")
ret []byte
vmerr error
leftOverGas = uint64(0)
leftOverGas uint64
contractAddr common.Address
snapshot = -1
execName = ""
snapshot int
execName string
)
// 为了方便计费,即使合约为新生成,也将地址的初始化放到外面操作
......@@ -76,18 +77,18 @@ func (evm *EVMExecutor) Exec(tx *types.Transaction, index int) (*types.Receipt,
if vmerr != nil {
log.Error("evm contract exec error", "error info", vmerr)
return nil, vmerr
} else {
}
// 计算消耗了多少费用(实际消耗的费用)
usedFee, overflow := common.SafeMul(usedGas, uint64(msg.GasPrice()))
// 费用消耗溢出,执行失败
if overflow || usedFee > uint64(tx.Fee) {
// 如果操作没有回滚,则在这里处理
if curVer != nil && snapshot >= curVer.GetId() && curVer.GetId() > -1 {
if curVer != nil && snapshot >= curVer.GetID() && curVer.GetID() > -1 {
evm.mStateDB.RevertToSnapshot(snapshot)
}
return nil, model.ErrOutOfGas
}
}
// 打印合约中生成的日志
evm.mStateDB.PrintLogs()
......@@ -96,11 +97,10 @@ func (evm *EVMExecutor) Exec(tx *types.Transaction, index int) (*types.Receipt,
return nil, nil
}
// 从状态机中获取数据变更和变更日志
data, logs := evm.mStateDB.GetChangedData(curVer.GetId())
contractReceipt := &evmtypes.ReceiptEVMContract{msg.From().String(), execName, contractAddr.String(), usedGas, ret}
data, logs := evm.mStateDB.GetChangedData(curVer.GetID())
logs = append(logs, &types.ReceiptLog{evmtypes.TyLogCallContract, types.Encode(contractReceipt)})
contractReceipt := &evmtypes.ReceiptEVMContract{Caller: msg.From().String(), ContractName: execName, ContractAddr: contractAddr.String(), UsedGas: usedGas, Ret: ret}
logs = append(logs, &types.ReceiptLog{Ty: evmtypes.TyLogCallContract, Log: types.Encode(contractReceipt)})
logs = append(logs, evm.mStateDB.GetReceiptLogs(contractAddr.String())...)
if types.IsDappFork(evm.GetHeight(), "evm", "ForkEVMKVHash") {
......@@ -125,13 +125,14 @@ func (evm *EVMExecutor) Exec(tx *types.Transaction, index int) (*types.Receipt,
return receipt, nil
}
// CheckInit 检查是否初始化数据库
func (evm *EVMExecutor) CheckInit() {
if evm.mStateDB == nil {
evm.mStateDB = state.NewMemoryStateDB(evm.GetStateDB(), evm.GetLocalDB(), evm.GetCoinsAccount(), evm.GetHeight())
}
}
// 目前的交易中,如果是coins交易,金额是放在payload的,但是合约不行,需要修改Transaction结构
// GetMessage 目前的交易中,如果是coins交易,金额是放在payload的,但是合约不行,需要修改Transaction结构
func (evm *EVMExecutor) GetMessage(tx *types.Transaction) (msg *common.Message, err error) {
var action evmtypes.EVMContractAction
err = types.Decode(tx.Payload, &action)
......@@ -190,7 +191,7 @@ func (evm *EVMExecutor) calcKVHash(addr common.Address, logs []*types.ReceiptLog
if len(hashes) > 0 {
hash := common.ToHash(hashes)
return &types.KeyValue{getDataHashKey(addr), hash.Bytes()}
return &types.KeyValue{Key: getDataHashKey(addr), Value: hash.Bytes()}
}
return nil
}
......
......@@ -9,6 +9,7 @@ import (
evmtypes "github.com/33cn/plugin/plugin/dapp/evm/types"
)
// ExecDelLocal 处理区块回滚
func (evm *EVMExecutor) ExecDelLocal(tx *types.Transaction, receipt *types.ReceiptData, index int) (*types.LocalDBSet, error) {
set, err := evm.DriverBase.ExecDelLocal(tx, receipt, index)
if err != nil {
......
......@@ -11,6 +11,7 @@ import (
evmtypes "github.com/33cn/plugin/plugin/dapp/evm/types"
)
// ExecLocal 处理本地区块新增逻辑
func (evm *EVMExecutor) ExecLocal(tx *types.Transaction, receipt *types.ReceiptData, index int) (*types.LocalDBSet, error) {
set, err := evm.DriverBase.ExecLocal(tx, receipt, index)
if err != nil {
......
......@@ -12,22 +12,22 @@ import (
"github.com/33cn/plugin/plugin/dapp/evm/executor/vm/state"
)
// 检查合约调用账户是否有充足的金额进行转账交易操作
func CanTransfer(db state.StateDB, sender, recipient common.Address, amount uint64) bool {
// CanTransfer 检查合约调用账户是否有充足的金额进行转账交易操作
func CanTransfer(db state.EVMStateDB, sender, recipient common.Address, amount uint64) bool {
return db.CanTransfer(sender.String(), recipient.String(), amount)
}
// 在内存数据库中执行转账操作(只修改内存中的金额)
// Transfer 在内存数据库中执行转账操作(只修改内存中的金额)
// 从外部账户地址到合约账户地址
func Transfer(db state.StateDB, sender, recipient common.Address, amount uint64) bool {
func Transfer(db state.EVMStateDB, sender, recipient common.Address, amount uint64) bool {
return db.Transfer(sender.String(), recipient.String(), amount)
}
// 获取制定高度区块的哈希
// GetHashFn 获取制定高度区块的哈希
func GetHashFn(api client.QueueProtocolAPI) func(blockHeight uint64) common.Hash {
return func(blockHeight uint64) common.Hash {
if api != nil {
reply, err := api.GetBlockHash(&types.ReqInt{int64(blockHeight)})
reply, err := api.GetBlockHash(&types.ReqInt{Height: int64(blockHeight)})
if nil != err {
log.Error("Call GetBlockHash Failed.", err)
}
......
......@@ -17,7 +17,7 @@ import (
evmtypes "github.com/33cn/plugin/plugin/dapp/evm/types"
)
// 检查合约地址是否存在,此操作不会改变任何状态,所以可以直接从statedb查询
// Query_CheckAddrExists 检查合约地址是否存在,此操作不会改变任何状态,所以可以直接从statedb查询
func (evm *EVMExecutor) Query_CheckAddrExists(in *evmtypes.CheckEVMAddrReq) (types.Message, error) {
evm.CheckInit()
addrStr := in.Addr
......@@ -51,7 +51,7 @@ func (evm *EVMExecutor) Query_CheckAddrExists(in *evmtypes.CheckEVMAddrReq) (typ
return ret, nil
}
// 此方法用来估算合约消耗的Gas,不能修改原有执行器的状态数据
// Query_EstimateGas 此方法用来估算合约消耗的Gas,不能修改原有执行器的状态数据
func (evm *EVMExecutor) Query_EstimateGas(in *evmtypes.EstimateEVMGasReq) (types.Message, error) {
evm.CheckInit()
var (
......@@ -80,9 +80,9 @@ func (evm *EVMExecutor) Query_EstimateGas(in *evmtypes.EstimateEVMGasReq) (types
var (
vmerr error
leftOverGas = uint64(0)
leftOverGas uint64
contractAddr common.Address
execName = "estimateGas"
execName string
)
if isCreate {
......@@ -100,7 +100,7 @@ func (evm *EVMExecutor) Query_EstimateGas(in *evmtypes.EstimateEVMGasReq) (types
return result, vmerr
}
// 此方法用来估算合约消耗的Gas,不能修改原有执行器的状态数据
// Query_EvmDebug 此方法用来估算合约消耗的Gas,不能修改原有执行器的状态数据
func (evm *EVMExecutor) Query_EvmDebug(in *evmtypes.EvmDebugReq) (types.Message, error) {
evm.CheckInit()
optype := in.Optype
......
......@@ -23,7 +23,7 @@ func TestCreateContract1(t *testing.T) {
gasLimit := gas
tx := createTx(privKey, deployCode, gas, 10000000)
mdb := buildStateDB(getAddr(privKey).String(), 500000000)
ret, addr, leftGas, err, statedb := createContract(mdb, tx, 0)
ret, addr, leftGas, statedb, err := createContract(mdb, tx, 0)
test := NewTester(t)
test.assertNil(err)
......@@ -33,7 +33,7 @@ func TestCreateContract1(t *testing.T) {
test.assertNotEqualsI(common.Address(addr), common.EmptyAddress())
// 检查返回数据是否正确
test.assertEqualsV(statedb.GetLastSnapshot().GetId(), 0)
test.assertEqualsV(statedb.GetLastSnapshot().GetID(), 0)
}
// 创建合约gas不足
......@@ -46,7 +46,7 @@ func TestCreateContract2(t *testing.T) {
gas := uint64(30)
tx := createTx(privKey, deployCode, gas, 0)
mdb := buildStateDB(getAddr(privKey).String(), 100000000)
ret, _, leftGas, err, _ := createContract(mdb, tx, 0)
ret, _, leftGas, _, err := createContract(mdb, tx, 0)
test := NewTester(t)
......@@ -72,7 +72,7 @@ func TestCreateContract3(t *testing.T) {
gasLimit := gas
tx := createTx(privKey, deployCode, gas, 0)
mdb := buildStateDB(getAddr(privKey).String(), 100000000)
ret, _, leftGas, err, _ := createContract(mdb, tx, 0)
ret, _, leftGas, _, err := createContract(mdb, tx, 0)
test := NewTester(t)
......@@ -98,7 +98,7 @@ func TestCreateContract4(t *testing.T) {
gasLimit := gas
tx := createTx(privKey, deployCode, gas, 0)
mdb := buildStateDB(getAddr(privKey).String(), 100000000)
ret, _, leftGas, err, _ := createContract(mdb, tx, 50)
ret, _, leftGas, _, err := createContract(mdb, tx, 50)
test := NewTester(t)
......
......@@ -144,13 +144,12 @@ func runCase(tt *testing.T, c VMCase, file string) {
// 合约执行出错的情况下,判断错误是否相同,如果相同,则返回,不判断post
if len(c.err) > 0 && c.err == err.Error() {
return
} else {
}
// 非意料情况下的出错,视为错误
tt.Errorf("test case:%s, failed:%s", c.name, err)
tt.Fail()
return
}
}
// 4 检查执行结果 post (注意,这里不检查Gas具体扣费数额,因为计费规则不一样,值检查执行结果是否正确)
t := NewTester(tt)
// 4.1 返回结果
......
......@@ -79,11 +79,11 @@ func scanTestData(basePath string) {
// 检查两个文件是否都存在
if _, err := os.Stat(keyFile); os.IsNotExist(err) {
fmt.Errorf("test template file:%s, not exists!", keyFile)
fmt.Println(fmt.Errorf("test template file:%s, not exists", keyFile))
return nil
}
if _, err := os.Stat(dataFile); os.IsNotExist(err) {
fmt.Errorf("test data file:%s, not exists!", dataFile)
fmt.Println(fmt.Errorf("test data file:%s, not exists", dataFile))
return nil
}
testmap[keyFile] = dataFile
......
......@@ -4,19 +4,21 @@
package tests
// VMCase 一个测试用例
type VMCase struct {
name string
env EnvJson
exec ExecJson
env EnvJSON
exec ExecJSON
gas int64
logs string
out string
err string
pre map[string]AccountJson
post map[string]AccountJson
pre map[string]AccountJSON
post map[string]AccountJSON
}
type EnvJson struct {
// EnvJSON 上下文信息
type EnvJSON struct {
currentCoinbase string
currentDifficulty int64
currentGasLimit int64
......@@ -24,7 +26,8 @@ type EnvJson struct {
currentTimestamp int64
}
type ExecJson struct {
// ExecJSON 调用信息
type ExecJSON struct {
address string
caller string
code string
......@@ -35,7 +38,8 @@ type ExecJson struct {
value int64
}
type AccountJson struct {
// AccountJSON 账户信息
type AccountJSON struct {
balance int64
code string
nonce int64
......
......@@ -10,10 +10,12 @@ import (
"github.com/33cn/plugin/plugin/dapp/evm/executor/vm/common"
)
// Tester 测试执行对象
type Tester struct {
t *testing.T
}
// NewTester 新创建测试执行对象
func NewTester(t *testing.T) *Tester {
return &Tester{t: t}
}
......
......@@ -68,9 +68,9 @@ func parseVMCase(data interface{}, ut *VMCase) {
}
}
func parseEnv(data interface{}) EnvJson {
func parseEnv(data interface{}) EnvJSON {
m := data.(map[string]interface{})
ut := EnvJson{}
ut := EnvJSON{}
for k, v := range m {
switch k {
case "currentCoinbase":
......@@ -90,9 +90,9 @@ func parseEnv(data interface{}) EnvJson {
return ut
}
func parseExec(data interface{}) ExecJson {
func parseExec(data interface{}) ExecJSON {
m := data.(map[string]interface{})
ut := ExecJson{}
ut := ExecJSON{}
for k, v := range m {
switch k {
case "address":
......@@ -118,8 +118,8 @@ func parseExec(data interface{}) ExecJson {
return ut
}
func parseAccount(data interface{}) map[string]AccountJson {
ret := make(map[string]AccountJson)
func parseAccount(data interface{}) map[string]AccountJSON {
ret := make(map[string]AccountJSON)
m := data.(map[string]interface{})
for k, v := range m {
ret[unpre(k)] = parseAccount2(v)
......@@ -127,9 +127,9 @@ func parseAccount(data interface{}) map[string]AccountJson {
return ret
}
func parseAccount2(data interface{}) AccountJson {
func parseAccount2(data interface{}) AccountJSON {
m := data.(map[string]interface{})
ut := AccountJson{}
ut := AccountJSON{}
for k, v := range m {
switch k {
case "balance":
......@@ -215,7 +215,7 @@ func addAccount(mdb *db.GoMemDB, execAddr string, acc1 *types.Account) {
}
}
func addContractAccount(db *state.MemoryStateDB, mdb *db.GoMemDB, addr string, a AccountJson, creator string) {
func addContractAccount(db *state.MemoryStateDB, mdb *db.GoMemDB, addr string, a AccountJSON, creator string) {
acc := state.NewContractAccount(addr, db)
acc.SetCreator(creator)
code, err := hex.DecodeString(a.code)
......@@ -247,7 +247,7 @@ func buildStateDB(addr string, balance int64) *db.GoMemDB {
return mdb
}
func createContract(mdb *db.GoMemDB, tx types.Transaction, maxCodeSize int) (ret []byte, contractAddr common.Address, leftOverGas uint64, err error, statedb *state.MemoryStateDB) {
func createContract(mdb *db.GoMemDB, tx types.Transaction, maxCodeSize int) (ret []byte, contractAddr common.Address, leftOverGas uint64, statedb *state.MemoryStateDB, err error) {
inst := evm.NewEVMExecutor()
inst.CheckInit()
msg, _ := inst.GetMessage(&tx)
......@@ -273,5 +273,5 @@ func createContract(mdb *db.GoMemDB, tx types.Transaction, maxCodeSize int) (ret
addr := *crypto2.RandomContractAddress()
ret, _, leftGas, err := env.Create(runtime.AccountRef(msg.From()), addr, msg.Data(), msg.GasLimit(), fmt.Sprintf("%s%s", evmtypes.EvmPrefix, common.BytesToHash(tx.Hash()).Hex()), "")
return ret, addr, leftGas, err, statedb
return ret, addr, leftGas, statedb, err
}
......@@ -13,37 +13,43 @@ import (
evmtypes "github.com/33cn/plugin/plugin/dapp/evm/types"
)
// 封装地址结构体,并提供各种常用操作封装
// Address 封装地址结构体,并提供各种常用操作封装
// 这里封装的操作主要是为了提供Address<->big.Int, Address<->[]byte 之间的互相转换
// 并且转换的核心是使用地址对象中的Hash160元素,因为在EVM中地址固定为[20]byte,超出此范围的地址无法正确解释执行
type Address struct {
addr *address.Address
}
// String 字符串结构
func (a Address) String() string { return a.addr.String() }
// Bytes 字节数组
func (a Address) Bytes() []byte {
return a.addr.Hash160[:]
}
// Big 大数字
func (a Address) Big() *big.Int {
ret := new(big.Int).SetBytes(a.Bytes())
return ret
}
// txHash生成EVM合约地址
// NewAddress xHash生成EVM合约地址
func NewAddress(txHash []byte) Address {
execAddr := address.GetExecAddress(types.ExecName(evmtypes.EvmPrefix) + BytesToHash(txHash).Hex())
return Address{addr: execAddr}
}
// ExecAddress 返回合约地址
func ExecAddress(execName string) Address {
execAddr := address.GetExecAddress(execName)
return Address{addr: execAddr}
}
// Hash 计算地址哈希
func (a Address) Hash() Hash { return ToHash(a.Bytes()) }
// BytesToAddress 字节向地址转换
func BytesToAddress(b []byte) Address {
a := new(address.Address)
a.Version = 0
......@@ -51,6 +57,7 @@ func BytesToAddress(b []byte) Address {
return Address{addr: a}
}
// StringToAddress 字符串转换为地址
func StringToAddress(s string) *Address {
addr, err := address.NewAddrFromString(s)
if err != nil {
......@@ -70,6 +77,7 @@ func bigBytes(b *big.Int) (out [20]byte) {
return
}
// BigToAddress 大数字转换为地址
func BigToAddress(b *big.Int) Address {
a := new(address.Address)
a.Version = 0
......@@ -77,4 +85,5 @@ func BigToAddress(b *big.Int) Address {
return Address{addr: a}
}
// EmptyAddress 返回空地址
func EmptyAddress() Address { return BytesToAddress([]byte{0}) }
......@@ -11,28 +11,34 @@ import (
// 常用的大整数常量定义
var (
// Big0 大数字0
Big0 = big.NewInt(0)
// Big1 大数字1
Big1 = big.NewInt(1)
// Big32 大数字32
Big32 = big.NewInt(32)
// Big256 大数字256
Big256 = big.NewInt(256)
// Big257 大数字257
Big257 = big.NewInt(257)
)
// 2的各种常用取幂结果
var (
// TT255 2的255次幂
TT255 = BigPow(2, 255)
tt256 = BigPow(2, 256)
tt256m1 = new(big.Int).Sub(tt256, big.NewInt(1))
)
const (
// 一个big.Word类型取值占用多少个位
// WordBits 一个big.Word类型取值占用多少个位
WordBits = 32 << (uint64(^big.Word(0)) >> 63)
// 一个big.Word类型取值占用多少个字节
// WordBytes 一个big.Word类型取值占用多少个字节
WordBytes = WordBits / 8
)
// 返回两者之中的较大值
// BigMax 返回两者之中的较大值
func BigMax(x, y *big.Int) *big.Int {
if x.Cmp(y) < 0 {
return y
......@@ -40,7 +46,7 @@ func BigMax(x, y *big.Int) *big.Int {
return x
}
// 返回两者之中的较小值
// BigMin 返回两者之中的较小值
func BigMin(x, y *big.Int) *big.Int {
if x.Cmp(y) > 0 {
return y
......@@ -48,13 +54,13 @@ func BigMin(x, y *big.Int) *big.Int {
return x
}
// 返回a的b次幂
// BigPow 返回a的b次幂
func BigPow(a, b int64) *big.Int {
r := big.NewInt(a)
return r.Exp(r, big.NewInt(b), nil)
}
// 求补
// U256 求补
func U256(x *big.Int) *big.Int {
return x.And(x, tt256m1)
}
......@@ -68,12 +74,11 @@ func U256(x *big.Int) *big.Int {
func S256(x *big.Int) *big.Int {
if x.Cmp(TT255) < 0 {
return x
} else {
return new(big.Int).Sub(x, tt256)
}
return new(big.Int).Sub(x, tt256)
}
// 指数函数,可以指定底数,结果被截断为256位长度
// Exp 指数函数,可以指定底数,结果被截断为256位长度
func Exp(base, exponent *big.Int) *big.Int {
result := big.NewInt(1)
......@@ -89,7 +94,7 @@ func Exp(base, exponent *big.Int) *big.Int {
return result
}
// big.Int以小端编码时,第n个位置的字节取值
// Byte big.Int以小端编码时,第n个位置的字节取值
// 例如: bigint '5', padlength 32, n=31 => 5
func Byte(bigint *big.Int, padlength, n int) byte {
if n >= padlength {
......@@ -117,17 +122,7 @@ func bigEndianByteAt(bigint *big.Int, n int) byte {
return byte(word >> shift)
}
// 以大端方式将big.Int编码为字节数组,结果数组长度为n
func PaddedBigBytes(bigint *big.Int, n int) []byte {
if bigint.BitLen()/8 >= n {
return bigint.Bytes()
}
ret := make([]byte, n)
ReadBits(bigint, ret)
return ret
}
// 以大端方式将big.Int编码为字节数组
// ReadBits 以大端方式将big.Int编码为字节数组
func ReadBits(bigint *big.Int, buf []byte) {
i := len(buf)
for _, d := range bigint.Bits() {
......@@ -139,17 +134,12 @@ func ReadBits(bigint *big.Int, buf []byte) {
}
}
// 减法运算,返回是否溢出
func SafeSub(x, y uint64) (uint64, bool) {
return x - y, x < y
}
// 加法运算,返回是否溢出
// SafeAdd 加法运算,返回是否溢出
func SafeAdd(x, y uint64) (uint64, bool) {
return x + y, y > math.MaxUint64-x
}
// 乘法运算,返回是否溢出
// SafeMul 乘法运算,返回是否溢出
func SafeMul(x, y uint64) (uint64, bool) {
if x == 0 || y == 0 {
return 0, false
......@@ -157,6 +147,7 @@ func SafeMul(x, y uint64) (uint64, bool) {
return x * y, y > math.MaxUint64/x
}
// Zero 检查数字是否为0
func Zero(value *big.Int) bool {
if value == nil || value.Sign() == 0 {
return true
......
......@@ -9,7 +9,7 @@ import (
"sort"
)
// 右填充字节数组
// RightPadBytes 右填充字节数组
func RightPadBytes(slice []byte, l int) []byte {
if l <= len(slice) {
return slice
......@@ -21,7 +21,7 @@ func RightPadBytes(slice []byte, l int) []byte {
return padded
}
// 左填充字节数组
// LeftPadBytes 左填充字节数组
func LeftPadBytes(slice []byte, l int) []byte {
if l <= len(slice) {
return slice
......@@ -33,7 +33,7 @@ func LeftPadBytes(slice []byte, l int) []byte {
return padded
}
// 十六进制的字符串转换为字节数组
// FromHex 十六进制的字符串转换为字节数组
func FromHex(s string) []byte {
if len(s) > 1 {
if s[0:2] == "0x" || s[0:2] == "0X" {
......@@ -46,13 +46,13 @@ func FromHex(s string) []byte {
return Hex2Bytes(s)
}
// 十六进制字符串转换为字节数组
// Hex2Bytes 十六进制字符串转换为字节数组
func Hex2Bytes(str string) []byte {
h, _ := hex.DecodeString(str)
return h
}
// 将字节数组转换为16进制的字符串表示
// Bytes2Hex 将字节数组转换为16进制的字符串表示
func Bytes2Hex(b []byte) string {
enc := make([]byte, len(b)*2+2)
copy(enc, "0x")
......@@ -60,7 +60,7 @@ func Bytes2Hex(b []byte) string {
return string(enc)
}
// 将字节数组转换为16进制的字符串表示
// Bytes2HexTrim 将字节数组转换为16进制的字符串表示
// 并且将前面多余的0去除
func Bytes2HexTrim(b []byte) string {
// 获取字节数组中第一个非零字节位置
......
......@@ -9,7 +9,7 @@ import (
"math/big"
)
// 返回从开始位置制定长度的数据
// GetData 返回从开始位置制定长度的数据
// 如果源数据不足,则剩余位置用零填充
func GetData(data []byte, start uint64, size uint64) []byte {
length := uint64(len(data))
......@@ -23,7 +23,7 @@ func GetData(data []byte, start uint64, size uint64) []byte {
return RightPadBytes(data[start:end], int(size))
}
// 返回从开始位置制定长度的数据
// GetDataBig 返回从开始位置制定长度的数据
// 如果源数据不足,则剩余位置用零填充
func GetDataBig(data []byte, start *big.Int, size *big.Int) []byte {
dlen := big.NewInt(int64(len(data)))
......@@ -33,12 +33,12 @@ func GetDataBig(data []byte, start *big.Int, size *big.Int) []byte {
return RightPadBytes(data[s.Uint64():e.Uint64()], int(size.Uint64()))
}
// 将大整数转换为uint64,并判断是否溢出
// BigUint64 将大整数转换为uint64,并判断是否溢出
func BigUint64(v *big.Int) (uint64, bool) {
return v.Uint64(), v.BitLen() > 64
}
// 计算制定字节长度所对应的字长度(一个字,对应32个字节,也就是256位)
// ToWordSize 计算制定字节长度所对应的字长度(一个字,对应32个字节,也就是256位)
// 如果长度不足一个字长,则补足
// EVM在内存中存储时的最小单位是字长(256位),而不是字节
func ToWordSize(size uint64) uint64 {
......@@ -49,7 +49,7 @@ func ToWordSize(size uint64) uint64 {
return (size + 31) / 32
}
// 判断字节数组内容是否全为零
// AllZero 判断字节数组内容是否全为零
func AllZero(b []byte) bool {
for _, byte := range b {
if byte != 0 {
......
......@@ -20,7 +20,7 @@ func bigFromBase10(s string) *big.Int {
// u is the BN parameter that determines the prime: 1868033³.
var u = bigFromBase10("4965661367192848881")
// p is a prime over which we form a basic field: 36u⁴+36u³+24u²+6u+1.
// P is a prime over which we form a basic field: 36u⁴+36u³+24u²+6u+1.
var P = bigFromBase10("21888242871839275222246405745257275088696311157297823662689037894645226208583")
// Order is the number of elements in both G₁ and G₂: 36u⁴+36u³+18u²+6u+1.
......
......@@ -190,14 +190,14 @@ func (c *curvePoint) Double(a *curvePoint, pool *bnPool) {
A.Mod(A, P)
B := pool.Get().Mul(a.y, a.y)
B.Mod(B, P)
C_ := pool.Get().Mul(B, B)
C_.Mod(C_, P)
C := pool.Get().Mul(B, B)
C.Mod(C, P)
t := pool.Get().Add(a.x, B)
t2 := pool.Get().Mul(t, t)
t2.Mod(t2, P)
t.Sub(t2, A)
t2.Sub(t, C_)
t2.Sub(t, C)
d := pool.Get().Add(t2, t2)
t.Add(A, A)
e := pool.Get().Add(t, A)
......@@ -207,7 +207,7 @@ func (c *curvePoint) Double(a *curvePoint, pool *bnPool) {
t.Add(d, d)
c.x.Sub(f, t)
t.Add(C_, C_)
t.Add(C, C)
t2.Add(t, t)
t.Add(t2, t2)
c.y.Sub(d, c.x)
......@@ -221,7 +221,7 @@ func (c *curvePoint) Double(a *curvePoint, pool *bnPool) {
pool.Put(A)
pool.Put(B)
pool.Put(C_)
pool.Put(C)
pool.Put(t)
pool.Put(t2)
pool.Put(d)
......
......@@ -134,7 +134,7 @@ func (e *gfP12) MulScalar(a *gfP12, b *gfP6, pool *bnPool) *gfP12 {
return e
}
func (c *gfP12) Exp(a *gfP12, power *big.Int, pool *bnPool) *gfP12 {
func (e *gfP12) Exp(a *gfP12, power *big.Int, pool *bnPool) *gfP12 {
sum := newGFp12(pool)
sum.SetOne()
t := newGFp12(pool)
......@@ -148,12 +148,12 @@ func (c *gfP12) Exp(a *gfP12, power *big.Int, pool *bnPool) *gfP12 {
}
}
c.Set(sum)
e.Set(sum)
sum.Put(pool)
t.Put(pool)
return c
return e
}
func (e *gfP12) Square(a *gfP12, pool *bnPool) *gfP12 {
......
......@@ -106,7 +106,7 @@ func (e *gfP2) Double(a *gfP2) *gfP2 {
return e
}
func (c *gfP2) Exp(a *gfP2, power *big.Int, pool *bnPool) *gfP2 {
func (e *gfP2) Exp(a *gfP2, power *big.Int, pool *bnPool) *gfP2 {
sum := newGFp2(pool)
sum.SetOne()
t := newGFp2(pool)
......@@ -120,12 +120,12 @@ func (c *gfP2) Exp(a *gfP2, power *big.Int, pool *bnPool) *gfP2 {
}
}
c.Set(sum)
e.Set(sum)
sum.Put(pool)
t.Put(pool)
return c
return e
}
// See "Multiplication and Squaring in Pairing-Friendly Fields",
......
......@@ -270,13 +270,13 @@ func (e *gfP6) Invert(a *gfP6, pool *bnPool) *gfP6 {
t1.Mul(a.y, a.z, pool)
B.Sub(B, t1)
C_ := newGFp2(pool)
C_.Square(a.y, pool)
C := newGFp2(pool)
C.Square(a.y, pool)
t1.Mul(a.x, a.z, pool)
C_.Sub(C_, t1)
C.Sub(C, t1)
F := newGFp2(pool)
F.Mul(C_, a.y, pool)
F.Mul(C, a.y, pool)
F.MulXi(F, pool)
t1.Mul(A, a.z, pool)
F.Add(F, t1)
......@@ -286,14 +286,14 @@ func (e *gfP6) Invert(a *gfP6, pool *bnPool) *gfP6 {
F.Invert(F, pool)
e.x.Mul(C_, F, pool)
e.x.Mul(C, F, pool)
e.y.Mul(B, F, pool)
e.z.Mul(A, F, pool)
t1.Put(pool)
A.Put(pool)
B.Put(pool)
C_.Put(pool)
C.Put(pool)
F.Put(pool)
return e
......
......@@ -92,12 +92,12 @@ func lineFunctionDouble(r *twistPoint, q *curvePoint, pool *bnPool) (a, b, c *gf
A := newGFp2(pool).Square(r.x, pool)
B := newGFp2(pool).Square(r.y, pool)
C_ := newGFp2(pool).Square(B, pool)
C := newGFp2(pool).Square(B, pool)
D := newGFp2(pool).Add(r.x, B)
D.Square(D, pool)
D.Sub(D, A)
D.Sub(D, C_)
D.Sub(D, C)
D.Add(D, D)
E := newGFp2(pool).Add(A, A)
......@@ -116,7 +116,7 @@ func lineFunctionDouble(r *twistPoint, q *curvePoint, pool *bnPool) (a, b, c *gf
rOut.y.Sub(D, rOut.x)
rOut.y.Mul(rOut.y, E, pool)
t := newGFp2(pool).Add(C_, C_)
t := newGFp2(pool).Add(C, C)
t.Add(t, t)
t.Add(t, t)
rOut.y.Sub(rOut.y, t)
......@@ -146,7 +146,7 @@ func lineFunctionDouble(r *twistPoint, q *curvePoint, pool *bnPool) (a, b, c *gf
A.Put(pool)
B.Put(pool)
C_.Put(pool)
C.Put(pool)
D.Put(pool)
E.Put(pool)
G.Put(pool)
......
......@@ -175,12 +175,12 @@ func (c *twistPoint) Double(a *twistPoint, pool *bnPool) {
// See http://hyperelliptic.org/EFD/g1p/auto-code/shortw/jacobian-0/doubling/dbl-2009-l.op3
A := newGFp2(pool).Square(a.x, pool)
B := newGFp2(pool).Square(a.y, pool)
C_ := newGFp2(pool).Square(B, pool)
C := newGFp2(pool).Square(B, pool)
t := newGFp2(pool).Add(a.x, B)
t2 := newGFp2(pool).Square(t, pool)
t.Sub(t2, A)
t2.Sub(t, C_)
t2.Sub(t, C)
d := newGFp2(pool).Add(t2, t2)
t.Add(A, A)
e := newGFp2(pool).Add(t, A)
......@@ -189,7 +189,7 @@ func (c *twistPoint) Double(a *twistPoint, pool *bnPool) {
t.Add(d, d)
c.x.Sub(f, t)
t.Add(C_, C_)
t.Add(C, C)
t2.Add(t, t)
t.Add(t2, t2)
c.y.Sub(d, c.x)
......@@ -201,7 +201,7 @@ func (c *twistPoint) Double(a *twistPoint, pool *bnPool) {
A.Put(pool)
B.Put(pool)
C_.Put(pool)
C.Put(pool)
t.Put(pool)
t2.Put(pool)
d.Put(pool)
......
......@@ -16,7 +16,7 @@ import (
"golang.org/x/crypto/sha3"
)
// 校验签名信息是否正确
// ValidateSignatureValues 校验签名信息是否正确
func ValidateSignatureValues(r, s *big.Int) bool {
if r.Cmp(common.Big1) < 0 || s.Cmp(common.Big1) < 0 {
return false
......@@ -24,7 +24,7 @@ func ValidateSignatureValues(r, s *big.Int) bool {
return true
}
// 根据压缩消息和签名,返回未压缩的公钥信息
// Ecrecover 根据压缩消息和签名,返回未压缩的公钥信息
func Ecrecover(hash, sig []byte) ([]byte, error) {
pub, err := SigToPub(hash, sig)
if err != nil {
......@@ -34,7 +34,7 @@ func Ecrecover(hash, sig []byte) ([]byte, error) {
return bytes, err
}
// 根据签名返回公钥信息
// SigToPub 根据签名返回公钥信息
func SigToPub(hash, sig []byte) (*ecdsa.PublicKey, error) {
btcsig := make([]byte, 65)
btcsig[0] = sig[64] + 27
......@@ -44,7 +44,7 @@ func SigToPub(hash, sig []byte) (*ecdsa.PublicKey, error) {
return (*ecdsa.PublicKey)(pub), err
}
// 随机生成一个新的地址,给新创建的合约地址使用
// RandomContractAddress 随机生成一个新的地址,给新创建的合约地址使用
func RandomContractAddress() *common.Address {
c, err := crypto.New(types.GetSignName("", types.SECP256K1))
if err != nil {
......
......@@ -11,17 +11,26 @@ import (
)
const (
// HashLength 哈希长度
HashLength = 32
)
// Hash 重定义哈希类型
type Hash common.Hash
// Str 字符串形式
func (h Hash) Str() string { return string(h[:]) }
// Bytes 二进制形式
func (h Hash) Bytes() []byte { return h[:] }
// Big 大数字形式
func (h Hash) Big() *big.Int { return new(big.Int).SetBytes(h[:]) }
// Hex 十六进制形式
func (h Hash) Hex() string { return Bytes2Hex(h[:]) }
// 设置哈希中的字节值,如果字节数组长度超过哈希长度,则被截断,只保留后面的部分
// SetBytes 设置哈希中的字节值,如果字节数组长度超过哈希长度,则被截断,只保留后面的部分
func (h *Hash) SetBytes(b []byte) {
if len(b) > len(h) {
b = b[len(b)-HashLength:]
......@@ -30,20 +39,17 @@ func (h *Hash) SetBytes(b []byte) {
copy(h[HashLength-len(b):], b)
}
// BigToHash 大数字转换为哈希
func BigToHash(b *big.Int) Hash {
return Hash(common.BigToHash(b))
}
// 将[]byte直接当做哈希处理
// BytesToHash 将[]byte直接当做哈希处理
func BytesToHash(b []byte) Hash {
return Hash(common.BytesToHash(b))
}
func EmptyHash(h Hash) bool {
return h == Hash{}
}
// 将[]byte经过哈希计算后转化为哈希对象
// ToHash 将[]byte经过哈希计算后转化为哈希对象
func ToHash(data []byte) Hash {
return BytesToHash(common.Sha256(data))
}
......@@ -4,7 +4,7 @@
package common
// 合约交易消息模型
// Message 合约交易消息模型
// 在EVM执行器中传递此消息,由外部Tx等价构造
type Message struct {
to *Address
......@@ -17,6 +17,7 @@ type Message struct {
data []byte
}
// NewMessage 新建消息结构
func NewMessage(from Address, to *Address, nonce int64, amount uint64, gasLimit uint64, gasPrice uint32, data []byte, alias string) *Message {
return &Message{
from: from,
......@@ -30,11 +31,26 @@ func NewMessage(from Address, to *Address, nonce int64, amount uint64, gasLimit
}
}
// From 来源
func (m Message) From() Address { return m.from }
// To 目的地址
func (m Message) To() *Address { return m.to }
// GasPrice Gas价格
func (m Message) GasPrice() uint32 { return m.gasPrice }
// Value 转账金额
func (m Message) Value() uint64 { return m.amount }
// Nonce nonce值
func (m Message) Nonce() int64 { return m.nonce }
// Data 附带数据
func (m Message) Data() []byte { return m.data }
// GasLimit Gas限制
func (m Message) GasLimit() uint64 { return m.gasLimit }
// Alias 合约别名
func (m Message) Alias() string { return m.alias }
......@@ -11,20 +11,26 @@ import (
)
const (
// GasQuickStep 计费
GasQuickStep uint64 = 2
// GasFastestStep 计费
GasFastestStep uint64 = 3
// GasFastStep 计费
GasFastStep uint64 = 5
// GasMidStep 计费
GasMidStep uint64 = 8
// GasSlowStep 计费
GasSlowStep uint64 = 10
// GasExtStep 计费
GasExtStep uint64 = 20
// 允许开辟的最大内存空间大小,超过此值时将会导致溢出
// MaxNewMemSize 允许开辟的最大内存空间大小,超过此值时将会导致溢出
MaxNewMemSize uint64 = 0xffffffffe0
)
// 返回真实花费的Gas
// availableGas - base * 63 / 64.
func callGas(gasTable GasTable, availableGas, base uint64, callCost *big.Int) (uint64, error) {
func callGas(gasTable Table, availableGas, base uint64, callCost *big.Int) (uint64, error) {
if availableGas == callCost.Uint64() {
availableGas = availableGas - base
gas := availableGas - availableGas/64
......
......@@ -12,15 +12,17 @@ import (
// 整数池允许的最大长度
const poolLimit = 256
// big.Int组成的内存池
// IntPool big.Int组成的内存池
type IntPool struct {
pool *Stack
}
// NewIntPool 创建新的内存池
func NewIntPool() *IntPool {
return &IntPool{pool: NewStack()}
}
// Get 取数据
func (p *IntPool) Get() *big.Int {
if p.pool.Len() > 0 {
return p.pool.Pop()
......@@ -28,6 +30,7 @@ func (p *IntPool) Get() *big.Int {
return new(big.Int)
}
// Put 存数据
func (p *IntPool) Put(is ...*big.Int) {
if len(p.pool.Items) > poolLimit {
return
......@@ -38,7 +41,7 @@ func (p *IntPool) Put(is ...*big.Int) {
}
}
// 返回一个零值的big.Int
// GetZero 返回一个零值的big.Int
func (p *IntPool) GetZero() *big.Int {
if p.pool.Len() > 0 {
return p.pool.Pop().SetUint64(0)
......@@ -49,17 +52,18 @@ func (p *IntPool) GetZero() *big.Int {
// 默认容量
const poolDefaultCap = 25
// 用于管理IntPool的Pool
// IntPoolPool 用于管理IntPool的Pool
type IntPoolPool struct {
pools []*IntPool
lock sync.Mutex
}
// PoolOfIntPools 内存缓冲池
var PoolOfIntPools = &IntPoolPool{
pools: make([]*IntPool, 0, poolDefaultCap),
}
// get is looking for an available pool to return.
// Get 返回一个可用的内存池
func (ipp *IntPoolPool) Get() *IntPool {
ipp.lock.Lock()
defer ipp.lock.Unlock()
......@@ -72,7 +76,7 @@ func (ipp *IntPoolPool) Get() *IntPool {
return NewIntPool()
}
// put a pool that has been allocated with get.
// Put 放入一个初始化过的内存池
func (ipp *IntPoolPool) Put(ip *IntPool) {
ipp.lock.Lock()
defer ipp.lock.Unlock()
......
......@@ -12,19 +12,20 @@ import (
"github.com/33cn/plugin/plugin/dapp/evm/executor/vm/common"
)
// 内存操作封装,在EVM中使用此对象模拟物理内存
// Memory 内存操作封装,在EVM中使用此对象模拟物理内存
type Memory struct {
// 内存中存储的数据
// Store 内存中存储的数据
Store []byte
// 上次开辟内存消耗的Gas
// LastGasCost 上次开辟内存消耗的Gas
LastGasCost uint64
}
// NewMemory 创建内存对象结构
func NewMemory() *Memory {
return &Memory{}
}
// 设置内存中的值, value => offset:offset + size
// Set 设置内存中的值, value => offset:offset + size
func (m *Memory) Set(offset, size uint64, value []byte) (err error) {
if size > 0 {
// 偏移量+大小一定不会大于内存长度
......@@ -39,7 +40,7 @@ func (m *Memory) Set(offset, size uint64, value []byte) (err error) {
return nil
}
// 从offset开始设置32个字节的内存值,如果值长度不足32个字节,左零值填充
// Set32 从offset开始设置32个字节的内存值,如果值长度不足32个字节,左零值填充
func (m *Memory) Set32(offset uint64, val *big.Int) (err error) {
// 确保长度足够设置值
......@@ -58,14 +59,14 @@ func (m *Memory) Set32(offset uint64, val *big.Int) (err error) {
return nil
}
// 扩充内存到指定大小
// Resize 扩充内存到指定大小
func (m *Memory) Resize(size uint64) {
if uint64(m.Len()) < size {
m.Store = append(m.Store, make([]byte, size-uint64(m.Len()))...)
}
}
// 获取内存中制定偏移量开始的指定长度的数据,返回数据的拷贝而非引用
// Get 获取内存中制定偏移量开始的指定长度的数据,返回数据的拷贝而非引用
func (m *Memory) Get(offset, size int64) (cpy []byte) {
if size == 0 {
return nil
......@@ -81,7 +82,7 @@ func (m *Memory) Get(offset, size int64) (cpy []byte) {
return
}
// 同Get操作,不过这里返回的是数据引用
// GetPtr 同Get操作,不过这里返回的是数据引用
func (m *Memory) GetPtr(offset, size int64) []byte {
if size == 0 {
return nil
......@@ -94,17 +95,17 @@ func (m *Memory) GetPtr(offset, size int64) []byte {
return nil
}
// 返回内存中已开辟空间的大小(以字节计算)
// Len 返回内存中已开辟空间的大小(以字节计算)
func (m *Memory) Len() int {
return len(m.Store)
}
// 返回内存中的原始数据引用
// Data 返回内存中的原始数据引用
func (m *Memory) Data() []byte {
return m.Store
}
// 打印内存中的数据(调试用)
// Print 打印内存中的数据(调试用)
func (m *Memory) Print() {
fmt.Printf("### mem %d bytes ###\n", len(m.Store))
if len(m.Store) > 0 {
......
......@@ -13,46 +13,56 @@ import (
// 本文件中定义各种操作下计算内存大小的逻辑
type (
// 计算所需内存大小
// MemorySizeFunc 计算所需内存大小
MemorySizeFunc func(*Stack) *big.Int
)
// MemorySha3 sha3计算所需内存大小
func MemorySha3(stack *Stack) *big.Int {
return calcMemSize(stack.Back(0), stack.Back(1))
}
//MemoryCallDataCopy callDataCopy所需内存大小
func MemoryCallDataCopy(stack *Stack) *big.Int {
return calcMemSize(stack.Back(0), stack.Back(2))
}
//MemoryReturnDataCopy returnDataCopy所需内存大小
func MemoryReturnDataCopy(stack *Stack) *big.Int {
return calcMemSize(stack.Back(0), stack.Back(2))
}
//MemoryCodeCopy codeCopy所需内存大小
func MemoryCodeCopy(stack *Stack) *big.Int {
return calcMemSize(stack.Back(0), stack.Back(2))
}
//MemoryExtCodeCopy extCodeCopy所需内存大小
func MemoryExtCodeCopy(stack *Stack) *big.Int {
return calcMemSize(stack.Back(1), stack.Back(3))
}
//MemoryMLoad mload所需内存大小
func MemoryMLoad(stack *Stack) *big.Int {
return calcMemSize(stack.Back(0), big.NewInt(32))
}
//MemoryMStore8 mstore8所需内存大小
func MemoryMStore8(stack *Stack) *big.Int {
return calcMemSize(stack.Back(0), big.NewInt(1))
}
//MemoryMStore mstore所需内存大小
func MemoryMStore(stack *Stack) *big.Int {
return calcMemSize(stack.Back(0), big.NewInt(32))
}
//MemoryCreate create所需内存大小
func MemoryCreate(stack *Stack) *big.Int {
return calcMemSize(stack.Back(1), stack.Back(2))
}
//MemoryCall call所需内存大小
func MemoryCall(stack *Stack) *big.Int {
x := calcMemSize(stack.Back(5), stack.Back(6))
y := calcMemSize(stack.Back(3), stack.Back(4))
......@@ -60,6 +70,7 @@ func MemoryCall(stack *Stack) *big.Int {
return common.BigMax(x, y)
}
//MemoryDelegateCall delegateCall所需内存大小
func MemoryDelegateCall(stack *Stack) *big.Int {
x := calcMemSize(stack.Back(4), stack.Back(5))
y := calcMemSize(stack.Back(2), stack.Back(3))
......@@ -67,6 +78,7 @@ func MemoryDelegateCall(stack *Stack) *big.Int {
return common.BigMax(x, y)
}
//MemoryStaticCall staticCall所需内存大小
func MemoryStaticCall(stack *Stack) *big.Int {
x := calcMemSize(stack.Back(4), stack.Back(5))
y := calcMemSize(stack.Back(2), stack.Back(3))
......@@ -74,14 +86,17 @@ func MemoryStaticCall(stack *Stack) *big.Int {
return common.BigMax(x, y)
}
//MemoryReturn return所需内存大小
func MemoryReturn(stack *Stack) *big.Int {
return calcMemSize(stack.Back(0), stack.Back(1))
}
//MemoryRevert revert所需内存大小
func MemoryRevert(stack *Stack) *big.Int {
return calcMemSize(stack.Back(0), stack.Back(1))
}
//MemoryLog log所需内存大小
func MemoryLog(stack *Stack) *big.Int {
mSize, mStart := stack.Back(1), stack.Back(0)
return calcMemSize(mStart, mSize)
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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