diff --git a/.gitignore b/.gitignore
index ec04931d..e49a4707 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,6 +5,7 @@
 #   git config --global core.excludesfile ~/.gitignore_global
 build/bin
 build/_workspace
+build/test_sdk
 
 *.bak
 
diff --git a/.goreleaser.yml b/.goreleaser.yml
index 2f66235e..79ce6918 100644
--- a/.goreleaser.yml
+++ b/.goreleaser.yml
@@ -1,4 +1,19 @@
-# This is an example goreleaser.yaml file with some sane defaults.
+# Copyright 2018 The Fractal Team Authors
+# This file is part of the fractal project.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
 # Make sure to check the documentation at http://goreleaser.com
 builds:
 - binary: ft
@@ -10,15 +25,6 @@ builds:
   goarch:
      - amd64
      - 386
-- binary: ftkey
-  main: ./cmd/ftkey
-  goos:
-     - windows
-     - darwin
-     - linux
-  goarch:
-     - amd64
-     - 386
 - binary: ftfinder
   main: ./cmd/ftfinder
   goos:
diff --git a/Makefile b/Makefile
index a4affb81..30baea3a 100644
--- a/Makefile
+++ b/Makefile
@@ -17,7 +17,7 @@
 SHELL:=/bin/bash
 REPO := $(shell pwd)
 GOFILES_NOVENDOR := $(shell go list -f "{{.Dir}}" ./...)
-PACKAGES_NOVENDOR := $(shell go list ./...)
+PACKAGES_NOVENDOR := $(shell go list ./... | grep -v test)
 WORK_SPACE := ${REPO}/build/_workspace
 FT_DIR :=${WORK_SPACE}/src/github.com/fractalplatform
 TEMP_GOPATH := $(GOPATH)
@@ -50,6 +50,13 @@ fmt:
 	@echo "Correcting any formatting style corrections."
 	@gofmt -l -w ${GOFILES_NOVENDOR}
 
+# vet runs extended compilation checks to find recommendations for
+# suspicious code constructs.
+.PHONY: vet
+vet:
+	@echo "Running go vet."
+	@go vet ${PACKAGES_NOVENDOR}
+
 ### Building project
 
 # Output commit_hash but only if we have the git repo (e.g. not in docker build
@@ -64,7 +71,7 @@ build_workspace:
 
 # build all targets 
 .PHONY: all
-all:check build_workspace build_ft build_ftkey build_ftfinder
+all:check build_workspace build_ft build_ftfinder
 
 # build ft
 .PHONY: build_ft
@@ -72,11 +79,6 @@ build_ft: commit_hash check build_workspace
 	@echo "Building ft."
 	$(call build,ft)
 
-# build ftkey
-.PHONY: build_ftkey
-build_ftkey: commit_hash check build_workspace
-	@echo "Building ftkey."
-	$(call build,ftkey)
 
 # build ftfinder
 .PHONY: build_ftfinder 
@@ -87,7 +89,7 @@ build_ftfinder: commit_hash check build_workspace
 ### Test
 
 .PHONY: test 
-test: build_workspace
+test: all
 	@cd ${FT_DIR}/fractal  && scripts/test.sh
 
 .PHONY: test_win 
@@ -121,13 +123,15 @@ docs: CHANGELOG NOTES
 
 # Tag the current HEAD commit with the current release defined in
 .PHONY: tag_release
-tag_release: test check docs all
+tag_release: test check docs 
 	@scripts/tag_release.sh
 
 .PHONY: release
-release: test check docs all
+release: test check docs 
 	@scripts/is_checkout_dirty.sh || (echo "checkout is dirty so not releasing!" && exit 1)
 	@export GOPATH=${TEMP_GOPATH} && scripts/release.sh
 
-
-
+.PHONY: tmp_release
+tmp_release: test check 
+	@echo "Building and releasing"
+	@export GOPATH=${TEMP_GOPATH} && goreleaser --snapshot --rm-dist 
\ No newline at end of file
diff --git a/accountmanager/account.go b/accountmanager/account.go
index e86c5ee7..9f8931d8 100644
--- a/accountmanager/account.go
+++ b/accountmanager/account.go
@@ -17,8 +17,10 @@
 package accountmanager
 
 import (
+	"fmt"
 	"math/big"
 
+	"github.com/ethereum/go-ethereum/log"
 	"github.com/fractalplatform/fractal/asset"
 	"github.com/fractalplatform/fractal/common"
 	"github.com/fractalplatform/fractal/crypto"
@@ -30,6 +32,17 @@ type AssetBalance struct {
 	Balance *big.Int `json:"balance"`
 }
 
+type recoverActionResult struct {
+	acctAuthors map[common.Name]*accountAuthor
+}
+
+type accountAuthor struct {
+	threshold             uint64
+	updateAuthorThreshold uint64
+	version               uint64
+	indexWeight           map[uint64]uint64
+}
+
 func newAssetBalance(assetID uint64, amount *big.Int) *AssetBalance {
 	ab := AssetBalance{
 		AssetID: assetID,
@@ -41,16 +54,22 @@ func newAssetBalance(assetID uint64, amount *big.Int) *AssetBalance {
 //Account account object
 type Account struct {
 	//LastTime *big.Int
-	AcctName    common.Name   `json:"accountName"`
-	Founder     common.Name   `json:"founder"`
-	ChargeRatio uint64        `json:"chargeRatio"`
-	Nonce       uint64        `json:"nonce"`
-	PublicKey   common.PubKey `json:"publicKey"`
-	Code        []byte        `json:"code"`
-	CodeHash    common.Hash   `json:"codeHash"`
-	CodeSize    uint64        `json:"codeSize"`
+	AcctName              common.Name `json:"accountName"`
+	Founder               common.Name `json:"founder"`
+	AccountID             uint64      `json:"accountID"`
+	Number                uint64      `json:"number"`
+	ChargeRatio           uint64      `json:"chargeRatio"`
+	Nonce                 uint64      `json:"nonce"`
+	Code                  []byte      `json:"code"`
+	CodeHash              common.Hash `json:"codeHash"`
+	CodeSize              uint64      `json:"codeSize"`
+	Threshold             uint64      `json:"threshold"`
+	UpdateAuthorThreshold uint64      `json:"updateAuthorThreshold"`
+	AuthorVersion         uint64      `json:"authorVersion"`
 	//sort by asset id asc
 	Balances []*AssetBalance `json:"balances"`
+	//realated account, pubkey and address
+	Authors []*common.Author `json:"authors"`
 	//code Suicide
 	Suicide bool `json:"suicide"`
 	//account destroy
@@ -59,25 +78,40 @@ type Account struct {
 
 // NewAccount create a new account object.
 func NewAccount(accountName common.Name, founderName common.Name, pubkey common.PubKey) (*Account, error) {
-	if !common.IsValidName(accountName.String()) {
+	if !common.IsValidAccountName(accountName.String()) {
 		return nil, ErrAccountNameInvalid
 	}
 
+	auth := common.NewAuthor(pubkey, 1)
 	acctObject := Account{
-		AcctName:    accountName,
-		Founder:     founderName,
-		ChargeRatio: 0,
-		PublicKey:   pubkey,
-		Nonce:       0,
-		Balances:    make([]*AssetBalance, 0),
-		Code:        make([]byte, 0),
-		CodeHash:    crypto.Keccak256Hash(nil),
-		Suicide:     false,
-		Destroy:     false,
+		AcctName:              accountName,
+		Founder:               founderName,
+		AccountID:             0,
+		Number:                0,
+		ChargeRatio:           0,
+		Nonce:                 0,
+		Balances:              make([]*AssetBalance, 0),
+		Code:                  make([]byte, 0),
+		CodeHash:              crypto.Keccak256Hash(nil),
+		Threshold:             1,
+		UpdateAuthorThreshold: 1,
+		AuthorVersion:         1,
+		Authors:               []*common.Author{auth},
+		Suicide:               false,
+		Destroy:               false,
 	}
 	return &acctObject, nil
 }
 
+//HaveCode check account have code
+func (a *Account) HaveCode() bool {
+	if a.GetCodeSize() == 0 {
+		return false
+	}
+	return true
+}
+
+// IsEmpty check account empty
 func (a *Account) IsEmpty() bool {
 	if a.GetCodeSize() == 0 && len(a.Balances) == 0 && a.Nonce == 0 {
 		return true
@@ -90,18 +124,42 @@ func (a *Account) GetName() common.Name {
 	return a.AcctName
 }
 
+//GetFounder return account object founder
 func (a *Account) GetFounder() common.Name {
 	return a.Founder
 }
 
+//SetFounder set account object founder
 func (a *Account) SetFounder(f common.Name) {
 	a.Founder = f
 }
 
+//GetAccountID return account object id
+func (a *Account) GetAccountID() uint64 {
+	return a.AccountID
+}
+
+//SetAccountID set account object id
+func (a *Account) SetAccountID(id uint64) {
+	a.AccountID = id
+}
+
+//GetAccountNumber return account object number
+func (a *Account) GetAccountNumber() uint64 {
+	return a.Number
+}
+
+//SetAccountNumber set account object number
+func (a *Account) SetAccountNumber(number uint64) {
+	a.Number = number
+}
+
+//GetChargeRatio return account charge ratio
 func (a *Account) GetChargeRatio() uint64 {
 	return a.ChargeRatio
 }
 
+//SetChargeRatio set account object charge ratio
 func (a *Account) SetChargeRatio(ra uint64) {
 	a.ChargeRatio = ra
 }
@@ -116,14 +174,12 @@ func (a *Account) SetNonce(nonce uint64) {
 	a.Nonce = nonce
 }
 
-//GetPubKey get bugkey
-func (a *Account) GetPubKey() common.PubKey {
-	return a.PublicKey
+func (a *Account) GetAuthorVersion() uint64 {
+	return a.AuthorVersion
 }
 
-//SetPubKey set pub key
-func (a *Account) SetPubKey(pubkey common.PubKey) {
-	a.PublicKey.SetBytes(pubkey.Bytes())
+func (a *Account) SetAuthorVersion() {
+	a.AuthorVersion++
 }
 
 //GetCode get code
@@ -150,6 +206,52 @@ func (a *Account) SetCode(code []byte) error {
 	return nil
 }
 
+func (a *Account) GetThreshold() uint64 {
+	return a.Threshold
+}
+
+func (a *Account) SetThreshold(t uint64) {
+	a.Threshold = t
+}
+
+func (a *Account) SetUpdateAuthorThreshold(t uint64) {
+	a.UpdateAuthorThreshold = t
+}
+
+func (a *Account) GetUpdateAuthorThreshold() uint64 {
+	return a.UpdateAuthorThreshold
+}
+
+func (a *Account) AddAuthor(author *common.Author) error {
+	for _, auth := range a.Authors {
+		if author.Owner.String() == auth.Owner.String() {
+			return fmt.Errorf("%s already exist", auth.Owner.String())
+		}
+	}
+	a.Authors = append(a.Authors, author)
+	return nil
+}
+
+func (a *Account) UpdateAuthor(author *common.Author) error {
+	for _, auth := range a.Authors {
+		if author.Owner.String() == auth.Owner.String() {
+			auth.Weight = author.Weight
+			break
+		}
+	}
+	return nil
+}
+
+func (a *Account) DeleteAuthor(author *common.Author) error {
+	for i, auth := range a.Authors {
+		if author.Owner.String() == auth.Owner.String() {
+			a.Authors = append(a.Authors[:i], a.Authors[i+1:]...)
+			break
+		}
+	}
+	return nil
+}
+
 // GetCodeHash get code hash
 func (a *Account) GetCodeHash() (common.Hash, error) {
 	if len(a.CodeHash) == 0 {
@@ -166,6 +268,7 @@ func (a *Account) GetBalanceByID(assetID uint64) (*big.Int, error) {
 	if p, find := a.binarySearch(assetID); find == true {
 		return a.Balances[p].Balance, nil
 	}
+	log.Debug("get balance by ID", "err", ErrAccountAssetNotExist, "account", a.AcctName, "asset", assetID)
 	return big.NewInt(0), ErrAccountAssetNotExist
 }
 
@@ -310,13 +413,13 @@ func (a *Account) SetSuicide() {
 	a.Suicide = true
 }
 
-//IsDestoryed is destoryed
-func (a *Account) IsDestoryed() bool {
+//IsDestroyed is destroyed
+func (a *Account) IsDestroyed() bool {
 	return a.Destroy
 }
 
-//SetDestory set destory
-func (a *Account) SetDestory() {
+//SetDestroy set destroy
+func (a *Account) SetDestroy() {
 	//just make a sign now
 	a.Destroy = true
 }
diff --git a/accountmanager/account_test.go b/accountmanager/account_test.go
index b79bab4e..1dc903a9 100644
--- a/accountmanager/account_test.go
+++ b/accountmanager/account_test.go
@@ -90,15 +90,14 @@ func TestAccount_GetName(t *testing.T) {
 	}
 	for _, tt := range tests {
 		a := &Account{
-			AcctName:  tt.fields.AcctName,
-			Nonce:     tt.fields.Nonce,
-			PublicKey: tt.fields.PublicKey,
-			Code:      tt.fields.Code,
-			CodeHash:  tt.fields.CodeHash,
-			CodeSize:  tt.fields.CodeSize,
-			Balances:  tt.fields.Balances,
-			Suicide:   tt.fields.Suicide,
-			Destroy:   tt.fields.Destroy,
+			AcctName: tt.fields.AcctName,
+			Nonce:    tt.fields.Nonce,
+			Code:     tt.fields.Code,
+			CodeHash: tt.fields.CodeHash,
+			CodeSize: tt.fields.CodeSize,
+			Balances: tt.fields.Balances,
+			Suicide:  tt.fields.Suicide,
+			Destroy:  tt.fields.Destroy,
 		}
 		if got := a.GetName(); !reflect.DeepEqual(got, tt.want) {
 			t.Errorf("%q. Account.GetName() = %v, want %v", tt.name, got, tt.want)
@@ -127,15 +126,14 @@ func TestAccount_GetNonce(t *testing.T) {
 	}
 	for _, tt := range tests {
 		a := &Account{
-			AcctName:  tt.fields.AcctName,
-			Nonce:     tt.fields.Nonce,
-			PublicKey: tt.fields.PublicKey,
-			Code:      tt.fields.Code,
-			CodeHash:  tt.fields.CodeHash,
-			CodeSize:  tt.fields.CodeSize,
-			Balances:  tt.fields.Balances,
-			Suicide:   tt.fields.Suicide,
-			Destroy:   tt.fields.Destroy,
+			AcctName: tt.fields.AcctName,
+			Nonce:    tt.fields.Nonce,
+			Code:     tt.fields.Code,
+			CodeHash: tt.fields.CodeHash,
+			CodeSize: tt.fields.CodeSize,
+			Balances: tt.fields.Balances,
+			Suicide:  tt.fields.Suicide,
+			Destroy:  tt.fields.Destroy,
 		}
 		if got := a.GetNonce(); got != tt.want {
 			t.Errorf("%q. Account.GetNonce() = %v, want %v", tt.name, got, tt.want)
@@ -167,95 +165,19 @@ func TestAccount_SetNonce(t *testing.T) {
 	}
 	for _, tt := range tests {
 		a := &Account{
-			AcctName:  tt.fields.AcctName,
-			Nonce:     tt.fields.Nonce,
-			PublicKey: tt.fields.PublicKey,
-			Code:      tt.fields.Code,
-			CodeHash:  tt.fields.CodeHash,
-			CodeSize:  tt.fields.CodeSize,
-			Balances:  tt.fields.Balances,
-			Suicide:   tt.fields.Suicide,
-			Destroy:   tt.fields.Destroy,
+			AcctName: tt.fields.AcctName,
+			Nonce:    tt.fields.Nonce,
+			Code:     tt.fields.Code,
+			CodeHash: tt.fields.CodeHash,
+			CodeSize: tt.fields.CodeSize,
+			Balances: tt.fields.Balances,
+			Suicide:  tt.fields.Suicide,
+			Destroy:  tt.fields.Destroy,
 		}
 		a.SetNonce(tt.args.nonce)
 	}
 }
 
-func TestAccount_GetPubKey(t *testing.T) {
-	type fields struct {
-		AcctName  common.Name
-		Nonce     uint64
-		PublicKey common.PubKey
-		Code      []byte
-		CodeHash  common.Hash
-		CodeSize  uint64
-		Balances  []*AssetBalance
-		Suicide   bool
-		Destroy   bool
-	}
-	tests := []struct {
-		name   string
-		fields fields
-		want   common.PubKey
-	}{
-		// TODO: Add test cases.
-	}
-	for _, tt := range tests {
-		a := &Account{
-			AcctName:  tt.fields.AcctName,
-			Nonce:     tt.fields.Nonce,
-			PublicKey: tt.fields.PublicKey,
-			Code:      tt.fields.Code,
-			CodeHash:  tt.fields.CodeHash,
-			CodeSize:  tt.fields.CodeSize,
-			Balances:  tt.fields.Balances,
-			Suicide:   tt.fields.Suicide,
-			Destroy:   tt.fields.Destroy,
-		}
-		if got := a.GetPubKey(); !reflect.DeepEqual(got, tt.want) {
-			t.Errorf("%q. Account.GetPubKey() = %v, want %v", tt.name, got, tt.want)
-		}
-	}
-}
-
-func TestAccount_SetPubKey(t *testing.T) {
-	type fields struct {
-		AcctName  common.Name
-		Nonce     uint64
-		PublicKey common.PubKey
-		Code      []byte
-		CodeHash  common.Hash
-		CodeSize  uint64
-		Balances  []*AssetBalance
-		Suicide   bool
-		Destroy   bool
-	}
-	type args struct {
-		pubkey common.PubKey
-	}
-	tests := []struct {
-		name   string
-		fields fields
-		args   args
-	}{
-		// TODO: Add test cases.
-	}
-	for _, tt := range tests {
-		a := &Account{
-			AcctName:  tt.fields.AcctName,
-			Nonce:     tt.fields.Nonce,
-			PublicKey: tt.fields.PublicKey,
-			Code:      tt.fields.Code,
-			CodeHash:  tt.fields.CodeHash,
-			CodeSize:  tt.fields.CodeSize,
-			Balances:  tt.fields.Balances,
-			Suicide:   tt.fields.Suicide,
-			Destroy:   tt.fields.Destroy,
-		}
-		a.SetPubKey(tt.args.pubkey)
-	}
-}
-
 func TestAccount_GetCode(t *testing.T) {
 	type fields struct {
 		AcctName  common.Name
@@ -278,15 +200,14 @@ func TestAccount_GetCode(t *testing.T) {
 	}
 	for _, tt := range tests {
 		a := &Account{
-			AcctName:  tt.fields.AcctName,
-			Nonce:     tt.fields.Nonce,
-			PublicKey: tt.fields.PublicKey,
-			Code:      tt.fields.Code,
-			CodeHash:  tt.fields.CodeHash,
-			CodeSize:  tt.fields.CodeSize,
-			Balances:  tt.fields.Balances,
-			Suicide:   tt.fields.Suicide,
-			Destroy:   tt.fields.Destroy,
+			AcctName: tt.fields.AcctName,
+			Nonce:    tt.fields.Nonce,
+			Code:     tt.fields.Code,
+			CodeHash: tt.fields.CodeHash,
+			CodeSize: tt.fields.CodeSize,
+			Balances: tt.fields.Balances,
+			Suicide:  tt.fields.Suicide,
+			Destroy:  tt.fields.Destroy,
 		}
 		got, err := a.GetCode()
 		if (err != nil) != tt.wantErr {
@@ -320,15 +241,14 @@ func TestAccount_GetCodeSize(t *testing.T) {
 	}
 	for _, tt := range tests {
 		a := &Account{
-			AcctName:  tt.fields.AcctName,
-			Nonce:     tt.fields.Nonce,
-			PublicKey: tt.fields.PublicKey,
-			Code:      tt.fields.Code,
-			CodeHash:  tt.fields.CodeHash,
-			CodeSize:  tt.fields.CodeSize,
-			Balances:  tt.fields.Balances,
-			Suicide:   tt.fields.Suicide,
-			Destroy:   tt.fields.Destroy,
+			AcctName: tt.fields.AcctName,
+			Nonce:    tt.fields.Nonce,
+			Code:     tt.fields.Code,
+			CodeHash: tt.fields.CodeHash,
+			CodeSize: tt.fields.CodeSize,
+			Balances: tt.fields.Balances,
+			Suicide:  tt.fields.Suicide,
+			Destroy:  tt.fields.Destroy,
 		}
 		if got := a.GetCodeSize(); got != tt.want {
 			t.Errorf("%q. Account.GetCodeSize() = %v, want %v", tt.name, got, tt.want)
@@ -361,15 +281,14 @@ func TestAccount_SetCode(t *testing.T) {
 	}
 	for _, tt := range tests {
 		a := &Account{
-			AcctName:  tt.fields.AcctName,
-			Nonce:     tt.fields.Nonce,
-			PublicKey: tt.fields.PublicKey,
-			Code:      tt.fields.Code,
-			CodeHash:  tt.fields.CodeHash,
-			CodeSize:  tt.fields.CodeSize,
-			Balances:  tt.fields.Balances,
-			Suicide:   tt.fields.Suicide,
-			Destroy:   tt.fields.Destroy,
+			AcctName: tt.fields.AcctName,
+			Nonce:    tt.fields.Nonce,
+			Code:     tt.fields.Code,
+			CodeHash: tt.fields.CodeHash,
+			CodeSize: tt.fields.CodeSize,
+			Balances: tt.fields.Balances,
+			Suicide:  tt.fields.Suicide,
+			Destroy:  tt.fields.Destroy,
 		}
 		if err := a.SetCode(tt.args.code); (err != nil) != tt.wantErr {
 			t.Errorf("%q. Account.SetCode() error = %v, wantErr %v", tt.name, err, tt.wantErr)
@@ -399,15 +318,14 @@ func TestAccount_GetCodeHash(t *testing.T) {
 	}
 	for _, tt := range tests {
 		a := &Account{
-			AcctName:  tt.fields.AcctName,
-			Nonce:     tt.fields.Nonce,
-			PublicKey: tt.fields.PublicKey,
-			Code:      tt.fields.Code,
-			CodeHash:  tt.fields.CodeHash,
-			CodeSize:  tt.fields.CodeSize,
-			Balances:  tt.fields.Balances,
-			Suicide:   tt.fields.Suicide,
-			Destroy:   tt.fields.Destroy,
+			AcctName: tt.fields.AcctName,
+			Nonce:    tt.fields.Nonce,
+			Code:     tt.fields.Code,
+			CodeHash: tt.fields.CodeHash,
+			CodeSize: tt.fields.CodeSize,
+			Balances: tt.fields.Balances,
+			Suicide:  tt.fields.Suicide,
+			Destroy:  tt.fields.Destroy,
 		}
 		got, err := a.GetCodeHash()
 		if (err != nil) != tt.wantErr {
@@ -446,15 +364,14 @@ func TestAccount_GetBalanceByID(t *testing.T) {
 	}
 	for _, tt := range tests {
 		a := &Account{
-			AcctName:  tt.fields.AcctName,
-			Nonce:     tt.fields.Nonce,
-			PublicKey: tt.fields.PublicKey,
-			Code:      tt.fields.Code,
-			CodeHash:  tt.fields.CodeHash,
-			CodeSize:  tt.fields.CodeSize,
-			Balances:  tt.fields.Balances,
-			Suicide:   tt.fields.Suicide,
-			Destroy:   tt.fields.Destroy,
+			AcctName: tt.fields.AcctName,
+			Nonce:    tt.fields.Nonce,
+			Code:     tt.fields.Code,
+			CodeHash: tt.fields.CodeHash,
+			CodeSize: tt.fields.CodeSize,
+			Balances: tt.fields.Balances,
+			Suicide:  tt.fields.Suicide,
+			Destroy:  tt.fields.Destroy,
 		}
 		got, err := a.GetBalanceByID(tt.args.assetID)
 		if (err != nil) != tt.wantErr {
@@ -488,15 +405,14 @@ func TestAccount_GetBalancesList(t *testing.T) {
 	}
 	for _, tt := range tests {
 		a := &Account{
-			AcctName:  tt.fields.AcctName,
-			Nonce:     tt.fields.Nonce,
-			PublicKey: tt.fields.PublicKey,
-			Code:      tt.fields.Code,
-			CodeHash:  tt.fields.CodeHash,
-			CodeSize:  tt.fields.CodeSize,
-			Balances:  tt.fields.Balances,
-			Suicide:   tt.fields.Suicide,
-			Destroy:   tt.fields.Destroy,
+			AcctName: tt.fields.AcctName,
+			Nonce:    tt.fields.Nonce,
+			Code:     tt.fields.Code,
+			CodeHash: tt.fields.CodeHash,
+			CodeSize: tt.fields.CodeSize,
+			Balances: tt.fields.Balances,
+			Suicide:  tt.fields.Suicide,
+			Destroy:  tt.fields.Destroy,
 		}
 		if got := a.GetBalancesList(); !reflect.DeepEqual(got, tt.want) {
 			t.Errorf("%q. Account.GetBalancesList() = %v, want %v", tt.name, got, tt.want)
@@ -526,15 +442,14 @@ func TestAccount_GetAllBalances(t *testing.T) {
 	}
 	for _, tt := range tests {
 		a := &Account{
-			AcctName:  tt.fields.AcctName,
-			Nonce:     tt.fields.Nonce,
-			PublicKey: tt.fields.PublicKey,
-			Code:      tt.fields.Code,
-			CodeHash:  tt.fields.CodeHash,
-			CodeSize:  tt.fields.CodeSize,
-			Balances:  tt.fields.Balances,
-			Suicide:   tt.fields.Suicide,
-			Destroy:   tt.fields.Destroy,
+			AcctName: tt.fields.AcctName,
+			Nonce:    tt.fields.Nonce,
+			Code:     tt.fields.Code,
+			CodeHash: tt.fields.CodeHash,
+			CodeSize: tt.fields.CodeSize,
+			Balances: tt.fields.Balances,
+			Suicide:  tt.fields.Suicide,
+			Destroy:  tt.fields.Destroy,
 		}
 		got, err := a.GetAllBalances()
 		if (err != nil) != tt.wantErr {
@@ -573,15 +488,14 @@ func TestAccount_binarySearch(t *testing.T) {
 	}
 	for _, tt := range tests {
 		a := &Account{
-			AcctName:  tt.fields.AcctName,
-			Nonce:     tt.fields.Nonce,
-			PublicKey: tt.fields.PublicKey,
-			Code:      tt.fields.Code,
-			CodeHash:  tt.fields.CodeHash,
-			CodeSize:  tt.fields.CodeSize,
-			Balances:  tt.fields.Balances,
-			Suicide:   tt.fields.Suicide,
-			Destroy:   tt.fields.Destroy,
+			AcctName: tt.fields.AcctName,
+			Nonce:    tt.fields.Nonce,
+			Code:     tt.fields.Code,
+			CodeHash: tt.fields.CodeHash,
+			CodeSize: tt.fields.CodeSize,
+			Balances: tt.fields.Balances,
+			Suicide:  tt.fields.Suicide,
+			Destroy:  tt.fields.Destroy,
 		}
 		got, got1 := a.binarySearch(tt.args.assetID)
 		if got != tt.want {
@@ -619,15 +533,14 @@ func TestAccount_AddNewAssetByAssetID(t *testing.T) {
 
 	for _, tt := range tests {
 		a := &Account{
-			AcctName:  tt.fields.AcctName,
-			Nonce:     tt.fields.Nonce,
-			PublicKey: tt.fields.PublicKey,
-			Code:      tt.fields.Code,
-			CodeHash:  tt.fields.CodeHash,
-			CodeSize:  tt.fields.CodeSize,
-			Balances:  tt.fields.Balances,
-			Suicide:   tt.fields.Suicide,
-			Destroy:   tt.fields.Destroy,
+			AcctName: tt.fields.AcctName,
+			Nonce:    tt.fields.Nonce,
+			Code:     tt.fields.Code,
+			CodeHash: tt.fields.CodeHash,
+			CodeSize: tt.fields.CodeSize,
+			Balances: tt.fields.Balances,
+			Suicide:  tt.fields.Suicide,
+			Destroy:  tt.fields.Destroy,
 		}
 		a.AddNewAssetByAssetID(tt.args.assetID, tt.args.amount)
 	}
@@ -659,15 +572,14 @@ func TestAccount_SetBalance(t *testing.T) {
 	}
 	for _, tt := range tests {
 		a := &Account{
-			AcctName:  tt.fields.AcctName,
-			Nonce:     tt.fields.Nonce,
-			PublicKey: tt.fields.PublicKey,
-			Code:      tt.fields.Code,
-			CodeHash:  tt.fields.CodeHash,
-			CodeSize:  tt.fields.CodeSize,
-			Balances:  tt.fields.Balances,
-			Suicide:   tt.fields.Suicide,
-			Destroy:   tt.fields.Destroy,
+			AcctName: tt.fields.AcctName,
+			Nonce:    tt.fields.Nonce,
+			Code:     tt.fields.Code,
+			CodeHash: tt.fields.CodeHash,
+			CodeSize: tt.fields.CodeSize,
+			Balances: tt.fields.Balances,
+			Suicide:  tt.fields.Suicide,
+			Destroy:  tt.fields.Destroy,
 		}
 		if err := a.SetBalance(tt.args.assetID, tt.args.amount); (err != nil) != tt.wantErr {
 			t.Errorf("%q. Account.SetBalance() error = %v, wantErr %v", tt.name, err, tt.wantErr)
@@ -701,15 +613,14 @@ func TestAccount_SubBalanceByID(t *testing.T) {
 	}
 	for _, tt := range tests {
 		a := &Account{
-			AcctName:  tt.fields.AcctName,
-			Nonce:     tt.fields.Nonce,
-			PublicKey: tt.fields.PublicKey,
-			Code:      tt.fields.Code,
-			CodeHash:  tt.fields.CodeHash,
-			CodeSize:  tt.fields.CodeSize,
-			Balances:  tt.fields.Balances,
-			Suicide:   tt.fields.Suicide,
-			Destroy:   tt.fields.Destroy,
+			AcctName: tt.fields.AcctName,
+			Nonce:    tt.fields.Nonce,
+			Code:     tt.fields.Code,
+			CodeHash: tt.fields.CodeHash,
+			CodeSize: tt.fields.CodeSize,
+			Balances: tt.fields.Balances,
+			Suicide:  tt.fields.Suicide,
+			Destroy:  tt.fields.Destroy,
 		}
 		if err := a.SubBalanceByID(tt.args.assetID, tt.args.value); (err != nil) != tt.wantErr {
 			t.Errorf("%q. Account.SubBalanceByID() error = %v, wantErr %v", tt.name, err, tt.wantErr)
@@ -743,15 +654,14 @@ func TestAccount_AddBalanceByID(t *testing.T) {
 	}
 	for _, tt := range tests {
 		a := &Account{
-			AcctName:  tt.fields.AcctName,
-			Nonce:     tt.fields.Nonce,
-			PublicKey: tt.fields.PublicKey,
-			Code:      tt.fields.Code,
-			CodeHash:  tt.fields.CodeHash,
-			CodeSize:  tt.fields.CodeSize,
-			Balances:  tt.fields.Balances,
-			Suicide:   tt.fields.Suicide,
-			Destroy:   tt.fields.Destroy,
+			AcctName: tt.fields.AcctName,
+			Nonce:    tt.fields.Nonce,
+			Code:     tt.fields.Code,
+			CodeHash: tt.fields.CodeHash,
+			CodeSize: tt.fields.CodeSize,
+			Balances: tt.fields.Balances,
+			Suicide:  tt.fields.Suicide,
+			Destroy:  tt.fields.Destroy,
 		}
 		if err := a.AddBalanceByID(tt.args.assetID, tt.args.value); (err != nil) != tt.wantErr {
 			t.Errorf("%q. Account.AddBalanceByID() error = %v, wantErr %v", tt.name, err, tt.wantErr)
@@ -785,15 +695,14 @@ func TestAccount_EnoughAccountBalance(t *testing.T) {
 	}
 	for _, tt := range tests {
 		a := &Account{
-			AcctName:  tt.fields.AcctName,
-			Nonce:     tt.fields.Nonce,
-			PublicKey: tt.fields.PublicKey,
-			Code:      tt.fields.Code,
-			CodeHash:  tt.fields.CodeHash,
-			CodeSize:  tt.fields.CodeSize,
-			Balances:  tt.fields.Balances,
-			Suicide:   tt.fields.Suicide,
-			Destroy:   tt.fields.Destroy,
+			AcctName: tt.fields.AcctName,
+			Nonce:    tt.fields.Nonce,
+			Code:     tt.fields.Code,
+			CodeHash: tt.fields.CodeHash,
+			CodeSize: tt.fields.CodeSize,
+			Balances: tt.fields.Balances,
+			Suicide:  tt.fields.Suicide,
+			Destroy:  tt.fields.Destroy,
 		}
 		if err := a.EnoughAccountBalance(tt.args.assetID, tt.args.value); (err != nil) != tt.wantErr {
 			t.Errorf("%q. Account.EnoughAccountBalance() error = %v, wantErr %v", tt.name, err, tt.wantErr)
@@ -822,15 +731,14 @@ func TestAccount_IsSuicided(t *testing.T) {
 	}
 	for _, tt := range tests {
 		a := &Account{
-			AcctName:  tt.fields.AcctName,
-			Nonce:     tt.fields.Nonce,
-			PublicKey: tt.fields.PublicKey,
-			Code:      tt.fields.Code,
-			CodeHash:  tt.fields.CodeHash,
-			CodeSize:  tt.fields.CodeSize,
-			Balances:  tt.fields.Balances,
-			Suicide:   tt.fields.Suicide,
-			Destroy:   tt.fields.Destroy,
+			AcctName: tt.fields.AcctName,
+			Nonce:    tt.fields.Nonce,
+			Code:     tt.fields.Code,
+			CodeHash: tt.fields.CodeHash,
+			CodeSize: tt.fields.CodeSize,
+			Balances: tt.fields.Balances,
+			Suicide:  tt.fields.Suicide,
+			Destroy:  tt.fields.Destroy,
 		}
 		if got := a.IsSuicided(); got != tt.want {
 			t.Errorf("%q. Account.IsSuicided() = %v, want %v", tt.name, got, tt.want)
@@ -858,21 +766,20 @@ func TestAccount_SetSuicide(t *testing.T) {
 	}
 	for _, tt := range tests {
 		a := &Account{
-			AcctName:  tt.fields.AcctName,
-			Nonce:     tt.fields.Nonce,
-			PublicKey: tt.fields.PublicKey,
-			Code:      tt.fields.Code,
-			CodeHash:  tt.fields.CodeHash,
-			CodeSize:  tt.fields.CodeSize,
-			Balances:  tt.fields.Balances,
-			Suicide:   tt.fields.Suicide,
-			Destroy:   tt.fields.Destroy,
+			AcctName: tt.fields.AcctName,
+			Nonce:    tt.fields.Nonce,
+			Code:     tt.fields.Code,
+			CodeHash: tt.fields.CodeHash,
+			CodeSize: tt.fields.CodeSize,
+			Balances: tt.fields.Balances,
+			Suicide:  tt.fields.Suicide,
+			Destroy:  tt.fields.Destroy,
 		}
 		a.SetSuicide()
 	}
 }
 
-func TestAccount_IsDestoryed(t *testing.T) {
+func TestAccount_IsDestroyed(t *testing.T) {
 	type fields struct {
 		AcctName  common.Name
 		Nonce     uint64
@@ -893,23 +800,22 @@ func TestAccount_IsDestoryed(t *testing.T) {
 	}
 	for _, tt := range tests {
 		a := &Account{
-			AcctName:  tt.fields.AcctName,
-			Nonce:     tt.fields.Nonce,
-			PublicKey: tt.fields.PublicKey,
-			Code:      tt.fields.Code,
-			CodeHash:  tt.fields.CodeHash,
-			CodeSize:  tt.fields.CodeSize,
-			Balances:  tt.fields.Balances,
-			Suicide:   tt.fields.Suicide,
-			Destroy:   tt.fields.Destroy,
+			AcctName: tt.fields.AcctName,
+			Nonce:    tt.fields.Nonce,
+			Code:     tt.fields.Code,
+			CodeHash: tt.fields.CodeHash,
+			CodeSize: tt.fields.CodeSize,
+			Balances: tt.fields.Balances,
+			Suicide:  tt.fields.Suicide,
+			Destroy:  tt.fields.Destroy,
 		}
-		if got := a.IsDestoryed(); got != tt.want {
-			t.Errorf("%q. Account.IsDestoryed() = %v, want %v", tt.name, got, tt.want)
+		if got := a.IsDestroyed(); got != tt.want {
+			t.Errorf("%q. Account.IsDestroyed() = %v, want %v", tt.name, got, tt.want)
 		}
 	}
 }
 
-func TestAccount_SetDestory(t *testing.T) {
+func TestAccount_SetDestroy(t *testing.T) {
 	type fields struct {
 		AcctName  common.Name
 		Nonce     uint64
@@ -929,16 +835,15 @@ func TestAccount_SetDestory(t *testing.T) {
 	}
 	for _, tt := range tests {
 		a := &Account{
-			AcctName:  tt.fields.AcctName,
-			Nonce:     tt.fields.Nonce,
-			PublicKey: tt.fields.PublicKey,
-			Code:      tt.fields.Code,
-			CodeHash:  tt.fields.CodeHash,
-			CodeSize:  tt.fields.CodeSize,
-			Balances:  tt.fields.Balances,
-			Suicide:   tt.fields.Suicide,
-			Destroy:   tt.fields.Destroy,
-		}
-		a.SetDestory()
+			AcctName: tt.fields.AcctName,
+			Nonce:    tt.fields.Nonce,
+			Code:     tt.fields.Code,
+			CodeHash: tt.fields.CodeHash,
+			CodeSize: tt.fields.CodeSize,
+			Balances: tt.fields.Balances,
+			Suicide:  tt.fields.Suicide,
+			Destroy:  tt.fields.Destroy,
+		}
+		a.SetDestroy()
 	}
 }
diff --git a/accountmanager/accountmanager.go b/accountmanager/accountmanager.go
index 306a76a8..503dd312 100644
--- a/accountmanager/accountmanager.go
+++ b/accountmanager/accountmanager.go
@@ -19,63 +19,193 @@ package accountmanager
 import (
 	"fmt"
 	"math/big"
+	"strconv"
 
+	"github.com/ethereum/go-ethereum/log"
 	"github.com/fractalplatform/fractal/asset"
 	"github.com/fractalplatform/fractal/common"
+	"github.com/fractalplatform/fractal/crypto"
+	"github.com/fractalplatform/fractal/params"
 	"github.com/fractalplatform/fractal/state"
 	"github.com/fractalplatform/fractal/types"
 	"github.com/fractalplatform/fractal/utils/rlp"
 )
 
-var acctInfoPrefix = "AcctInfo"
+var (
+	acctInfoPrefix      = "acctInfo"
+	accountNameIDPrefix = "accountNameId"
+	counterPrefix       = "accountCounter"
+)
+var acctManagerName = "sysAccount"
+var sysName string = "fractal.account"
+var counterID uint64 = 4096
+
+type AuthorActionType uint64
 
 const (
-	//Account Type
-	NormalAccount uint64 = iota
-	ContractAccount
-	AssetAccount
+	AddAuthor AuthorActionType = iota
+	UpdateAuthor
+	DeleteAuthor
 )
 
 type AccountAction struct {
-	Founder     common.Name
-	ChargeRatio uint64
-	PublicKey   common.PubKey
+	AccountName common.Name   `json:"accountName,omitempty"`
+	Founder     common.Name   `json:"founder,omitempty"`
+	ChargeRatio uint64        `json:"chargeRatio,omitempty"`
+	PublicKey   common.PubKey `json:"publicKey,omitempty"`
+}
+
+type AuthorAction struct {
+	ActionType AuthorActionType
+	Author     *common.Author
+}
+
+type AccountAuthorAction struct {
+	Threshold             uint64          `json:"threshold,omitempty"`
+	UpdateAuthorThreshold uint64          `json:"updateAuthorThreshold,omitempty"`
+	AuthorActions         []*AuthorAction `json:"authorActions,omitempty"`
 }
 
 type IncAsset struct {
-	AssetId uint64      `json:"assetid,omitempty"`
+	AssetId uint64      `json:"assetId,omitempty"`
 	Amount  *big.Int    `json:"amount,omitempty"`
 	To      common.Name `json:"account,omitempty"`
 }
 
-// AccountManager represents account management model.
+//AccountManager represents account management model.
 type AccountManager struct {
 	sdb SdbIf
 	ast *asset.Asset
 }
 
+func SetAccountNameConfig(config *Config) bool {
+	if config == nil {
+		return false
+	}
+
+	if config.AccountNameLevel < 0 || config.AccountNameLength <= 8 {
+		return false
+	}
+
+	if config.AccountNameLevel > 0 {
+		if config.SubAccountNameLength < 1 {
+			return false
+		}
+	}
+
+	common.SetAccountNameCheckRule(config.AccountNameLevel, config.AccountNameLength, config.SubAccountNameLength)
+	return true
+}
+
+//SetSysName set the global sys name
+func SetSysName(name common.Name) bool {
+	if common.IsValidAccountName(name.String()) {
+		sysName = name.String()
+		return true
+	}
+	return false
+}
+
+//SetAcctMangerName  set the global account manager name
+func SetAcctMangerName(name common.Name) bool {
+	if common.IsValidAccountName(name.String()) {
+		acctManagerName = name.String()
+		return true
+	}
+	return false
+}
+
 //NewAccountManager create new account manager
 func NewAccountManager(db *state.StateDB) (*AccountManager, error) {
 	if db == nil {
 		return nil, ErrNewAccountErr
 	}
-	return &AccountManager{
+	if len(acctManagerName) == 0 {
+		log.Error("NewAccountManager error", "name", ErrAccountManagerNotExist, acctManagerName)
+		return nil, ErrAccountManagerNotExist
+	}
+	am := &AccountManager{
 		sdb: db,
 		ast: asset.NewAsset(db),
-	}, nil
+	}
+
+	am.InitAccountCounter()
+	return am, nil
+}
+
+//InitAccountCounter init account manage counter
+func (am *AccountManager) InitAccountCounter() {
+	_, err := am.getAccountCounter()
+	if err == ErrCounterNotExist {
+		//var counterID uint64
+		//counterID = 0
+		//store assetCount
+		b, err := rlp.EncodeToBytes(&counterID)
+		if err != nil {
+			panic(err)
+		}
+		am.sdb.Put(acctManagerName, counterPrefix, b)
+	}
+	return
+}
+
+//getAccountCounter get account counter cur value
+func (am *AccountManager) getAccountCounter() (uint64, error) {
+	b, err := am.sdb.Get(acctManagerName, counterPrefix)
+	if err != nil {
+		return 0, err
+	}
+	if len(b) == 0 {
+		return 0, ErrCounterNotExist
+	}
+	var accountCounter uint64
+	err = rlp.DecodeBytes(b, &accountCounter)
+	if err != nil {
+		return 0, err
+	}
+	return accountCounter, nil
 }
 
 // AccountIsExist check account is exist.
 func (am *AccountManager) AccountIsExist(accountName common.Name) (bool, error) {
 	//check is exist
-	acct, err := am.GetAccountByName(accountName)
+	accountID, err := am.GetAccountIDByName(accountName)
 	if err != nil {
 		return false, err
 	}
-	if acct != nil {
+	if accountID > 0 {
 		return true, nil
+	} else {
+		return false, nil
 	}
-	return false, nil
+}
+
+// AccountIDIsExist check account is exist by ID.
+func (am *AccountManager) AccountIDIsExist(accountID uint64) (bool, error) {
+	//check is exist
+	account, err := am.GetAccountById(accountID)
+	if err != nil {
+		return false, err
+	}
+	if account != nil {
+		return true, nil
+	} else {
+		return false, nil
+	}
+}
+
+//AccountHaveCode check account have code
+func (am *AccountManager) AccountHaveCode(accountName common.Name) (bool, error) {
+	//check is exist
+	acct, err := am.GetAccountByName(accountName)
+	if err != nil {
+		return false, err
+	}
+	if acct == nil {
+		return false, ErrAccountNotExist
+	}
+
+	return acct.HaveCode(), nil
 }
 
 //AccountIsEmpty check account is empty
@@ -95,17 +225,43 @@ func (am *AccountManager) AccountIsEmpty(accountName common.Name) (bool, error)
 	return false, nil
 }
 
+func (am *AccountManager) CreateAnyAccount(fromName common.Name, accountName common.Name, founderName common.Name, number uint64, chargeRatio uint64, pubkey common.PubKey) error {
+
+	if accountName.AccountNameLevel() > 1 {
+		if !fromName.IsValidCreator(accountName.String()) {
+			return ErrAccountInvaid
+		}
+	}
+
+	if err := am.CreateAccount(accountName, founderName, number, 0, pubkey); err != nil {
+		return err
+	}
+
+	return nil
+}
+
 //CreateAccount contract account
-func (am *AccountManager) CreateAccount(accountName common.Name, founderName common.Name, chargeRatio uint64, pubkey common.PubKey) error {
+func (am *AccountManager) CreateAccount(accountName common.Name, founderName common.Name, number uint64, chargeRatio uint64, pubkey common.PubKey) error {
+	if !common.IsValidAccountName(accountName.String()) {
+		return fmt.Errorf("account %s is invalid", accountName.String())
+	}
+
 	//check is exist
-	acct, err := am.GetAccountByName(accountName)
+	accountID, err := am.GetAccountIDByName(accountName)
 	if err != nil {
 		return err
 	}
-	if acct != nil {
+	if accountID > 0 {
 		return ErrAccountIsExist
 	}
-	if len(founderName.String()) > 0 {
+
+	assetID, _ := am.ast.GetAssetIdByName(accountName.String())
+	if assetID > 0 {
+		return ErrNameIsExist
+	}
+
+	var fname common.Name
+	if len(founderName.String()) > 0 && founderName != accountName {
 		f, err := am.GetAccountByName(founderName)
 		if err != nil {
 			return err
@@ -113,9 +269,12 @@ func (am *AccountManager) CreateAccount(accountName common.Name, founderName com
 		if f == nil {
 			return ErrAccountNotExist
 		}
+		fname.SetString(founderName.String())
+	} else {
+		fname.SetString(accountName.String())
 	}
 
-	acctObj, err := NewAccount(accountName, founderName, pubkey)
+	acctObj, err := NewAccount(accountName, fname, pubkey)
 	if err != nil {
 		return err
 	}
@@ -123,8 +282,25 @@ func (am *AccountManager) CreateAccount(accountName common.Name, founderName com
 		return ErrCreateAccountError
 	}
 
+	//get accountCounter
+	accountCounter, err := am.getAccountCounter()
+	if err != nil {
+		return err
+	}
+	accountCounter = accountCounter + 1
+	//set account id
+	acctObj.SetAccountID(accountCounter)
+
+	//store account name with account id
+	aid, err := rlp.EncodeToBytes(&accountCounter)
+	if err != nil {
+		return err
+	}
+	acctObj.SetAccountNumber(number)
 	acctObj.SetChargeRatio(0)
 	am.SetAccount(acctObj)
+	am.sdb.Put(acctManagerName, accountNameIDPrefix+accountName.String(), aid)
+	am.sdb.Put(acctManagerName, counterPrefix, aid)
 	return nil
 }
 
@@ -141,8 +317,8 @@ func (am *AccountManager) SetChargeRatio(accountName common.Name, ra uint64) err
 	return am.SetAccount(acct)
 }
 
-//UpdateAccount update the pubkey of the accunt
-func (am *AccountManager) UpdateAccount(accountName common.Name, founderName common.Name, chargeRatio uint64, pubkey common.PubKey) error {
+//UpdateAccount update the pubkey of the account
+func (am *AccountManager) UpdateAccount(accountName common.Name, accountAction *AccountAction) error {
 	acct, err := am.GetAccountByName(accountName)
 	if acct == nil {
 		return ErrAccountNotExist
@@ -150,27 +326,65 @@ func (am *AccountManager) UpdateAccount(accountName common.Name, founderName com
 	if err != nil {
 		return err
 	}
-	if len(founderName.String()) > 0 {
-		f, err := am.GetAccountByName(founderName)
+	if len(accountAction.Founder.String()) > 0 {
+		f, err := am.GetAccountByName(accountAction.Founder)
 		if err != nil {
 			return err
 		}
 		if f == nil {
 			return ErrAccountNotExist
 		}
+	} else {
+		accountAction.Founder.SetString(accountName.String())
 	}
-	if chargeRatio > 100 {
+
+	if accountAction.ChargeRatio > 100 {
 		return ErrChargeRatioInvalid
 	}
-	acct.SetFounder(founderName)
-	acct.SetChargeRatio(chargeRatio)
-	acct.SetPubKey(pubkey)
+	acct.SetFounder(accountAction.Founder)
+	acct.SetChargeRatio(accountAction.ChargeRatio)
+	return am.SetAccount(acct)
+}
+
+func (am *AccountManager) UpdateAccountAuthor(accountName common.Name, acctAuth *AccountAuthorAction) error {
+	acct, err := am.GetAccountByName(accountName)
+	if acct == nil {
+		return ErrAccountNotExist
+	}
+	if err != nil {
+		return err
+	}
+	if acctAuth.Threshold != 0 {
+		acct.SetThreshold(acctAuth.Threshold)
+	}
+	if acctAuth.UpdateAuthorThreshold != 0 {
+		acct.SetUpdateAuthorThreshold(acctAuth.UpdateAuthorThreshold)
+	}
+	for _, authorAct := range acctAuth.AuthorActions {
+		actionTy := authorAct.ActionType
+		switch actionTy {
+		case AddAuthor:
+			acct.AddAuthor(authorAct.Author)
+		case UpdateAuthor:
+			acct.UpdateAuthor(authorAct.Author)
+		case DeleteAuthor:
+			acct.DeleteAuthor(authorAct.Author)
+		default:
+			return fmt.Errorf("invalid account author operation type %d", actionTy)
+		}
+	}
+	acct.SetAuthorVersion()
 	return am.SetAccount(acct)
 }
 
 //GetAccountByTime get account by name and time
 func (am *AccountManager) GetAccountByTime(accountName common.Name, time uint64) (*Account, error) {
-	b, err := am.sdb.GetSnapshot(accountName.String(), acctInfoPrefix, time)
+	accountID, err := am.GetAccountIDByName(accountName)
+	if err != nil {
+		return nil, err
+	}
+
+	b, err := am.sdb.GetSnapshot(acctManagerName, acctInfoPrefix+strconv.FormatUint(accountID, 10), time)
 	if err != nil {
 		return nil, err
 	}
@@ -188,40 +402,68 @@ func (am *AccountManager) GetAccountByTime(accountName common.Name, time uint64)
 
 //GetAccountByName get account by name
 func (am *AccountManager) GetAccountByName(accountName common.Name) (*Account, error) {
-	b, err := am.sdb.Get(accountName.String(), acctInfoPrefix)
+	accountID, err := am.GetAccountIDByName(accountName)
 	if err != nil {
 		return nil, err
 	}
+	return am.GetAccountById(accountID)
+}
+
+//GetAccountIDByName get account id by account name
+func (am *AccountManager) GetAccountIDByName(accountName common.Name) (uint64, error) {
+	if accountName == "" {
+		return 0, nil
+	}
+	b, err := am.sdb.Get(acctManagerName, accountNameIDPrefix+accountName.String())
+	if err != nil {
+		return 0, err
+	}
 	if len(b) == 0 {
+		return 0, nil
+	}
+	var accountID uint64
+	if err := rlp.DecodeBytes(b, &accountID); err != nil {
+		return 0, err
+	}
+	return accountID, nil
+}
+
+//GetAccountById get account by account id
+func (am *AccountManager) GetAccountById(id uint64) (*Account, error) {
+	if id == 0 {
 		return nil, nil
 	}
 
+	b, err := am.sdb.Get(acctManagerName, acctInfoPrefix+strconv.FormatUint(id, 10))
+
+	if err != nil {
+		return nil, err
+	}
+	if len(b) == 0 {
+		log.Debug("account not exist", "id", ErrAccountNotExist, id)
+		return nil, nil
+	}
 	var acct Account
 	if err := rlp.DecodeBytes(b, &acct); err != nil {
 		return nil, err
 	}
-
-	//user can find destroyed account
-	//if acct.IsDestoryed() == true {
-	//	return nil, ErrAccountNotExist
-	//}
-
 	return &acct, nil
 }
 
-//store account object to db
+//SetAccount store account object to db
 func (am *AccountManager) SetAccount(acct *Account) error {
 	if acct == nil {
 		return ErrAccountIsNil
 	}
-	if acct.IsDestoryed() == true {
+	if acct.IsDestroyed() == true {
 		return ErrAccountIsDestroy
 	}
 	b, err := rlp.EncodeToBytes(acct)
 	if err != nil {
 		return err
 	}
-	am.sdb.Put(acct.GetName().String(), acctInfoPrefix, b)
+	//am.sdb.Put(acctManagerName, acctInfoPrefix+acct.GetName().String(), b)
+	am.sdb.Put(acctManagerName, acctInfoPrefix+strconv.FormatUint(acct.GetAccountID(), 10), b)
 	return nil
 }
 
@@ -235,7 +477,7 @@ func (am *AccountManager) DeleteAccountByName(accountName common.Name) error {
 		return ErrAccountNotExist
 	}
 
-	acct.SetDestory()
+	acct.SetDestroy()
 	b, err := rlp.EncodeToBytes(acct)
 	if err != nil {
 		return err
@@ -269,57 +511,66 @@ func (am *AccountManager) SetNonce(accountName common.Name, nonce uint64) error
 	return am.SetAccount(acct)
 }
 
-//GetBalancesList get Balances return a list
-//func (am *AccountManager) GetBalancesList(accountName common.Name) ([]*AssetBalance, error) {
-//	acct, err := am.GetAccountByName(accountName)
-//	if err != nil {
-//		return nil, err
-//	}
-//	return acct.GetBalancesList(), nil
-//}
-
-//GetAllAccountBalance return all balance in map.
-//func (am *AccountManager) GetAccountAllBalance(accountName common.Name) (map[uint64]*big.Int, error) {
-//	acct, err := am.GetAccountByName(accountName)
-//	if err != nil {
-//		return nil, err
-//	}
-//	if acct == nil {
-//		return nil, ErrAccountNotExist
-//	}
-//
-//	return acct.GetAllBalances()
-//}
-
-//GetAcccountPubkey get account pub key
-//func (am *AccountManager) GetAcccountPubkey(accountName common.Name) ([]byte, error) {
-//	acct, err := am.GetAccountByName(accountName)
-//	if err != nil {
-//		return nil, err
-//	}
-//	if acct == nil {
-//		return nil, ErrAccountNotExist
-//	}
-//	return acct.GetPubKey().Bytes(), nil
-//}
+// GetAuthorVersion returns the account author version
+func (am *AccountManager) GetAuthorVersion(accountName common.Name) (uint64, error) {
+	acct, err := am.GetAccountByName(accountName)
+	if err != nil {
+		return 0, err
+	}
+	if acct == nil {
+		return 0, ErrAccountNotExist
+	}
+	return acct.GetAuthorVersion(), nil
+}
 
 // RecoverTx Make sure the transaction is signed properly and validate account authorization.
 func (am *AccountManager) RecoverTx(signer types.Signer, tx *types.Transaction) error {
 	for _, action := range tx.GetActions() {
-		pub, err := types.Recover(signer, action, tx)
+		pubs, err := types.RecoverMultiKey(signer, action, tx)
 		if err != nil {
 			return err
 		}
 
-		if err := am.IsValidSign(action.Sender(), action.Type(), pub); err != nil {
-			return err
+		if uint64(len(pubs)) > params.MaxSignLength {
+			return fmt.Errorf("exceed max sign length, want most %d, actual is %d", params.MaxSignLength, len(pubs))
+		}
+
+		recoverRes := &recoverActionResult{make(map[common.Name]*accountAuthor, 0)}
+		for i, pub := range pubs {
+			index := action.GetSignIndex(uint64(i))
+			if uint64(len(index)) > params.MaxSignDepth {
+				return fmt.Errorf("exceed max sign depth, want most %d, actual is %d", params.MaxSignDepth, len(index))
+			}
+
+			if err := am.ValidSign(action.Sender(), pub, index, recoverRes); err != nil {
+				return err
+			}
+		}
+
+		authorVersion := make(map[common.Name]uint64, 0)
+		for name, acctAuthor := range recoverRes.acctAuthors {
+
+			var count uint64
+			for _, weight := range acctAuthor.indexWeight {
+				count += weight
+			}
+			threshold := acctAuthor.threshold
+			if name.String() == action.Sender().String() && action.Type() == types.UpdateAccountAuthor {
+				threshold = acctAuthor.updateAuthorThreshold
+			}
+			if count < threshold {
+				return fmt.Errorf("account %s want threshold %d, but actual is %d", name, acctAuthor.threshold, count)
+			}
+			authorVersion[name] = acctAuthor.version
 		}
+
+		types.StoreAuthorCache(action, authorVersion)
 	}
 	return nil
 }
 
 // IsValidSign
-func (am *AccountManager) IsValidSign(accountName common.Name, aType types.ActionType, pub common.PubKey) error {
+func (am *AccountManager) IsValidSign(accountName common.Name, pub common.PubKey) error {
 	acct, err := am.GetAccountByName(accountName)
 	if err != nil {
 		return err
@@ -327,16 +578,88 @@ func (am *AccountManager) IsValidSign(accountName common.Name, aType types.Actio
 	if acct == nil {
 		return ErrAccountNotExist
 	}
-	if acct.IsDestoryed() {
+	if acct.IsDestroyed() {
 		return ErrAccountIsDestroy
 	}
 	//TODO action type verify
 
-	if acct.GetPubKey().Compare(pub) != 0 {
-		return fmt.Errorf("%v %v have %v excepted %v", acct.AcctName, ErrkeyNotSame, acct.GetPubKey().String(), pub.String())
+	for _, author := range acct.Authors {
+		if author.String() == pub.String() && author.GetWeight() >= acct.GetThreshold() {
+			return nil
+		}
 	}
-	return nil
+	return fmt.Errorf("%v %v excepted %v", acct.AcctName, ErrkeyNotSame, pub.String())
+}
+
+//IsValidSign check the sign
+func (am *AccountManager) ValidSign(accountName common.Name, pub common.PubKey, index []uint64, recoverRes *recoverActionResult) error {
+	acct, err := am.GetAccountByName(accountName)
+	if err != nil {
+		return err
+	}
+	if acct == nil {
+		return ErrAccountNotExist
+	}
+	if acct.IsDestroyed() {
+		return ErrAccountIsDestroy
+	}
+
+	var i int
+	var idx uint64
+	for i, idx = range index {
+		if idx >= uint64(len(acct.Authors)) {
+			return fmt.Errorf("acct authors modified")
+		}
+		if i == len(index)-1 {
+			break
+		}
+		switch ownerTy := acct.Authors[idx].Owner.(type) {
+		case common.Name:
+			nextacct, err := am.GetAccountByName(ownerTy)
+			if err != nil {
+				return err
+			}
+			if nextacct == nil {
+				return ErrAccountNotExist
+			}
+			if nextacct.IsDestroyed() {
+				return ErrAccountIsDestroy
+			}
+			if recoverRes.acctAuthors[acct.GetName()] == nil {
+				a := &accountAuthor{version: acct.AuthorVersion, threshold: acct.Threshold, updateAuthorThreshold: acct.UpdateAuthorThreshold, indexWeight: map[uint64]uint64{idx: acct.Authors[idx].GetWeight()}}
+				recoverRes.acctAuthors[acct.GetName()] = a
+			} else {
+				recoverRes.acctAuthors[acct.GetName()].indexWeight[idx] = acct.Authors[idx].GetWeight()
+			}
+			acct = nextacct
+		default:
+			return ErrAccountNotExist
+		}
+	}
+	return am.ValidOneSign(acct, idx, pub, recoverRes)
+}
 
+func (am *AccountManager) ValidOneSign(acct *Account, index uint64, pub common.PubKey, recoverRes *recoverActionResult) error {
+	switch ownerTy := acct.Authors[index].Owner.(type) {
+	case common.PubKey:
+		if pub.Compare(ownerTy) != 0 {
+			return fmt.Errorf("%v %v have %v excepted %v", acct.AcctName, ErrkeyNotSame, pub.String(), ownerTy.String())
+		}
+	case common.Address:
+		addr := common.BytesToAddress(crypto.Keccak256(pub.Bytes()[1:])[12:])
+		if addr.Compare(ownerTy) != 0 {
+			return fmt.Errorf("%v %v have %v excepted %v", acct.AcctName, ErrkeyNotSame, addr.String(), ownerTy.String())
+		}
+	default:
+		return fmt.Errorf("wrong sign type")
+	}
+	if recoverRes.acctAuthors[acct.GetName()] == nil {
+		a := &accountAuthor{version: acct.AuthorVersion, threshold: acct.Threshold, updateAuthorThreshold: acct.UpdateAuthorThreshold, indexWeight: map[uint64]uint64{index: acct.Authors[index].GetWeight()}}
+		recoverRes.acctAuthors[acct.GetName()] = a
+		return nil
+	}
+	recoverRes.acctAuthors[acct.GetName()].indexWeight[index] = acct.Authors[index].GetWeight()
+	return nil
 }
 
 //GetAssetInfoByName get asset info by asset name.
@@ -353,8 +676,95 @@ func (am *AccountManager) GetAssetInfoByID(assetID uint64) (*asset.AssetObject,
 	return am.ast.GetAssetObjectById(assetID)
 }
 
+// GetAllAssetbyAssetId get accout asset and subAsset Info
+func (am *AccountManager) GetAllAssetbyAssetId(acct *Account, assetId uint64) (map[uint64]*big.Int, error) {
+	var ba = make(map[uint64]*big.Int, 0)
+
+	b, err := acct.GetBalanceByID(assetId)
+	if err != nil {
+		return nil, err
+	}
+	ba[assetId] = b
+
+	assetObj, err := am.ast.GetAssetObjectById(assetId)
+	if err != nil {
+		return nil, err
+	}
+
+	assetName := assetObj.GetAssetName()
+	balances, err := acct.GetAllBalances()
+	if err != nil {
+		return nil, err
+	}
+
+	for id, balance := range balances {
+		subAssetObj, err := am.ast.GetAssetObjectById(id)
+		if err != nil {
+			return nil, err
+		}
+
+		if common.IsValidCreator(assetName, subAssetObj.GetAssetName()) {
+			ba[id] = balance
+		}
+	}
+
+	return ba, nil
+}
+
+// GetAllBalancebyAssetID get account balance, balance(asset) = asset + subAsset
+func (am *AccountManager) GetAllBalancebyAssetID(acct *Account, assetID uint64) (*big.Int, error) {
+	var ba *big.Int
+	ba = big.NewInt(0)
+
+	b, _ := acct.GetBalanceByID(assetID)
+	ba = ba.Add(ba, b)
+
+	assetObj, err := am.ast.GetAssetObjectById(assetID)
+	if err != nil {
+		return big.NewInt(0), err
+	}
+
+	assetName := assetObj.GetAssetName()
+	balances, err := acct.GetAllBalances()
+	if err != nil {
+		return big.NewInt(0), err
+	}
+
+	for id, balance := range balances {
+		subAssetObj, err := am.ast.GetAssetObjectById(id)
+		if err != nil {
+			return big.NewInt(0), err
+		}
+
+		if common.IsValidCreator(assetName, subAssetObj.GetAssetName()) {
+			ba = ba.Add(ba, balance)
+		}
+	}
+
+	return ba, nil
+}
+
+//GetBalanceByTime get account balance by Time
+func (am *AccountManager) GetBalanceByTime(accountName common.Name, assetID uint64, typeID uint64, time uint64) (*big.Int, error) {
+	acct, err := am.GetAccountByTime(accountName, time)
+	if err != nil {
+		return big.NewInt(0), err
+	}
+	if acct == nil {
+		return big.NewInt(0), ErrAccountNotExist
+	}
+
+	if typeID == 0 {
+		return acct.GetBalanceByID(assetID)
+	} else if typeID == 1 {
+		return am.GetAllBalancebyAssetID(acct, assetID)
+	} else {
+		return big.NewInt(0), fmt.Errorf("type ID %d invalid", typeID)
+	}
+}
+
 //GetAccountBalanceByID get account balance by ID
-func (am *AccountManager) GetAccountBalanceByID(accountName common.Name, assetID uint64) (*big.Int, error) {
+func (am *AccountManager) GetAccountBalanceByID(accountName common.Name, assetID uint64, typeID uint64) (*big.Int, error) {
 	acct, err := am.GetAccountByName(accountName)
 	if err != nil {
 		return big.NewInt(0), err
@@ -362,7 +772,13 @@ func (am *AccountManager) GetAccountBalanceByID(accountName common.Name, assetID
 	if acct == nil {
 		return big.NewInt(0), ErrAccountNotExist
 	}
-	return acct.GetBalanceByID(assetID)
+	if typeID == 0 {
+		return acct.GetBalanceByID(assetID)
+	} else if typeID == 1 {
+		return am.GetAllBalancebyAssetID(acct, assetID)
+	} else {
+		return big.NewInt(0), fmt.Errorf("type ID %d invalid", typeID)
+	}
 }
 
 //GetAssetAmountByTime get asset amount by time
@@ -406,30 +822,7 @@ func (am *AccountManager) GetSnapshotTime(num uint64, time uint64) (uint64, erro
 	return 0, ErrTimeTypeInvalid
 }
 
-//GetBalanceByTime get account balance by Time
-func (am *AccountManager) GetBalanceByTime(accountName common.Name, assetID uint64, time uint64) (*big.Int, error) {
-	acct, err := am.GetAccountByTime(accountName, time)
-	if err != nil {
-		return nil, err
-	}
-	if acct == nil {
-		return nil, ErrAccountNotExist
-	}
-	return acct.GetBalanceByID(assetID)
-	//if time == 0 {
-	//	//current
-	//	return acct.GetBalanceByID(assetID)
-	//}else {
-	//	//spec time balance
-	//	if acct, err = am.GetAccountByTime(accountName,time);err!= nil{
-	//		return nil,err
-	//	}
-	//	return acct.GetBalanceByID(assetID)
-	//}
-
-}
-
-//Get Account Founder
+//GetFounder Get Account Founder
 func (am *AccountManager) GetFounder(accountName common.Name) (common.Name, error) {
 	acct, err := am.GetAccountByName(accountName)
 	if err != nil {
@@ -441,12 +834,12 @@ func (am *AccountManager) GetFounder(accountName common.Name) (common.Name, erro
 	return acct.GetFounder(), nil
 }
 
-//Get Asset Founder
+//GetAssetFounder Get Asset Founder
 func (am *AccountManager) GetAssetFounder(assetID uint64) (common.Name, error) {
 	return am.ast.GetAssetFounderById(assetID)
 }
 
-//Get Account ChargeRatio
+//GetChargeRatio Get Account ChargeRatio
 func (am *AccountManager) GetChargeRatio(accountName common.Name) (uint64, error) {
 	acct, err := am.GetAccountByName(accountName)
 	if err != nil {
@@ -458,7 +851,7 @@ func (am *AccountManager) GetChargeRatio(accountName common.Name) (uint64, error
 	return acct.GetChargeRatio(), nil
 }
 
-//Get Asset ChargeRatio
+//GetAssetChargeRatio Get Asset ChargeRatio
 func (am *AccountManager) GetAssetChargeRatio(assetID uint64) (uint64, error) {
 	acctName, err := am.ast.GetAssetFounderById(assetID)
 	if err != nil {
@@ -510,15 +903,12 @@ func (am *AccountManager) SubAccountBalanceByID(accountName common.Name, assetID
 	if value.Cmp(big.NewInt(0)) < 0 {
 		return ErrAmountValueInvalid
 	}
-	//
-	val, err := acct.GetBalanceByID(assetID)
+
+	err = acct.SubBalanceByID(assetID, value)
 	if err != nil {
 		return err
 	}
-	if val.Cmp(big.NewInt(0)) < 0 || val.Cmp(value) < 0 {
-		return ErrInsufficientBalance
-	}
-	acct.SetBalance(assetID, new(big.Int).Sub(val, value))
+
 	return am.SetAccount(acct)
 }
 
@@ -536,15 +926,15 @@ func (am *AccountManager) AddAccountBalanceByID(accountName common.Name, assetID
 		return ErrAmountValueInvalid
 	}
 
-	val, err := acct.GetBalanceByID(assetID)
-	if err == ErrAccountAssetNotExist {
-		acct.AddNewAssetByAssetID(assetID, value)
-	} else {
-		acct.SetBalance(assetID, new(big.Int).Add(val, value))
+	err = acct.AddBalanceByID(assetID, value)
+	if err != nil {
+		return err
 	}
+
 	return am.SetAccount(acct)
 }
 
+//AddAccountBalanceByName  add balance by name
 func (am *AccountManager) AddAccountBalanceByName(accountName common.Name, assetName string, value *big.Int) error {
 	acct, err := am.GetAccountByName(accountName)
 	if err != nil {
@@ -553,6 +943,7 @@ func (am *AccountManager) AddAccountBalanceByName(accountName common.Name, asset
 	if acct == nil {
 		return ErrAccountNotExist
 	}
+
 	assetID, err := am.ast.GetAssetIdByName(assetName)
 	if err != nil {
 		return err
@@ -565,12 +956,11 @@ func (am *AccountManager) AddAccountBalanceByName(accountName common.Name, asset
 		return ErrAmountValueInvalid
 	}
 
-	val, err := acct.GetBalanceByID(assetID)
-	if err == ErrAccountAssetNotExist {
-		acct.AddNewAssetByAssetID(assetID, value)
-	} else {
-		acct.SetBalance(assetID, new(big.Int).Add(val, value))
+	err = acct.AddBalanceByID(assetID, value)
+	if err != nil {
+		return err
 	}
+
 	return am.SetAccount(acct)
 }
 
@@ -676,8 +1066,19 @@ func (am *AccountManager) CanTransfer(accountName common.Name, assetID uint64, v
 	return false, err
 }
 
-//TransferAsset
+//TransferAsset transfer asset
 func (am *AccountManager) TransferAsset(fromAccount common.Name, toAccount common.Name, assetID uint64, value *big.Int) error {
+	if value.Sign() == -1 {
+		return ErrNegativeValue
+	}
+
+	if ast, err := am.GetAssetInfoByID(assetID); err != nil {
+		return err
+	} else if len(ast.Contract.String()) != 0 && !(fromAccount == ast.Contract || toAccount == ast.Contract) {
+		return ErrInvalidReceiptAsset
+	}
+
+	//check from account
 	fromAcct, err := am.GetAccountByName(fromAccount)
 	if err != nil {
 		return err
@@ -688,9 +1089,10 @@ func (am *AccountManager) TransferAsset(fromAccount common.Name, toAccount commo
 	if value.Cmp(big.NewInt(0)) < 0 {
 		return ErrAmountValueInvalid
 	}
-	if fromAccount == toAccount {
+	if fromAccount == toAccount || value.Cmp(big.NewInt(0)) == 0 {
 		return nil
 	}
+	//check from account balance
 	val, err := fromAcct.GetBalanceByID(assetID)
 	if err != nil {
 		return err
@@ -699,7 +1101,7 @@ func (am *AccountManager) TransferAsset(fromAccount common.Name, toAccount commo
 		return ErrInsufficientBalance
 	}
 	fromAcct.SetBalance(assetID, new(big.Int).Sub(val, value))
-
+	//check to account
 	toAcct, err := am.GetAccountByName(toAccount)
 	if err != nil {
 		return err
@@ -707,7 +1109,7 @@ func (am *AccountManager) TransferAsset(fromAccount common.Name, toAccount commo
 	if toAcct == nil {
 		return ErrAccountNotExist
 	}
-	if toAcct.IsDestoryed() {
+	if toAcct.IsDestroyed() {
 		return ErrAccountIsDestroy
 	}
 	val, err = toAcct.GetBalanceByID(assetID)
@@ -722,11 +1124,20 @@ func (am *AccountManager) TransferAsset(fromAccount common.Name, toAccount commo
 	return am.SetAccount(toAcct)
 }
 
-//IssueAsset issue asset
-func (am *AccountManager) IssueAsset(asset *asset.AssetObject) error {
-	if err := am.ast.IssueAsset(asset.GetAssetName(), asset.GetSymbol(), asset.GetAssetAmount(), asset.GetDecimals(), asset.GetAssetFounder(), asset.GetAssetOwner(), asset.GetUpperLimit()); err != nil {
+func (am *AccountManager) IssueAnyAsset(fromName common.Name, asset *asset.AssetObject) error {
+	if !am.ast.IsValidOwner(fromName, asset.GetAssetName()) {
+		return fmt.Errorf("account %s can not create %s", fromName, asset.GetAssetName())
+	}
+
+	if err := am.IssueAsset(asset); err != nil {
 		return err
 	}
+	return nil
+}
+
+//IssueAsset issue asset
+func (am *AccountManager) IssueAsset(asset *asset.AssetObject) error {
+	//check owner
 	acct, err := am.GetAccountByName(asset.GetAssetOwner())
 	if err != nil {
 		return err
@@ -734,17 +1145,35 @@ func (am *AccountManager) IssueAsset(asset *asset.AssetObject) error {
 	if acct == nil {
 		return ErrAccountNotExist
 	}
-	f, err := am.GetAccountByName(asset.GetAssetFounder())
-	if err != nil {
-		return err
+	//check founder
+	if len(asset.GetAssetFounder()) > 0 {
+		f, err := am.GetAccountByName(asset.GetAssetFounder())
+		if err != nil {
+			return err
+		}
+		if f == nil {
+			return ErrAccountNotExist
+		}
+	} else {
+		asset.SetAssetFounder(asset.GetAssetOwner())
 	}
-	if f == nil {
-		return ErrAccountNotExist
+
+	if name, err := common.StringToName(asset.GetAssetName()); err == nil {
+		accountID, _ := am.GetAccountIDByName(name)
+		if accountID > 0 {
+			return ErrNameIsExist
+		}
+	}
+
+	if err := am.ast.IssueAsset(asset.GetAssetName(), asset.GetAssetNumber(), asset.GetSymbol(), asset.GetAssetAmount(), asset.GetDecimals(), asset.GetAssetFounder(), asset.GetAssetOwner(), asset.GetUpperLimit(), asset.GetContract()); err != nil {
+		return err
 	}
+
+	//add the asset to owner
 	return am.AddAccountBalanceByName(asset.GetAssetOwner(), asset.GetAssetName(), asset.GetAssetAmount())
 }
 
-//increase asset and add amount to accout balance
+//IncAsset2Acct increase asset and add amount to accout balance
 func (am *AccountManager) IncAsset2Acct(fromName common.Name, toName common.Name, assetID uint64, amount *big.Int) error {
 	if err := am.ast.IncreaseAsset(fromName, assetID, amount); err != nil {
 		return err
@@ -765,118 +1194,195 @@ func (am *AccountManager) IncAsset2Acct(fromName common.Name, toName common.Name
 //	rerturn
 //}
 
-// Process account action
-
-func (am *AccountManager) Process(action *types.Action) error {
+//Process account action
+func (am *AccountManager) Process(accountManagerContext *types.AccountManagerContext) ([]*types.InternalAction, error) {
 	snap := am.sdb.Snapshot()
-	err := am.process(action)
+	internalActions, err := am.process(accountManagerContext)
 	if err != nil {
 		am.sdb.RevertToSnapshot(snap)
 	}
-	return err
+	return internalActions, err
 }
 
-func (am *AccountManager) process(action *types.Action) error {
+func (am *AccountManager) process(accountManagerContext *types.AccountManagerContext) ([]*types.InternalAction, error) {
+	action := accountManagerContext.Action
+	number := accountManagerContext.Number
+
+	var internalActions []*types.InternalAction
+
+	if !action.CheckValue() {
+		return nil, ErrAmountValueInvalid
+	}
+
+	if action.Type() != types.Transfer && action.Recipient() != common.Name(sysName) {
+		return nil, ErrInvalidReceipt
+	}
+
+	//transfer
+	if action.Value().Cmp(big.NewInt(0)) > 0 {
+		if err := am.TransferAsset(action.Sender(), action.Recipient(), action.AssetID(), action.Value()); err != nil {
+			return nil, err
+		}
+	}
+
+	//transaction
 	switch action.Type() {
 	case types.CreateAccount:
-		key := common.BytesToPubKey(action.Data())
-		if err := am.CreateAccount(action.Recipient(), common.Name(""), 0, key); err != nil {
-			return err
+		var acct AccountAction
+		err := rlp.DecodeBytes(action.Data(), &acct)
+		if err != nil {
+			return nil, err
+		}
+
+		if err := am.CreateAnyAccount(action.Sender(), acct.AccountName, acct.Founder, number, 0, acct.PublicKey); err != nil {
+			return nil, err
+		}
+
+		if action.Value().Cmp(big.NewInt(0)) > 0 {
+			if err := am.TransferAsset(common.Name(sysName), acct.AccountName, action.AssetID(), action.Value()); err != nil {
+				return nil, err
+			}
+			actionX := types.NewAction(action.Type(), common.Name(sysName), acct.AccountName, 0, 0, action.AssetID(), action.Value(), nil)
+			internalAction := &types.InternalAction{Action: actionX.NewRPCAction(0), ActionType: "", GasUsed: 0, GasLimit: 0, Depth: 0, Error: ""}
+			internalActions = append(internalActions, internalAction)
 		}
 		break
 	case types.UpdateAccount:
 		var acct AccountAction
 		err := rlp.DecodeBytes(action.Data(), &acct)
 		if err != nil {
-			return err
+			return nil, err
 		}
-		if err := am.UpdateAccount(action.Sender(), acct.Founder, 0, acct.PublicKey); err != nil {
-			return err
+
+		if err := am.UpdateAccount(action.Sender(), &acct); err != nil {
+			return nil, err
+		}
+		break
+	case types.UpdateAccountAuthor:
+		var acctAuth AccountAuthorAction
+		err := rlp.DecodeBytes(action.Data(), &acctAuth)
+		if err != nil {
+			return nil, err
+		}
+		if err := am.UpdateAccountAuthor(action.Sender(), &acctAuth); err != nil {
+			return nil, err
 		}
 		break
-		//case types.DeleteAccount:
-		//	if err := am.DeleteAccountByName(action.Sender()); err != nil {
-		//		return err
-		//	}
-		//	break
 	case types.IssueAsset:
 		var asset asset.AssetObject
 		err := rlp.DecodeBytes(action.Data(), &asset)
 		if err != nil {
-			return err
+			return nil, err
 		}
-		if err := am.IssueAsset(&asset); err != nil {
-			return err
+
+		asset.SetAssetNumber(number)
+		if err := am.IssueAnyAsset(action.Sender(), &asset); err != nil {
+			return nil, err
 		}
+		actionX := types.NewAction(action.Type(), common.Name(sysName), asset.GetAssetOwner(), 0, 0, asset.GetAssetId(), asset.GetAssetAmount(), nil)
+		internalAction := &types.InternalAction{Action: actionX.NewRPCAction(0), ActionType: "", GasUsed: 0, GasLimit: 0, Depth: 0, Error: ""}
+		internalActions = append(internalActions, internalAction)
 		break
 	case types.IncreaseAsset:
 		var inc IncAsset
+		var accountFrom = common.Name("")
 		err := rlp.DecodeBytes(action.Data(), &inc)
 		if err != nil {
-			return err
+			return nil, err
 		}
 		if err = am.IncAsset2Acct(action.Sender(), inc.To, inc.AssetId, inc.Amount); err != nil {
-			return err
+			return nil, err
 		}
+		actionX := types.NewAction(action.Type(), common.Name(accountFrom), inc.To, 0, 0, inc.AssetId, inc.Amount, nil)
+		internalAction := &types.InternalAction{Action: actionX.NewRPCAction(0), ActionType: "", GasUsed: 0, GasLimit: 0, Depth: 0, Error: ""}
+		internalActions = append(internalActions, internalAction)
 		break
 
-	case types.DestoryAsset:
-		var asset asset.AssetObject
-		err := rlp.DecodeBytes(action.Data(), &asset)
-		if err != nil {
-			return err
-		}
-		if err = am.SubAccountBalanceByID(action.Sender(), asset.GetAssetId(), asset.GetAssetAmount()); err != nil {
-			return err
+	case types.DestroyAsset:
+		// var asset asset.AssetObject
+		// err := rlp.DecodeBytes(action.Data(), &asset)
+		// if err != nil {
+		// 	return err
+		// }
+		if err := am.SubAccountBalanceByID(common.Name(sysName), action.AssetID(), action.Value()); err != nil {
+			return nil, err
 		}
-		if err = am.ast.DestoryAsset(action.Sender(), asset.GetAssetId(), asset.GetAssetAmount()); err != nil {
-			return err
+
+		if err := am.ast.DestroyAsset(common.Name(sysName), action.AssetID(), action.Value()); err != nil {
+			return nil, err
 		}
+		actionX := types.NewAction(action.Type(), common.Name(sysName), "", 0, 0, action.AssetID(), action.Value(), nil)
+		internalAction := &types.InternalAction{Action: actionX.NewRPCAction(0), ActionType: "", GasUsed: 0, GasLimit: 0, Depth: 0, Error: ""}
+		internalActions = append(internalActions, internalAction)
 		break
-	case types.SetAssetOwner:
+	case types.UpdateAsset:
 		var asset asset.AssetObject
 		err := rlp.DecodeBytes(action.Data(), &asset)
 		if err != nil {
-			return err
+			return nil, err
 		}
 		acct, err := am.GetAccountByName(asset.GetAssetOwner())
 		if err != nil {
-			return err
+			return nil, err
 		}
 		if acct == nil {
-			return ErrAccountNotExist
-		}
-		if err := am.ast.SetAssetNewOwner(action.Sender(), asset.GetAssetId(), asset.GetAssetOwner()); err != nil {
-			return err
-		}
-		break
-	case types.SetAssetFounder:
-		var asset asset.AssetObject
-		err := rlp.DecodeBytes(action.Data(), &asset)
-		if err != nil {
-			return err
+			return nil, ErrAccountNotExist
 		}
 		if len(asset.GetAssetFounder().String()) > 0 {
 			acct, err := am.GetAccountByName(asset.GetAssetFounder())
 			if err != nil {
-				return err
+				return nil, err
 			}
 			if acct == nil {
-				return ErrAccountNotExist
+				return nil, ErrAccountNotExist
 			}
 		}
-		if err = am.ast.SetAssetFounder(action.Sender(), asset.GetAssetId(), asset.GetAssetFounder()); err != nil {
-			return err
+		if err := am.ast.UpdateAsset(action.Sender(), asset.GetAssetId(), asset.GetAssetOwner(), asset.GetAssetFounder(), asset.GetAssetContract()); err != nil {
+			return nil, err
+		}
+		break
+	case types.SetAssetOwner:
+		var asset asset.AssetObject
+		err := rlp.DecodeBytes(action.Data(), &asset)
+		if err != nil {
+			return nil, err
+		}
+		acct, err := am.GetAccountByName(asset.GetAssetOwner())
+		if err != nil {
+			return nil, err
+		}
+		if acct == nil {
+			return nil, ErrAccountNotExist
 		}
+		if err := am.ast.SetAssetNewOwner(action.Sender(), asset.GetAssetId(), asset.GetAssetOwner()); err != nil {
+			return nil, err
+		}
+		break
+	// case types.SetAssetFounder:
+	// 	var asset asset.AssetObject
+	// 	err := rlp.DecodeBytes(action.Data(), &asset)
+	// 	if err != nil {
+	// 		return err
+	// 	}
+	// 	if len(asset.GetAssetFounder().String()) > 0 {
+	// 		acct, err := am.GetAccountByName(asset.GetAssetFounder())
+	// 		if err != nil {
+	// 			return err
+	// 		}
+	// 		if acct == nil {
+	// 			return ErrAccountNotExist
+	// 		}
+	// 	}
+	// 	if err = am.ast.SetAssetFounder(action.Sender(), asset.GetAssetId(), asset.GetAssetFounder()); err != nil {
+	// 		return err
+	// 	}
+	// 	break
+	case types.Transfer:
+		//return am.TransferAsset(action.Sender(), action.Recipient(), action.AssetID(), action.Value())
 		break
-	//case types.Transfer:
-	//	return am.TransferAsset(action.Sender(), action.Recipient(), action.AssetID(), action.Value())
 	default:
-		return ErrUnkownTxType
+		return nil, ErrUnkownTxType
 	}
 
-	if action.Value().Cmp(big.NewInt(0)) > 0 {
-		return am.TransferAsset(action.Sender(), action.Recipient(), action.AssetID(), action.Value())
-	}
-	return nil
+	return internalActions, nil
 }
diff --git a/accountmanager/accountmanager_test.go b/accountmanager/accountmanager_test.go
index eab47857..2894ac81 100644
--- a/accountmanager/accountmanager_test.go
+++ b/accountmanager/accountmanager_test.go
@@ -17,7 +17,6 @@
 package accountmanager
 
 import (
-	"bytes"
 	"crypto/ecdsa"
 	"fmt"
 	"math/big"
@@ -43,7 +42,7 @@ func getStateDB() *state.StateDB {
 	tridb := state.NewDatabase(db)
 	statedb, err := state.New(common.Hash{}, tridb)
 	if err != nil {
-		//.Fatal("test NewState failure ", err)
+		fmt.Printf("test getStateDB() failure %v", err)
 		return nil
 	}
 
@@ -53,19 +52,23 @@ func getAsset() *asset.Asset {
 	return asset.NewAsset(sdb)
 }
 func getAccountManager() *AccountManager {
-
+	SetAcctMangerName("systestname")
+	SetSysName("systestname")
 	am, err := NewAccountManager(sdb)
 	if err != nil {
-		//t.Fatal("test NewAccount failure ", err)
+		fmt.Printf("test getAccountManager() failure %v", err)
 	}
+	pubkey := new(common.PubKey)
+	pubkey.SetBytes([]byte("abcde123456789"))
+	am.CreateAccount(common.Name("systestname"), common.Name(""), 0, 0, *pubkey)
 	return am
 }
 
 func TestSDB(t *testing.T) {
-
 	b, err := rlp.EncodeToBytes("aaaa")
 	if err != nil {
 		fmt.Printf("encode err = %v", err)
+
 	}
 	sdb.Put("test1", acctInfoPrefix, b)
 	b1, err := sdb.Get("test1", acctInfoPrefix)
@@ -86,10 +89,10 @@ func TestSDB(t *testing.T) {
 
 }
 func TestNN(t *testing.T) {
-	if err := acctm.CreateAccount(common.Name("123asdf2"), common.Name(""), 0, *new(common.PubKey)); err != nil {
+	if err := acctm.CreateAccount(common.Name("123asdf2"), common.Name(""), 0, 0, *new(common.PubKey)); err != nil {
 		t.Errorf("err create account\n")
 	}
-	_, err := acctm.GetAccountBalanceByID(common.Name("123asdf2"), 1)
+	_, err := acctm.GetAccountBalanceByID(common.Name("123asdf2"), 1, 0)
 	if err == nil {
 		t.Errorf("err get balance err %v\n", err)
 	}
@@ -124,6 +127,10 @@ func TestNewAccountManager(t *testing.T) {
 	}
 }
 
+func TestAccountManager_InitAccountCounter(t *testing.T) {
+	//TODO
+}
+
 func TestAccountManager_CreateAccount(t *testing.T) {
 	type fields struct {
 		sdb *state.StateDB
@@ -158,7 +165,7 @@ func TestAccountManager_CreateAccount(t *testing.T) {
 			sdb: tt.fields.sdb,
 			ast: tt.fields.ast,
 		}
-		if err := am.CreateAccount(tt.args.accountName, tt.args.founderName, 1, tt.args.pubkey); (err != nil) != tt.wantErr {
+		if err := am.CreateAccount(tt.args.accountName, tt.args.founderName, 0, 1, tt.args.pubkey); (err != nil) != tt.wantErr {
 			t.Errorf("%q. AccountManager.CreateAccount() error = %v, wantErr %v", tt.name, err, tt.wantErr)
 		}
 	}
@@ -167,7 +174,7 @@ func TestAccountManager_CreateAccount(t *testing.T) {
 		sdb: sdb,
 		ast: ast,
 	}
-	err := am1.CreateAccount(common.Name("aaaadddd"), common.Name("111222332a"), 1, *pubkey)
+	err := am1.CreateAccount(common.Name("aaaadddd"), common.Name("111222332a"), 0, 1, *pubkey)
 	if err != nil {
 		t.Errorf("create acct err:%v", err)
 	}
@@ -228,7 +235,7 @@ func TestAccountManager_AccountIsEmpty(t *testing.T) {
 		wantErr error
 	}{
 		//
-		{"accountEmpty", fields{sdb, ast}, args{common.Name("11122233")}, false, ErrAccountNotExist},
+		{"accountNotEmpty", fields{sdb, ast}, args{common.Name("11122233")}, false, ErrAccountNotExist},
 		{"accountEmpty", fields{sdb, ast}, args{common.Name("a123456789aeee")}, true, nil},
 	}
 	for _, tt := range tests {
@@ -250,52 +257,6 @@ func GeneragePubKey() (common.PubKey, *ecdsa.PrivateKey) {
 	prikey, _ := crypto.GenerateKey()
 	return common.BytesToPubKey(crypto.FromECDSAPub(&prikey.PublicKey)), prikey
 }
-func TestAccountManager_UpdateAccount(t *testing.T) {
-	type fields struct {
-		sdb SdbIf
-		ast *asset.Asset
-	}
-	pubkey := new(common.PubKey)
-	pubkey2 := new(common.PubKey)
-	pubkey.SetBytes([]byte("abcde123456789"))
-
-	pubkey3, _ := GeneragePubKey()
-	//fmt.Printf("UpdateAccount key=%v\n", pubkey3.Bytes())
-	type args struct {
-		accountName common.Name
-		founderName common.Name
-		chargeRatio uint64
-		pubkey      common.PubKey
-	}
-	tests := []struct {
-		name    string
-		fields  fields
-		args    args
-		wantErr bool
-	}{
-		//
-		{"updateAccount", fields{sdb, ast}, args{common.Name("a123456789aeee"), common.Name("a123456789aeee"), 1, pubkey3}, false},
-		{"updateAccount", fields{sdb, ast}, args{common.Name("a123456789aeee"), common.Name("111222332a"), 1, pubkey3}, false},
-		{"updateAccountNilFounder", fields{sdb, ast}, args{common.Name("111222332a"), common.Name("1112223-"), 1, *pubkey2}, true},
-		{"updateAccountInvaidName", fields{sdb, ast}, args{common.Name("a123456789aeeegty"), common.Name("a123456789aeeegty"), 1, *pubkey2}, true},
-	}
-	for _, tt := range tests {
-		am := &AccountManager{
-			sdb: tt.fields.sdb,
-			ast: tt.fields.ast,
-		}
-		//if err := am.CreateAccount(tt.args.accountName, *pubkey2); (err != nil) != tt.wantErr {
-		//	t.Errorf("%q. AccountManager.CreateAccount() error = %v, wantErr %v", tt.name, err, tt.wantErr)
-		//}
-		if err := am.UpdateAccount(tt.args.accountName, tt.args.founderName, tt.args.chargeRatio, tt.args.pubkey); (err != nil) != tt.wantErr {
-			t.Errorf("%q. AccountManager.UpdateAccount() error = %v, wantErr %v", tt.name, err, tt.wantErr)
-		}
-	}
-	acct, _ := acctm.GetAccountByName(common.Name("a123456789aeee"))
-	if bytes.Compare(acct.PublicKey.Bytes(), pubkey3.Bytes()) != 0 {
-		t.Errorf("AccountManager.UpdateAccount() error key not eque:%v\n =%v", acct.PublicKey.Bytes(), []byte("abcde123456789"))
-	}
-}
 
 func TestAccountManager_GetAccountByName(t *testing.T) {
 	type fields struct {
@@ -355,7 +316,7 @@ func TestAccountManager_SetAccount(t *testing.T) {
 		acct *Account
 	}
 	pubkey2 := new(common.PubKey)
-	acctm.CreateAccount(common.Name("a123456789"), common.Name(""), 0, *pubkey2)
+	acctm.CreateAccount(common.Name("a123456789"), common.Name(""), 0, 0, *pubkey2)
 	ac, _ := acctm.GetAccountByName(common.Name("a123456789"))
 
 	tests := []struct {
@@ -572,13 +533,12 @@ func TestAccountManager_IsValidSign(t *testing.T) {
 	}
 	type args struct {
 		accountName common.Name
-		aType       types.ActionType
 		pub         common.PubKey
 	}
 	pubkey := new(common.PubKey)
 	pubkey2 := new(common.PubKey)
 	pubkey2.SetBytes([]byte("abcde123456789"))
-	acctm.UpdateAccount(common.Name("a123456789aeee"), common.Name("a123456789aeee"), 1, *pubkey2)
+	//acctm.UpdateAccount(common.Name("a123456789aeee"), &AccountAction{common.Name("a123456789aeee"), common.Name("a123456789aeee"), 1, *pubkey2})
 	tests := []struct {
 		name    string
 		fields  fields
@@ -586,15 +546,15 @@ func TestAccountManager_IsValidSign(t *testing.T) {
 		wantErr bool
 	}{
 		//
-		{"invalidsign", fields{sdb, ast}, args{common.Name("a123456789aeee"), types.CreateContract, *pubkey}, true},
-		{"validsign", fields{sdb, ast}, args{common.Name("a123456789aeee"), types.CreateContract, *pubkey2}, false},
+		{"invalidsign", fields{sdb, ast}, args{common.Name("a123456789aeee"), *pubkey}, false},
+		{"validsign", fields{sdb, ast}, args{common.Name("a123456789aeee"), *pubkey2}, true},
 	}
 	for _, tt := range tests {
 		am := &AccountManager{
 			sdb: tt.fields.sdb,
 			ast: tt.fields.ast,
 		}
-		if err := am.IsValidSign(tt.args.accountName, tt.args.aType, tt.args.pub); (err != nil) != tt.wantErr {
+		if err := am.IsValidSign(tt.args.accountName, tt.args.pub); (err != nil) != tt.wantErr {
 			t.Errorf("%q. AccountManager.IsValidSign() error = %v, wantErr %v", tt.name, err, tt.wantErr)
 		}
 	}
@@ -609,16 +569,16 @@ func TestAccountManager_GetAccountBalanceByID(t *testing.T) {
 		accountName common.Name
 		assetID     uint64
 	}
-
-	acctm.ast.IssueAsset("ziz", "zz", big.NewInt(1000), 10, common.Name("a123456789aeee"), common.Name("a123456789aeee"), big.NewInt(1000))
+	//asset ID = 1
+	acctm.ast.IssueAsset("ziz", 0, "zz", big.NewInt(1000), 0, common.Name("a123456789aeee"), common.Name("a123456789aeee"), big.NewInt(1000), common.Name(""))
 	id, _ := acctm.ast.GetAssetIdByName("ziz")
-	//t.Logf("GetAccountBalanceByID id=%v", id)
+	t.Logf("GetAccountBalanceByID id=%v", id)
 	if err := acctm.AddAccountBalanceByID(common.Name("a123456789aeee"), id, big.NewInt(800)); err != nil {
 		t.Errorf("%q. GetAccountByName.AddBalanceByName() error = %v, ", common.Name("a123456789aeee"), err)
 	}
 
-	//val, _ := acctm.GetAccountBalanceByID(common.Name("a123456789aeee"), id)
-	//	t.Logf("GetAccountBalanceByID asset id=%v : val=%v\n", id, val)
+	val, _ := acctm.GetAccountBalanceByID(common.Name("a123456789aeee"), id, 0)
+	t.Logf("a123456789aeee asset id=%v : val=%v\n", id, val)
 
 	tests := []struct {
 		name    string
@@ -628,7 +588,7 @@ func TestAccountManager_GetAccountBalanceByID(t *testing.T) {
 		wantErr bool
 	}{
 		//
-		{"getAcctBaByID", fields{sdb, ast}, args{common.Name("a123456789aeee"), id}, big.NewInt(800), false},
+		{"getAcctByID", fields{sdb, ast}, args{common.Name("a123456789aeee"), id}, big.NewInt(800), false},
 	}
 	//acctm := getAccountManager(t)
 	//pubkey2 := new(common.PubKey)
@@ -642,7 +602,7 @@ func TestAccountManager_GetAccountBalanceByID(t *testing.T) {
 			sdb: tt.fields.sdb,
 			ast: tt.fields.ast,
 		}
-		got, err := am.GetAccountBalanceByID(tt.args.accountName, tt.args.assetID)
+		got, err := am.GetAccountBalanceByID(tt.args.accountName, tt.args.assetID, 0)
 		if (err != nil) != tt.wantErr {
 			t.Errorf("%q. AccountManager.GetAccountBalanceByID() error = %v, wantErr %v", tt.name, err, tt.wantErr)
 			continue
@@ -651,7 +611,7 @@ func TestAccountManager_GetAccountBalanceByID(t *testing.T) {
 			t.Errorf("%q. AccountManager.GetAccountBalanceByID() = %v, want %v", tt.name, got, tt.want)
 		}
 	}
-	val, _ := acctm.GetAccountBalanceByID(common.Name("a123456789aeee"), id)
+	val, _ = acctm.GetAccountBalanceByID(common.Name("a123456789aeee"), id, 0)
 	if val.Cmp(big.NewInt(800)) != 0 {
 		t.Errorf("TestAccountManager_GetAccountBalanceByID = %v", val)
 	}
@@ -665,7 +625,7 @@ func TestAccountManager_GetAssetInfoByName(t *testing.T) {
 	type args struct {
 		name string
 	}
-	ast1, err := asset.NewAssetObject("ziz", "zz", big.NewInt(1000), 10, common.Name("a123456789aeee"), common.Name("a123456789aeee"), big.NewInt(1000))
+	ast1, err := asset.NewAssetObject("ziz", 0, "zz", big.NewInt(1000), 0, common.Name("a123456789aeee"), common.Name("a123456789aeee"), big.NewInt(1000), common.Name(""))
 	if err != nil {
 		t.Errorf("new asset object err")
 	}
@@ -706,7 +666,7 @@ func TestAccountManager_GetAssetInfoByID(t *testing.T) {
 		assetID uint64
 	}
 
-	ast1, err := asset.NewAssetObject("ziz", "zz", big.NewInt(1000), 10, common.Name("a123456789aeee"), common.Name("a123456789aeee"), big.NewInt(1000))
+	ast1, err := asset.NewAssetObject("ziz", 0, "zz", big.NewInt(1000), 0, common.Name("a123456789aeee"), common.Name("a123456789aeee"), big.NewInt(1000), common.Name(""))
 	if err != nil {
 		t.Errorf("new asset object err")
 	}
@@ -898,7 +858,7 @@ func TestAccountManager_GetBalanceByTime(t *testing.T) {
 			sdb: tt.fields.sdb,
 			ast: tt.fields.ast,
 		}
-		got, err := am.GetBalanceByTime(tt.args.accountName, tt.args.assetID, tt.args.time)
+		got, err := am.GetBalanceByTime(tt.args.accountName, tt.args.assetID, 0, tt.args.time)
 		if (err != nil) != tt.wantErr {
 			t.Errorf("%q. AccountManager.GetBalanceByTime() error = %v, wantErr %v", tt.name, err, tt.wantErr)
 			continue
@@ -1115,7 +1075,7 @@ func TestAccountManager_EnoughAccountBalance(t *testing.T) {
 		args    args
 		wantErr bool
 	}{
-		//
+		//amount = 1000
 		{"enough", fields{sdb, ast}, args{common.Name("a123456789aeee"), 1, big.NewInt(-2)}, true},
 		{"enough", fields{sdb, ast}, args{common.Name("a123456789aeee"), 1, big.NewInt(999)}, false},
 		{"notenough", fields{sdb, ast}, args{common.Name("a123456789aeee"), 1, big.NewInt(1001)}, true},
@@ -1133,7 +1093,7 @@ func TestAccountManager_EnoughAccountBalance(t *testing.T) {
 			t.Errorf("%q. AccountManager.EnoughAccountBalance() error = %v, wantErr %v", tt.name, err, tt.wantErr)
 		}
 	}
-	val, _ := acctm.GetAccountBalanceByID(common.Name("a123456789aeee"), 1)
+	val, _ := acctm.GetAccountBalanceByID(common.Name("a123456789aeee"), 1, 0)
 	if val.Cmp(big.NewInt(1000)) != 0 {
 		t.Logf("TestAccountManager_EnoughAccountBalance = %v", val)
 	}
@@ -1149,7 +1109,7 @@ func TestAccountManager_GetCode(t *testing.T) {
 	}
 	pubkey2 := new(common.PubKey)
 	acct, _ := acctm.GetAccountByName(common.Name("a123456789aeee"))
-	acctm.CreateAccount(common.Name("a123456789aeed"), common.Name("a123456789aeed"), 0, *pubkey2)
+	acctm.CreateAccount(common.Name("a123456789aeed"), common.Name("a123456789aeed"), 0, 0, *pubkey2)
 	acct.SetCode([]byte("abcde123456789"))
 	acctm.SetAccount(acct)
 	//t.Logf("EnoughAccountBalance asset id=%v : val=%v\n", 1, val)
@@ -1339,7 +1299,7 @@ func TestAccountManager_TransferAsset(t *testing.T) {
 		//
 		{"tranferok", fields{sdb, ast}, args{common.Name("a123456789aeee"), common.Name("a123456789aeed"), 1, big.NewInt(3)}, false},
 	}
-	val, err := acctm.GetAccountBalanceByID(common.Name("a123456789aeee"), 1)
+	val, err := acctm.GetAccountBalanceByID(common.Name("a123456789aeee"), 1, 0)
 	if err != nil {
 		t.Error("TransferAsset GetAccountBalanceByID err")
 	}
@@ -1356,7 +1316,7 @@ func TestAccountManager_TransferAsset(t *testing.T) {
 			t.Errorf("%q. AccountManager.TransferAsset() error = %v, wantErr %v", tt.name, err, tt.wantErr)
 		}
 	}
-	val1, err := acctm.GetAccountBalanceByID(common.Name("a123456789aeee"), 1)
+	val1, err := acctm.GetAccountBalanceByID(common.Name("a123456789aeee"), 1, 0)
 	if err != nil {
 		t.Error("TransferAsset GetAccountBalanceByID err")
 	}
@@ -1381,17 +1341,18 @@ func TestAccountManager_IssueAsset(t *testing.T) {
 	//if err != nil {
 	//	t.Fatal("IssueAsset err", err)
 	//}
-	ast1, err := asset.NewAssetObject("ziz0123456789ziz", "ziz", big.NewInt(2), 18, common.Name("a0123456789ziz"), common.Name("a0123456789ziz"), big.NewInt(100000))
+
+	ast1, err := asset.NewAssetObject("ziz0123456789ziz", 0, "ziz", big.NewInt(2), 18, common.Name("a123456789aeee"), common.Name("a0123456789ziz"), big.NewInt(100000), common.Name(""))
 	if err != nil {
 		t.Fatal("IssueAsset err", err)
 	}
 
-	//ast3, err := asset.NewAssetObject("ziz0123456789", "ziz", big.NewInt(2), 18, common.Name("a123456789aeee"))
-	//if err != nil {
-	//	t.Fatal("IssueAsset err", err)
-	//}
-
-	ast2, err := asset.NewAssetObject("ziz0123456789zi", "ziz", big.NewInt(2), 18, common.Name("a123456789aeee"), common.Name("a123456789aeee"), big.NewInt(2))
+	ast3, err := asset.NewAssetObject("ziz0123456789", 0, "ziz", big.NewInt(2), 18, common.Name("a123456777777"), common.Name("a123456789aeee"), big.NewInt(2), common.Name(""))
+	if err != nil {
+		t.Fatal("IssueAsset err", err)
+	}
+	//asset id =2
+	ast2, err := asset.NewAssetObject("ziz0123456789zi", 0, "ziz", big.NewInt(2), 18, common.Name("a123456789aeee"), common.Name("a123456789aeee"), big.NewInt(12000), common.Name(""))
 	if err != nil {
 		t.Fatal("IssueAsset err", err)
 	}
@@ -1409,6 +1370,7 @@ func TestAccountManager_IssueAsset(t *testing.T) {
 	}{
 		//
 		{"ownernotexist", fields{sdb, ast}, args{ast1}, true},
+		{"foundernotexist", fields{sdb, ast}, args{ast3}, true},
 		{"ownerexist", fields{sdb, ast}, args{ast2}, false},
 	}
 
@@ -1441,7 +1403,8 @@ func TestAccountManager_IncAsset2Acct(t *testing.T) {
 		wantErr bool
 	}{
 		//
-		{"accountexist", fields{sdb, ast}, args{common.Name("a0123456789ziz"), common.Name("a123456789aeee"), 2, big.NewInt(10)}, false},
+		{"over upperlimit", fields{sdb, ast}, args{common.Name("a123456789aeee"), common.Name("a123456789aeee"), 2, big.NewInt(11999)}, true},
+		{"accountexist", fields{sdb, ast}, args{common.Name("a123456789aeee"), common.Name("a123456789aeee"), 2, big.NewInt(10)}, false},
 		{"notexist", fields{sdb, ast}, args{common.Name("a0123456789ziz"), common.Name("a123456789aeef"), 2, big.NewInt(1)}, true},
 	}
 	for _, tt := range tests {
@@ -1494,8 +1457,8 @@ func TestAccountManager_Process(t *testing.T) {
 	}
 
 	inc := &IncAsset{
-		AssetId: 4,
-		Amount:  big.NewInt(100000000),
+		AssetId: 2,
+		Amount:  big.NewInt(100),
 		To:      common.Name("a123456789aeee"),
 	}
 	payload2, err := rlp.EncodeToBytes(inc)
@@ -1504,7 +1467,7 @@ func TestAccountManager_Process(t *testing.T) {
 	}
 
 	ast0 := &asset.AssetObject{
-		AssetId:    4,
+		AssetId:    2,
 		AssetName:  "abced99",
 		Symbol:     "aaa",
 		Amount:     big.NewInt(100000000),
@@ -1515,13 +1478,13 @@ func TestAccountManager_Process(t *testing.T) {
 		UpperLimit: big.NewInt(1000000000),
 	}
 	ast1 := &asset.AssetObject{
-		AssetId:    4,
+		AssetId:    2,
 		AssetName:  "abced99",
 		Symbol:     "aaa",
 		Amount:     big.NewInt(100000000),
 		Decimals:   2,
-		Founder:    common.Name("a123456789addd"),
-		Owner:      common.Name("a123456789addd"),
+		Founder:    common.Name(sysName),
+		Owner:      common.Name(sysName),
 		AddIssue:   big.NewInt(0),
 		UpperLimit: big.NewInt(1000000000),
 	}
@@ -1536,6 +1499,8 @@ func TestAccountManager_Process(t *testing.T) {
 	pubkey, _ := GeneragePubKey()
 	pubkey1, _ := GeneragePubKey()
 	aa := &AccountAction{
+		AccountName: common.Name("a123456789addd"),
+		Founder:     common.Name(""),
 		ChargeRatio: 10,
 		PublicKey:   pubkey,
 	}
@@ -1544,6 +1509,8 @@ func TestAccountManager_Process(t *testing.T) {
 		panic("rlp payload err")
 	}
 	aa1 := &AccountAction{
+		AccountName: common.Name("a123456789addd"),
+		Founder:     common.Name(""),
 		ChargeRatio: 99,
 		PublicKey:   pubkey1,
 	}
@@ -1551,12 +1518,24 @@ func TestAccountManager_Process(t *testing.T) {
 	if err != nil {
 		panic("rlp payload err")
 	}
+	ca1 := common.NewAuthor(common.Name("a123456789aeee"), 1)
+	autha1 := &AuthorAction{ActionType: 0, Author: ca1}
+	ca2 := common.NewAuthor(common.Name("a123456789aeee"), 2)
+	autha2 := &AuthorAction{ActionType: 1, Author: ca2}
+
+	aaa1 := &AccountAuthorAction{Threshold: 10, AuthorActions: []*AuthorAction{autha1, autha2}}
+	payload5, err := rlp.EncodeToBytes(aaa1)
+	if err != nil {
+		panic("rlp payload err")
+	}
+
+	action := types.NewAction(types.IssueAsset, common.Name("a123456789aeee"), common.Name(sysName), 1, 1, 0, big.NewInt(0), payload)
+	action1 := types.NewAction(types.IncreaseAsset, common.Name("a123456789aeee"), common.Name(sysName), 1, 1, 2, big.NewInt(0), payload2)
+	action2 := types.NewAction(types.UpdateAsset, common.Name("a123456789aeee"), common.Name(sysName), 1, 1, 2, big.NewInt(0), payload1)
+	action3 := types.NewAction(types.CreateAccount, common.Name("a123456789aeee"), common.Name(sysName), 1, 1, 2, big.NewInt(10), payload3)
+	action4 := types.NewAction(types.UpdateAccount, common.Name("a123456789addd"), common.Name(sysName), 1, 1, 2, big.NewInt(0), payload4)
+	action5 := types.NewAction(types.UpdateAccountAuthor, common.Name("a123456789addd"), common.Name(sysName), 1, 1, 2, big.NewInt(0), payload5)
 
-	action := types.NewAction(types.IssueAsset, common.Name("a123456789aeee"), common.Name("a123456789aeee"), 1, 1, 0, big.NewInt(2), payload)
-	action1 := types.NewAction(types.IncreaseAsset, common.Name("a123456789aeee"), common.Name("a123456789aeee"), 1, 1, 2, big.NewInt(0), payload2)
-	action2 := types.NewAction(types.SetAssetOwner, common.Name("a123456789aeee"), common.Name("a123456789addd"), 1, 1, 2, big.NewInt(0), payload1)
-	action3 := types.NewAction(types.CreateAccount, common.Name("a123456789aeee"), common.Name("a123456789addd"), 1, 1, 2, big.NewInt(10), payload3)
-	action4 := types.NewAction(types.UpdateAccount, common.Name("a123456789addd"), common.Name("a123456789addd"), 1, 1, 2, big.NewInt(0), payload4)
 	//action5 := types.NewAction(types.DeleteAccount, common.Name("123asdf2"), common.Name("123asdf2"), 1, 1, 2, big.NewInt(0), pubkey1[:])
 	//action6 := types.NewAction(types.Transfer, common.Name("a123456789aeee"), common.Name("a123456789aeee"), 1, 1, 2, big.NewInt(1), pubkey1[:])
 	//action7 := types.NewAction(types.Transfer, common.Name("a123456789addd"), common.Name("a123456789aeee"), 1, 1, 2, big.NewInt(1), payload)
@@ -1571,18 +1550,21 @@ func TestAccountManager_Process(t *testing.T) {
 		{"issue", fields{sdb, ast}, args{action}, false},
 		{"increase", fields{sdb, ast}, args{action1}, false},
 		{"createaccount", fields{sdb, ast}, args{action3}, false},
-		{"setowner", fields{sdb, ast}, args{action2}, false},
+		{"updateasset", fields{sdb, ast}, args{action2}, false},
 		{"updateaccount", fields{sdb, ast}, args{action4}, false},
+		{"updateaccountauthor", fields{sdb, ast}, args{action5}, false},
+
 		//{"deleteaccount", fields{sdb, ast}, args{action5}, false},
 		//{"transfer2self", fields{sdb, ast}, args{action6}, false},
 		//{"transfer", fields{sdb, ast}, args{action7}, false},
 	}
+
 	for _, tt := range tests {
 		am := &AccountManager{
 			sdb: tt.fields.sdb,
 			ast: tt.fields.ast,
 		}
-		if err := am.Process(tt.args.action); (err != nil) != tt.wantErr {
+		if _, err := am.Process(&types.AccountManagerContext{Action: tt.args.action, Number: 0}); (err != nil) != tt.wantErr {
 			t.Errorf("%q. AccountManager.Process() error = %v, wantErr %v", tt.name, err, tt.wantErr)
 		}
 	}
@@ -1592,13 +1574,13 @@ func TestAccountManager_Process(t *testing.T) {
 		t.Error("Process issue asset failure")
 	}
 	//t.Logf("issue ok id=%v", asset2.AssetId)
-	if asset2.Amount.Cmp(big.NewInt(200000000)) != 0 {
+	if asset2.Amount.Cmp(big.NewInt(100000000)) != 0 {
 		t.Errorf("Process increase asset failure amount=%v", asset2.Amount)
 	}
-	if asset2.GetAssetOwner() != "a123456789addd" {
+	if asset2.GetAssetOwner() != "a123456789aeee" {
 		t.Errorf("Process set asset owner failure =%v", asset2.GetAssetName())
 	}
-	val, err := acctm.GetAccountBalanceByID(common.Name("a123456789aeee"), 1)
+	val, err := acctm.GetAccountBalanceByID(common.Name("a123456789aeee"), 1, 0)
 	if err != nil {
 		t.Error("Process GetAccountBalanceByID err")
 	}
@@ -1608,7 +1590,7 @@ func TestAccountManager_Process(t *testing.T) {
 	if err != nil {
 		t.Error("Process GetAccountByName err")
 	}
-	if !ac.IsDestoryed() {
+	if !ac.IsDestroyed() {
 		//t.Error("Process delete account failure")
 	}
 
@@ -1619,12 +1601,253 @@ func TestAccountManager_Process(t *testing.T) {
 	if ac1 == nil {
 		t.Error("Process create account err")
 	}
-	if bytes.Compare(ac1.PublicKey.Bytes(), pubkey1[:]) != 0 {
-		t.Error("Process update account failure")
+	if ac1.Authors[1].Weight != 2 {
+		t.Errorf("Process update accountauthor fail")
 	}
 	val, err = ac1.GetBalanceByID(1)
 	if val.Cmp(big.NewInt(10)) != 0 {
 		t.Errorf("Process transfer  failure=%v", val)
 	}
+	ca3 := common.NewAuthor(common.Name("a123456789aeee"), 1)
+	autha3 := &AuthorAction{ActionType: 2, Author: ca3}
+	aaa2 := &AccountAuthorAction{AuthorActions: []*AuthorAction{autha3}}
+
+	payload6, err := rlp.EncodeToBytes(aaa2)
+	if err != nil {
+		panic("rlp payload err")
+	}
+	action6 := types.NewAction(types.UpdateAccountAuthor, common.Name("a123456789addd"), common.Name(sysName), 1, 1, 2, big.NewInt(0), payload6)
+
+	tests = []struct {
+		name    string
+		fields  fields
+		args    args
+		wantErr bool
+	}{
+		{"updateaccountauthor", fields{sdb, ast}, args{action6}, false},
+	}
+	for _, tt := range tests {
+		am := &AccountManager{
+			sdb: tt.fields.sdb,
+			ast: tt.fields.ast,
+		}
+		if _, err := am.Process(&types.AccountManagerContext{Action: tt.args.action, Number: 0}); (err != nil) != tt.wantErr {
+			t.Errorf("%q. AccountManager.Process() error = %v, wantErr %v", tt.name, err, tt.wantErr)
+		}
+	}
+	ac2, err := acctm.GetAccountByName(common.Name("a123456789addd"))
+	if err != nil {
+		t.Error("Process GetAccountByName err")
+	}
+	if ac2 == nil {
+		t.Error("Process create account err")
+	}
+	if len(ac2.Authors) != 1 && ac2.Threshold != 10 {
+		t.Errorf("Process delete accountauthor fail")
+	}
+
+}
+
+func TestAccountManager_SubAccount(t *testing.T) {
+
+	type fields struct {
+		sdb SdbIf
+		ast *asset.Asset
+	}
+	type args struct {
+		action *types.Action
+	}
+
+	pubkey, _ := GeneragePubKey()
+	a := &AccountAction{
+		AccountName: common.Name("bbbbbbbb"),
+		Founder:     common.Name(""),
+		ChargeRatio: 10,
+		PublicKey:   pubkey,
+	}
+	payload, err := rlp.EncodeToBytes(a)
+	if err != nil {
+		panic("rlp payload err")
+	}
+
+	a1 := &AccountAction{
+		AccountName: common.Name("bbbbbbbb.cc"),
+		Founder:     common.Name(""),
+		ChargeRatio: 10,
+		PublicKey:   pubkey,
+	}
+	payload1, err := rlp.EncodeToBytes(a1)
+	if err != nil {
+		panic("rlp payload err")
+	}
+
+	a2 := &AccountAction{
+		AccountName: common.Name("bbbbbbbb.dd"),
+		Founder:     common.Name(""),
+		ChargeRatio: 10,
+		PublicKey:   pubkey,
+	}
+	payload2, err := rlp.EncodeToBytes(a2)
+	if err != nil {
+		panic("rlp payload err")
+	}
+
+	a3 := &AccountAction{
+		AccountName: common.Name("bbbbbbbb.ccc"),
+		Founder:     common.Name(""),
+		ChargeRatio: 10,
+		PublicKey:   pubkey,
+	}
+	payload3, err := rlp.EncodeToBytes(a3)
+	if err != nil {
+		panic("rlp payload err")
+	}
+
+	a4 := &AccountAction{
+		AccountName: common.Name("bbbbbbbb.cc.dd"),
+		Founder:     common.Name(""),
+		ChargeRatio: 10,
+		PublicKey:   pubkey,
+	}
+	payload4, err := rlp.EncodeToBytes(a4)
+	if err == nil {
+		panic("rlp payload err")
+	}
+
+	a5 := &AccountAction{
+		AccountName: common.Name("bbbbbbbb.cc.ee"),
+		Founder:     common.Name(""),
+		ChargeRatio: 10,
+		PublicKey:   pubkey,
+	}
+	payload5, err := rlp.EncodeToBytes(a5)
+	if err == nil {
+		panic("rlp payload err")
+	}
+
+	a6 := &AccountAction{
+		AccountName: common.Name("bbbbbbbb.cc.ff"),
+		Founder:     common.Name(""),
+		ChargeRatio: 10,
+		PublicKey:   pubkey,
+	}
+	payload6, err := rlp.EncodeToBytes(a6)
+	if err == nil {
+		panic("rlp payload err")
+	}
+
+	a7 := &AccountAction{
+		AccountName: common.Name("cccccccc"),
+		Founder:     common.Name(""),
+		ChargeRatio: 10,
+		PublicKey:   pubkey,
+	}
+	payload7, err := rlp.EncodeToBytes(a7)
+	if err != nil {
+		panic("rlp payload err")
+	}
+
+	a8 := &AccountAction{
+		AccountName: common.Name("bbbbbbbb.ee"),
+		Founder:     common.Name(""),
+		ChargeRatio: 10,
+		PublicKey:   pubkey,
+	}
+	payload8, err := rlp.EncodeToBytes(a8)
+	if err != nil {
+		panic("rlp payload err")
+	}
+
+	a9 := &AccountAction{
+		AccountName: common.Name("bbbbbbbb."),
+		Founder:     common.Name(""),
+		ChargeRatio: 10,
+		PublicKey:   pubkey,
+	}
+	_, err = rlp.EncodeToBytes(a9)
+	if err == nil {
+		panic("rlp payload err")
+	}
+
+	a10 := &AccountAction{
+		AccountName: common.Name("bbbbbb"),
+		Founder:     common.Name(""),
+		ChargeRatio: 10,
+		PublicKey:   pubkey,
+	}
+	_, err = rlp.EncodeToBytes(a10)
+	if err == nil {
+		panic("rlp payload err")
+	}
+
+	a11 := &AccountAction{
+		AccountName: common.Name("bbbbbbbbbbbbbbbbb"),
+		Founder:     common.Name(""),
+		ChargeRatio: 10,
+		PublicKey:   pubkey,
+	}
+	_, err = rlp.EncodeToBytes(a11)
+	if err == nil {
+		panic("rlp payload err")
+	}
+
+	a12 := &AccountAction{
+		AccountName: common.Name("bbbbbbbbbbbbbb.."),
+		Founder:     common.Name(""),
+		ChargeRatio: 10,
+		PublicKey:   pubkey,
+	}
+	_, err = rlp.EncodeToBytes(a12)
+	if err == nil {
+		panic("rlp payload err")
+	}
+
+	a13 := &AccountAction{
+		AccountName: common.Name("bbbbbbbbbbbbbbbb.aaa.."),
+		Founder:     common.Name(""),
+		ChargeRatio: 10,
+		PublicKey:   pubkey,
+	}
+	_, err = rlp.EncodeToBytes(a13)
+	if err == nil {
+		panic("rlp payload err")
+	}
+
+	action := types.NewAction(types.CreateAccount, common.Name("a123456789aeee"), common.Name(sysName), 1, 1, 2, big.NewInt(40), payload)
+	action1 := types.NewAction(types.CreateAccount, common.Name("bbbbbbbb"), common.Name(sysName), 1, 1, 2, big.NewInt(10), payload1)
+	action2 := types.NewAction(types.CreateAccount, common.Name("bbbbbbbb"), common.Name(sysName), 1, 1, 2, big.NewInt(10), payload2)
+	action3 := types.NewAction(types.CreateAccount, common.Name("bbbbbbbb"), common.Name(sysName), 1, 1, 2, big.NewInt(10), payload3)
+	action4 := types.NewAction(types.CreateAccount, common.Name("bbbbbbbb"), common.Name(sysName), 1, 1, 2, big.NewInt(10), payload4)
+	action5 := types.NewAction(types.CreateAccount, common.Name("bbbbbbbb.cc"), common.Name(sysName), 1, 1, 2, big.NewInt(10), payload5)
+	action6 := types.NewAction(types.CreateAccount, common.Name("bbbbbbbb.ccc"), common.Name(sysName), 1, 1, 2, big.NewInt(10), payload6)
+	action7 := types.NewAction(types.CreateAccount, common.Name("a123456789aeee"), common.Name(sysName), 1, 1, 2, big.NewInt(30), payload7)
+	action8 := types.NewAction(types.CreateAccount, common.Name("cccccccc"), common.Name(sysName), 1, 1, 2, big.NewInt(30), payload8)
+
+	tests := []struct {
+		name    string
+		fields  fields
+		args    args
+		wantErr bool
+	}{
+		{"createaccount", fields{sdb, ast}, args{action}, false},
+		{"createsubaccount1", fields{sdb, ast}, args{action1}, false},
+		{"createsubaccount2", fields{sdb, ast}, args{action2}, false},
+		{"createsubaccount3", fields{sdb, ast}, args{action3}, false},
+		{"createsubaccount4", fields{sdb, ast}, args{action4}, true},
+		{"createsubaccount5", fields{sdb, ast}, args{action5}, true},
+		{"createsubaccount6", fields{sdb, ast}, args{action6}, true},
+		{"createsubaccount7", fields{sdb, ast}, args{action7}, false},
+		{"createsubaccount8", fields{sdb, ast}, args{action8}, true},
+	}
+
+	for _, tt := range tests {
+		am := &AccountManager{
+			sdb: tt.fields.sdb,
+			ast: tt.fields.ast,
+		}
+		if _, err := am.Process(&types.AccountManagerContext{Action: tt.args.action, Number: 0}); (err != nil) != tt.wantErr {
+			t.Errorf("%q. AccountManager.Process() error = %v, wantErr %v", tt.name, err, tt.wantErr)
+		}
+	}
 
 }
diff --git a/test/systemtestcase/rpc/globalConfig.go b/accountmanager/config.go
similarity index 56%
rename from test/systemtestcase/rpc/globalConfig.go
rename to accountmanager/config.go
index 0c808556..9e074092 100644
--- a/test/systemtestcase/rpc/globalConfig.go
+++ b/accountmanager/config.go
@@ -14,18 +14,20 @@
 // You should have received a copy of the GNU General Public License
 // along with this program. If not, see <http://www.gnu.org/licenses/>.
 
-package rpc
+package accountmanager
 
-import (
-	"github.com/fractalplatform/fractal/common"
-	"github.com/fractalplatform/fractal/crypto"
-)
+// Config Account Level
+type Config struct {
+	AccountNameLevel     uint64 `json:"accountNameLevel"`
+	AccountNameLength    uint64 `json:"accountNameLength"`
+	SubAccountNameLength uint64 `json:"subAccountNameLength"`
+}
 
-var (
-	SystemAccountPriKey, _ = crypto.HexToECDSA("289c2857d4598e37fb9647507e47a309d6133539bf21a8b9cb6df88fd5232032")
-	SystemAccountPubKey    = common.HexToPubKey("0x047db227d7094ce215c3a0f57e1bcc732551fe351f94249471934567e0f5dc1bf795962b8cccb87a2eb56b29fbe37d614e2f4c3c45b789ae4f1f51f4cb21972ffd")
-	Gaslimit               = uint64(2000000)
-	SystemAccount          = "ftsystemio"
-	Minernonce             = uint64(0)
-	MaxTxNumInTxpool       = 40960 + 4096
-)
+// DefaultAccountNameConf return account config
+func DefaultAccountNameConf() *Config {
+	return &Config{
+		AccountNameLevel:     0,
+		AccountNameLength:    16,
+		SubAccountNameLength: 0,
+	}
+}
diff --git a/accountmanager/error.go b/accountmanager/error.go
index 0268462a..e0d3af62 100644
--- a/accountmanager/error.go
+++ b/accountmanager/error.go
@@ -19,24 +19,34 @@ package accountmanager
 import "errors"
 
 var (
-	ErrInsufficientBalance  = errors.New("insufficient balance")
-	ErrNewAccountErr        = errors.New("new account err")
-	ErrAssetIDInvalid       = errors.New("asset id invalid")
-	ErrCreateAccountError   = errors.New("create account error")
-	ErrAccountIsExist       = errors.New("account is exist")
-	ErrAccountIsDestroy     = errors.New("account is destory")
-	ErrAccountNotExist      = errors.New("account not exist")
-	ErrHashIsEmpty          = errors.New("hash is empty")
-	ErrkeyNotSame           = errors.New("key not same")
-	ErrAccountNameInvalid   = errors.New("account name is Invalid")
-	ErrInvalidPubKey        = errors.New("invalid public key")
-	ErrAccountIsNil         = errors.New("account object is empty")
-	ErrCodeIsEmpty          = errors.New("code is empty")
-	ErrAmountValueInvalid   = errors.New("amount value is invalid")
-	ErrAccountAssetNotExist = errors.New("account asset not exist")
-	ErrUnkownTxType         = errors.New("not support action type")
-	ErrTimeInvalid          = errors.New("input time invalid ")
-	ErrTimeTypeInvalid      = errors.New("get snapshot time type invalid ")
-	ErrChargeRatioInvalid   = errors.New("charge ratio value invalid ")
-	ErrSnapshotTimeNotExist = errors.New("next snapshot time not exist")
+	ErrInsufficientBalance    = errors.New("insufficient balance")
+	ErrNewAccountErr          = errors.New("new account err")
+	ErrAssetIDInvalid         = errors.New("asset id invalid")
+	ErrCreateAccountError     = errors.New("create account error")
+	ErrAccountInvaid          = errors.New("account not permission")
+	ErrAccountIsExist         = errors.New("account is exist")
+	ErrNameIsExist            = errors.New("name is exist")
+	ErrAccountIsDestroy       = errors.New("account is destroy")
+	ErrAccountNotExist        = errors.New("account not exist")
+	ErrHashIsEmpty            = errors.New("hash is empty")
+	ErrkeyNotSame             = errors.New("key not same")
+	ErrAccountNameInvalid     = errors.New("account name is Invalid")
+	ErrInvalidPubKey          = errors.New("invalid public key")
+	ErrAccountIsNil           = errors.New("account object is empty")
+	ErrCodeIsEmpty            = errors.New("code is empty")
+	ErrAmountValueInvalid     = errors.New("amount value is invalid")
+	ErrAccountAssetNotExist   = errors.New("account asset not exist")
+	ErrUnkownTxType           = errors.New("not support action type")
+	ErrTimeInvalid            = errors.New("input time invalid ")
+	ErrTimeTypeInvalid        = errors.New("get snapshot time type invalid ")
+	ErrChargeRatioInvalid     = errors.New("charge ratio value invalid ")
+	ErrSnapshotTimeNotExist   = errors.New("next snapshot time not exist")
+	ErrAccountManagerNotExist = errors.New("account manager name not exist")
+	ErrAmountMustZero         = errors.New("amount must be zero")
+	ErrToNameInvalid          = errors.New("action to name(Recipient) invalid")
+	ErrCounterNotExist        = errors.New("account global counter not exist")
+	ErrAccountIdInvalid       = errors.New("account id invalid")
+	ErrInvalidReceiptAsset    = errors.New("invalid receipt of asset")
+	ErrInvalidReceipt         = errors.New("invalid receipt")
+	ErrNegativeValue          = errors.New("negative value")
 )
diff --git a/accountmanager/interface.go b/accountmanager/interface.go
index 9c47610e..a9697012 100644
--- a/accountmanager/interface.go
+++ b/accountmanager/interface.go
@@ -49,8 +49,8 @@ type IAccount interface {
 	IsSuicided() bool
 	SetSuicide()
 	//
-	IsDestoryed()
-	SetDestory()
+	IsDestroyed()
+	SetDestroy()
 }
 
 //export account manager interface
diff --git a/asset/asset.go b/asset/asset.go
index 2cbcabec..d2afe9dc 100644
--- a/asset/asset.go
+++ b/asset/asset.go
@@ -17,17 +17,20 @@
 package asset
 
 import (
+	"fmt"
+	"math/big"
+	"strconv"
+
+	"github.com/ethereum/go-ethereum/log"
 	"github.com/fractalplatform/fractal/common"
-	"github.com/fractalplatform/fractal/params"
 	"github.com/fractalplatform/fractal/state"
 	"github.com/fractalplatform/fractal/utils/rlp"
-	"math/big"
-	"strconv"
 )
 
-var sysAcct string
+//AssetManager is used to access asset
+var assetManagerName = "sysAccount"
+
 var (
-	//sysAccount is used to access asset
 	assetCountPrefix  = "assetCount"
 	assetNameIdPrefix = "assetNameId"
 	assetObjectPrefix = "assetDefinitionObject"
@@ -37,16 +40,45 @@ type Asset struct {
 	sdb *state.StateDB
 }
 
-//New create Asset
+func SetAssetNameConfig(config *Config) bool {
+	if config == nil {
+		return false
+	}
+
+	if config.AssetNameLevel < 0 || config.AssetNameLength <= 2 {
+		return false
+	}
+
+	if config.AssetNameLevel > 0 {
+		if config.SubAssetNameLength < 1 {
+			return false
+		}
+	}
+
+	common.SetAssetNameCheckRule(config.AssetNameLevel, config.AssetNameLength, config.SubAssetNameLength)
+	return true
+}
+
+//SetAssetMangerName  set the global asset manager name
+func SetAssetMangerName(name common.Name) bool {
+	if common.IsValidAccountName(name.String()) {
+		assetManagerName = name.String()
+		return true
+	}
+	return false
+}
+
+//NewAsset New create Asset
 func NewAsset(sdb *state.StateDB) *Asset {
 	asset := Asset{
 		sdb: sdb,
 	}
-	if len(params.DefaultChainconfig.SysName) > 0 {
-		sysAcct = params.DefaultChainconfig.SysName.String()
-	} else {
-		sysAcct = "sysAccount"
+
+	if len(assetManagerName) == 0 {
+		log.Error("NewAsset error", "name", ErrAssetManagerNotExist, assetManagerName)
+		return nil
 	}
+
 	asset.InitAssetCount()
 	return &asset
 }
@@ -65,7 +97,7 @@ func (a *Asset) GetAssetObjectByTime(assetID uint64, time uint64) (*AssetObject,
 	if assetID == 0 {
 		return nil, ErrAssetIdInvalid
 	}
-	b, err := a.sdb.GetSnapshot(sysAcct, assetObjectPrefix+strconv.FormatUint(assetID, 10), time)
+	b, err := a.sdb.GetSnapshot(assetManagerName, assetObjectPrefix+strconv.FormatUint(assetID, 10), time)
 	if err != nil {
 		return nil, err
 	}
@@ -79,12 +111,12 @@ func (a *Asset) GetAssetObjectByTime(assetID uint64, time uint64) (*AssetObject,
 	return &asset, nil
 }
 
-//get assset id by asset name
+//GetAssetIdByName get assset id by asset name
 func (a *Asset) GetAssetIdByName(assetName string) (uint64, error) {
 	if assetName == "" {
 		return 0, ErrAssetNameEmpty
 	}
-	b, err := a.sdb.Get(sysAcct, assetNameIdPrefix+assetName)
+	b, err := a.sdb.Get(assetManagerName, assetNameIdPrefix+assetName)
 	if err != nil {
 		return 0, err
 	}
@@ -98,7 +130,7 @@ func (a *Asset) GetAssetIdByName(assetName string) (uint64, error) {
 	return assetID, nil
 }
 
-//get asset founder by id
+//GetAssetFounderById get asset founder by id
 func (a *Asset) GetAssetFounderById(id uint64) (common.Name, error) {
 	ao, err := a.GetAssetObjectById(id)
 	if err != nil {
@@ -107,12 +139,12 @@ func (a *Asset) GetAssetFounderById(id uint64) (common.Name, error) {
 	return ao.GetAssetFounder(), nil
 }
 
-//get asset by asset id
+//GetAssetObjectById get asset by asset id
 func (a *Asset) GetAssetObjectById(id uint64) (*AssetObject, error) {
 	if id == 0 {
 		return nil, ErrAssetIdInvalid
 	}
-	b, err := a.sdb.Get(sysAcct, assetObjectPrefix+strconv.FormatUint(id, 10))
+	b, err := a.sdb.Get(assetManagerName, assetObjectPrefix+strconv.FormatUint(id, 10))
 	if err != nil {
 		return nil, err
 	}
@@ -128,7 +160,7 @@ func (a *Asset) GetAssetObjectById(id uint64) (*AssetObject, error) {
 
 //get asset total count
 func (a *Asset) getAssetCount() (uint64, error) {
-	b, err := a.sdb.Get(sysAcct, assetCountPrefix)
+	b, err := a.sdb.Get(assetManagerName, assetCountPrefix)
 	if err != nil {
 		return 0, err
 	}
@@ -154,12 +186,12 @@ func (a *Asset) InitAssetCount() {
 		if err != nil {
 			panic(err)
 		}
-		a.sdb.Put(sysAcct, assetCountPrefix, b)
+		a.sdb.Put(assetManagerName, assetCountPrefix, b)
 	}
 	return
 }
 
-//
+//GetAllAssetObject get all asset
 func (a *Asset) GetAllAssetObject() ([]*AssetObject, error) {
 	assetCount, err := a.getAssetCount()
 	if err != nil {
@@ -173,12 +205,12 @@ func (a *Asset) GetAllAssetObject() ([]*AssetObject, error) {
 		if err != nil {
 			return nil, err
 		}
-		assets[i] = asset
+		assets[i-1] = asset
 	}
 	return assets, nil
 }
 
-//get asset object by name
+//GetAssetObjectByName get asset object by name
 func (a *Asset) GetAssetObjectByName(assetName string) (*AssetObject, error) {
 	assetID, err := a.GetAssetIdByName(assetName)
 	if err != nil {
@@ -187,7 +219,7 @@ func (a *Asset) GetAssetObjectByName(assetName string) (*AssetObject, error) {
 	return a.GetAssetObjectById(assetID)
 }
 
-//add new asset object and store into database
+//addNewAssetObject add new asset object and store into database
 func (a *Asset) addNewAssetObject(ao *AssetObject) (uint64, error) {
 	if ao == nil {
 		return 0, ErrAssetObjectEmpty
@@ -209,19 +241,15 @@ func (a *Asset) addNewAssetObject(ao *AssetObject) (uint64, error) {
 	if err != nil {
 		return 0, err
 	}
-	//store assetCount
-	b, err := rlp.EncodeToBytes(&assetCount)
-	if err != nil {
-		return 0, err
-	}
 
-	a.sdb.Put(sysAcct, assetObjectPrefix+strconv.FormatUint(assetCount, 10), aobject)
-	a.sdb.Put(sysAcct, assetNameIdPrefix+ao.GetAssetName(), aid)
-	a.sdb.Put(sysAcct, assetCountPrefix, b)
+	a.sdb.Put(assetManagerName, assetObjectPrefix+strconv.FormatUint(assetCount, 10), aobject)
+	a.sdb.Put(assetManagerName, assetNameIdPrefix+ao.GetAssetName(), aid)
+	//store assetCount
+	a.sdb.Put(assetManagerName, assetCountPrefix, aid)
 	return assetCount, nil
 }
 
-//add an asset and store into database
+//SetAssetObject store an asset into database
 func (a *Asset) SetAssetObject(ao *AssetObject) error {
 	if ao == nil {
 		return ErrAssetObjectEmpty
@@ -234,11 +262,11 @@ func (a *Asset) SetAssetObject(ao *AssetObject) error {
 	if err != nil {
 		return err
 	}
-	a.sdb.Put(sysAcct, assetObjectPrefix+strconv.FormatUint(assetId, 10), b)
+	a.sdb.Put(assetManagerName, assetObjectPrefix+strconv.FormatUint(assetId, 10), b)
 	return nil
 }
 
-//Issue Asset Object
+//IssueAssetObject Issue Asset Object
 func (a *Asset) IssueAssetObject(ao *AssetObject) (uint64, error) {
 	if ao == nil {
 		return 0, ErrAssetObjectEmpty
@@ -257,8 +285,12 @@ func (a *Asset) IssueAssetObject(ao *AssetObject) (uint64, error) {
 	return assetID, nil
 }
 
-//issue asset
-func (a *Asset) IssueAsset(assetName string, symbol string, amount *big.Int, dec uint64, founder common.Name, owner common.Name, limit *big.Int) error {
+//IssueAsset issue asset
+func (a *Asset) IssueAsset(assetName string, number uint64, symbol string, amount *big.Int, dec uint64, founder common.Name, owner common.Name, limit *big.Int, contract common.Name) error {
+	if !common.IsValidAssetName(assetName) {
+		return fmt.Errorf("%s is invalid", assetName)
+	}
+
 	assetId, err := a.GetAssetIdByName(assetName)
 	if err != nil {
 		return err
@@ -266,7 +298,8 @@ func (a *Asset) IssueAsset(assetName string, symbol string, amount *big.Int, dec
 	if assetId > 0 {
 		return ErrAssetIsExist
 	}
-	ao, err := NewAssetObject(assetName, symbol, amount, dec, founder, owner, limit)
+
+	ao, err := NewAssetObject(assetName, number, symbol, amount, dec, founder, owner, limit, contract)
 	if err != nil {
 		return err
 	}
@@ -277,8 +310,8 @@ func (a *Asset) IssueAsset(assetName string, symbol string, amount *big.Int, dec
 	return nil
 }
 
-//destory asset
-func (a *Asset) DestoryAsset(accountName common.Name, assetId uint64, amount *big.Int) error {
+//DestroyAsset destroy asset
+func (a *Asset) DestroyAsset(accountName common.Name, assetId uint64, amount *big.Int) error {
 	if accountName == "" {
 		return ErrAccountNameNull
 	}
@@ -295,16 +328,15 @@ func (a *Asset) DestoryAsset(accountName common.Name, assetId uint64, amount *bi
 	if asset == nil {
 		return ErrAssetNotExist
 	}
-	if asset.GetAssetOwner() != accountName {
-		return ErrOwnerMismatch
-	}
 
-	//if asset.GetAssetAmount().Cmp(amount) < 0{
-	//	return ErrAssetAmountZero
-	//}
+	//everyone can destory asset
+	// if asset.GetAssetOwner() != accountName {
+	// 	return ErrOwnerMismatch
+	// }
+
 	var total *big.Int
 	if total = new(big.Int).Sub(asset.GetAssetAmount(), amount); total.Cmp(big.NewInt(0)) < 0 {
-		return ErrDestoryLimit
+		return ErrDestroyLimit
 	}
 	asset.SetAssetAmount(total)
 	err = a.SetAssetObject(asset)
@@ -314,7 +346,7 @@ func (a *Asset) DestoryAsset(accountName common.Name, assetId uint64, amount *bi
 	return nil
 }
 
-//increase asset
+//IncreaseAsset increase asset, upperlimit == 0 means no upper limit
 func (a *Asset) IncreaseAsset(accountName common.Name, assetId uint64, amount *big.Int) error {
 	if accountName == "" {
 		return ErrAccountNameNull
@@ -335,16 +367,23 @@ func (a *Asset) IncreaseAsset(accountName common.Name, assetId uint64, amount *b
 	if asset.GetAssetOwner() != accountName {
 		return ErrOwnerMismatch
 	}
+
+	//check AddIssue > UpperLimit
 	var AddIssue *big.Int
-	if AddIssue = new(big.Int).Add(asset.GetAssetAddIssue(), amount); AddIssue.Cmp(asset.GetUpperLimit()) > 0 {
+	AddIssue = new(big.Int).Add(asset.GetAssetAddIssue(), amount)
+	if asset.GetUpperLimit().Cmp(big.NewInt(0)) > 0 && AddIssue.Cmp(asset.GetUpperLimit()) > 0 {
 		return ErrUpperLimit
 	}
 	asset.SetAssetAddIssue(AddIssue)
+
+	//check Amount > UpperLimit
 	var total *big.Int
-	if total = new(big.Int).Add(asset.GetAssetAmount(), amount); total.Cmp(asset.GetUpperLimit()) > 0 {
+	total = new(big.Int).Add(asset.GetAssetAmount(), amount)
+	if asset.GetUpperLimit().Cmp(big.NewInt(0)) > 0 && total.Cmp(asset.GetUpperLimit()) > 0 {
 		return ErrUpperLimit
 	}
 	asset.SetAssetAmount(total)
+	//save
 	err = a.SetAssetObject(asset)
 	if err != nil {
 		return err
@@ -352,8 +391,8 @@ func (a *Asset) IncreaseAsset(accountName common.Name, assetId uint64, amount *b
 	return nil
 }
 
-//change asset owner
-func (a *Asset) SetAssetNewOwner(accountName common.Name, assetId uint64, newOwner common.Name) error {
+//UpdateAsset change asset info
+func (a *Asset) UpdateAsset(accountName common.Name, assetId uint64, Owner common.Name, founderName common.Name, contractName common.Name) error {
 	if accountName == "" {
 		return ErrAccountNameNull
 	}
@@ -370,12 +409,14 @@ func (a *Asset) SetAssetNewOwner(accountName common.Name, assetId uint64, newOwn
 	if asset.GetAssetOwner() != accountName {
 		return ErrOwnerMismatch
 	}
-	asset.SetAssetOwner(newOwner)
+	asset.SetAssetOwner(Owner)
+	asset.SetAssetFounder(founderName)
+	asset.SetAssetContract(contractName)
 	return a.SetAssetObject(asset)
 }
 
-//asset founder
-func (a *Asset) SetAssetFounder(accountName common.Name, assetId uint64, founderName common.Name) error {
+//SetAssetNewOwner change asset owner
+func (a *Asset) SetAssetNewOwner(accountName common.Name, assetId uint64, newOwner common.Name) error {
 	if accountName == "" {
 		return ErrAccountNameNull
 	}
@@ -392,6 +433,73 @@ func (a *Asset) SetAssetFounder(accountName common.Name, assetId uint64, founder
 	if asset.GetAssetOwner() != accountName {
 		return ErrOwnerMismatch
 	}
-	asset.SetAssetFounder(founderName)
+	asset.SetAssetOwner(newOwner)
 	return a.SetAssetObject(asset)
 }
+
+//SetAssetFounder asset founder
+// func (a *Asset) SetAssetFounder(accountName common.Name, assetId uint64, founderName common.Name) error {
+// 	if accountName == "" {
+// 		return ErrAccountNameNull
+// 	}
+// 	if assetId == 0 {
+// 		return ErrAssetIdInvalid
+// 	}
+// 	asset, err := a.GetAssetObjectById(assetId)
+// 	if err != nil {
+// 		return err
+// 	}
+// 	if asset == nil {
+// 		return ErrAssetNotExist
+// 	}
+// 	if asset.GetAssetOwner() != accountName {
+// 		return ErrOwnerMismatch
+// 	}
+// 	asset.SetAssetFounder(founderName)
+// 	return a.SetAssetObject(asset)
+// }
+
+func (a *Asset) IsValidOwner(fromName common.Name, assetName string) bool {
+	assetNames := common.SplitString(assetName)
+	if len(assetNames) == 1 {
+		return true
+	}
+
+	if !common.IsValidAssetName(assetName) {
+		return false
+	}
+
+	var an string
+	for i := 0; i < len(assetNames)-1; i++ {
+		if i == 0 {
+			an = assetNames[i]
+		} else {
+			an = an + "." + assetNames[i]
+		}
+
+		assetId, err := a.GetAssetIdByName(an)
+		if err != nil {
+			continue
+		}
+
+		if assetId <= 0 {
+			continue
+		}
+
+		assetObj, err := a.GetAssetObjectById(assetId)
+		if err != nil {
+			continue
+		}
+
+		if assetObj == nil {
+			continue
+		}
+
+		if assetObj.GetAssetOwner() == fromName {
+			log.Debug("Asset create", "name", an, "onwer", assetObj.GetAssetOwner(), "fromName", fromName, "newName", assetName)
+			return true
+		}
+	}
+	log.Debug("Asset create failed", "account", fromName, "name", assetName)
+	return false
+}
diff --git a/asset/asset_object.go b/asset/asset_object.go
index b99720af..26837795 100644
--- a/asset/asset_object.go
+++ b/asset/asset_object.go
@@ -17,43 +17,52 @@ package asset
 
 import (
 	"math/big"
-	"regexp"
 
 	"github.com/fractalplatform/fractal/common"
 )
 
 type AssetObject struct {
-	AssetId    uint64      `json:"assetid,omitempty"`
-	AssetName  string      `json:"assetname,omitempty"`
-	Symbol     string      `json:"symbol,omitempty"`
-	Amount     *big.Int    `json:"amount,omitempty"`
-	Decimals   uint64      `json:"decimals,omitempty"`
-	Founder    common.Name `json:"founder,omitempty"`
-	Owner      common.Name `json:"owner,omitempty"`
-	AddIssue   *big.Int    `json:"AddIssue,omitempty"`
-	UpperLimit *big.Int    `json:"UpperLimit,omitempty"`
-}
-
-func NewAssetObject(assetName string, symbol string, amount *big.Int, dec uint64, founder common.Name, owner common.Name, limit *big.Int) (*AssetObject, error) {
+	AssetId    uint64      `json:"assetId,omitempty"`
+	Number     uint64      `json:"number,omitempty"`
+	AssetName  string      `json:"assetName"`
+	Symbol     string      `json:"symbol"`
+	Amount     *big.Int    `json:"amount"`
+	Decimals   uint64      `json:"decimals"`
+	Founder    common.Name `json:"founder"`
+	Owner      common.Name `json:"owner"`
+	AddIssue   *big.Int    `json:"addIssue"`
+	UpperLimit *big.Int    `json:"upperLimit"`
+	Contract   common.Name `json:"contract"`
+}
+
+func NewAssetObject(assetName string, number uint64, symbol string, amount *big.Int, dec uint64, founder common.Name, owner common.Name, limit *big.Int, contract common.Name) (*AssetObject, error) {
 	if assetName == "" || symbol == "" || owner == "" {
 		return nil, ErrNewAssetObject
 	}
 
-	if amount.Cmp(big.NewInt(0)) < 0 || limit.Cmp(big.NewInt(0)) < 0 || amount.Cmp(limit) > 0 {
+	if amount.Cmp(big.NewInt(0)) < 0 || limit.Cmp(big.NewInt(0)) < 0 {
 		return nil, ErrNewAssetObject
 	}
 
-	reg := regexp.MustCompile("^[a-z0-9]{2,16}$")
-	if reg.MatchString(assetName) == false {
+	if limit.Cmp(big.NewInt(0)) > 0 {
+		if amount.Cmp(limit) > 0 {
+			return nil, ErrNewAssetObject
+		}
+	}
+
+	// reg := regexp.MustCompile("^[a-z0-9]{2,16}$")
+
+	if common.IsValidAssetName(assetName) == false {
 		return nil, ErrNewAssetObject
 	}
 
-	if reg.MatchString(symbol) == false {
+	if common.IsValidAssetName(symbol) == false {
 		return nil, ErrNewAssetObject
 	}
 
 	ao := AssetObject{
 		AssetId:    0,
+		Number:     number,
 		AssetName:  assetName,
 		Symbol:     symbol,
 		Amount:     amount,
@@ -62,6 +71,7 @@ func NewAssetObject(assetName string, symbol string, amount *big.Int, dec uint64
 		Owner:      owner,
 		AddIssue:   amount,
 		UpperLimit: limit,
+		Contract:   contract,
 	}
 	return &ao, nil
 }
@@ -74,6 +84,14 @@ func (ao *AssetObject) SetAssetId(assetId uint64) {
 	ao.AssetId = assetId
 }
 
+func (ao *AssetObject) GetAssetNumber() uint64 {
+	return ao.Number
+}
+
+func (ao *AssetObject) SetAssetNumber(number uint64) {
+	ao.Number = number
+}
+
 func (ao *AssetObject) GetSymbol() string {
 	return ao.Symbol
 }
@@ -92,6 +110,7 @@ func (ao *AssetObject) SetDecimals(dec uint64) {
 func (ao *AssetObject) GetAssetName() string {
 	return ao.AssetName
 }
+
 func (ao *AssetObject) SetAssetName(assetName string) {
 	ao.AssetName = assetName
 }
@@ -112,6 +131,10 @@ func (ao *AssetObject) GetUpperLimit() *big.Int {
 	return ao.UpperLimit
 }
 
+func (ao *AssetObject) GetContract() common.Name {
+	return ao.Contract
+}
+
 func (ao *AssetObject) SetAssetAmount(amount *big.Int) {
 	ao.Amount = amount
 }
@@ -131,3 +154,11 @@ func (ao *AssetObject) GetAssetOwner() common.Name {
 func (ao *AssetObject) SetAssetOwner(owner common.Name) {
 	ao.Owner = owner
 }
+
+func (ao *AssetObject) GetAssetContract() common.Name {
+	return ao.Contract
+}
+
+func (ao *AssetObject) SetAssetContract(contract common.Name) {
+	ao.Contract = contract
+}
diff --git a/asset/asset_object_test.go b/asset/asset_object_test.go
index c801fcf9..eecc1876 100644
--- a/asset/asset_object_test.go
+++ b/asset/asset_object_test.go
@@ -41,7 +41,7 @@ func Test_newAssetObject(t *testing.T) {
 		wantErr bool
 	}{
 		// TODO: Add test cases.
-		{"normal", args{"ft", "ft", big.NewInt(2), 18, common.Name(""), common.Name("a123"), big.NewInt(999999)}, &AssetObject{0, "ft", "ft", big.NewInt(2), 18, common.Name(""), common.Name("a123"), big.NewInt(2), big.NewInt(999999)}, false},
+		{"normal", args{"ft", "ft", big.NewInt(2), 18, common.Name(""), common.Name("a123"), big.NewInt(999999)}, &AssetObject{0, 0, "ft", "ft", big.NewInt(2), 18, common.Name(""), common.Name("a123"), big.NewInt(2), big.NewInt(999999), common.Name("")}, false},
 		{"shortname", args{"z", "z", big.NewInt(2), 18, common.Name("a123"), common.Name("a123"), big.NewInt(999999)}, nil, true},
 		{"longname", args{"ftt0123456789ftt12", "zz", big.NewInt(2), 18, common.Name("a123"), common.Name("a123"), big.NewInt(999999)}, nil, true},
 		{"emptyname", args{"", "z", big.NewInt(2), 18, common.Name("a123"), common.Name("a123"), big.NewInt(999999)}, nil, true},
@@ -53,7 +53,7 @@ func Test_newAssetObject(t *testing.T) {
 		{"emptyname", args{"ft", "#ip0123456789ft", big.NewInt(2), 18, common.Name("a123"), common.Name("a123"), big.NewInt(999999)}, nil, true},
 	}
 	for _, tt := range tests {
-		got, err := NewAssetObject(tt.args.assetName, tt.args.symbol, tt.args.amount, tt.args.dec, tt.args.founder, tt.args.owner, tt.args.UpperLimit)
+		got, err := NewAssetObject(tt.args.assetName, 0, tt.args.symbol, tt.args.amount, tt.args.dec, tt.args.founder, tt.args.owner, tt.args.UpperLimit, common.Name(""))
 		if (err != nil) != tt.wantErr {
 			t.Errorf("%q. newAssetObject() error = %v, wantErr %v", tt.name, err, tt.wantErr)
 			continue
diff --git a/asset/asset_test.go b/asset/asset_test.go
index 52fc3012..5c779e3c 100644
--- a/asset/asset_test.go
+++ b/asset/asset_test.go
@@ -102,12 +102,15 @@ func TestAsset_GetAssetObjectByName(t *testing.T) {
 		assetName string
 	}
 
-	ao, _ := NewAssetObject("ft", "zz", big.NewInt(1000), 10, common.Name(""), common.Name("a123456789aeee"), big.NewInt(9999999999))
+	ao, _ := NewAssetObject("ft", 0, "zz", big.NewInt(1000), 10, common.Name(""), common.Name("a123456789aeee"), big.NewInt(9999999999), common.Name(""))
 	ao.SetAssetId(1)
 	ast.addNewAssetObject(ao)
-	ao1, _ := NewAssetObject("ft2", "zz2", big.NewInt(1000), 10, common.Name(""), common.Name("a123456789aeee"), big.NewInt(9999999999))
+	ao1, _ := NewAssetObject("ft2", 0, "zz2", big.NewInt(1000), 10, common.Name(""), common.Name("a123456789aeee"), big.NewInt(9999999999), common.Name(""))
 	ao1.SetAssetId(2)
 	ast.addNewAssetObject(ao1)
+	ao2, _ := NewAssetObject("ft0", 0, "zz0", big.NewInt(1000), 0, common.Name(""), common.Name("a123456789aeee"), big.NewInt(9999999999), common.Name(""))
+	ao1.SetAssetId(2)
+	ast.addNewAssetObject(ao2)
 	tests := []struct {
 		name    string
 		fields  fields
@@ -118,6 +121,7 @@ func TestAsset_GetAssetObjectByName(t *testing.T) {
 		// TODO: Add test cases.
 		{"getall", fields{astdb}, args{"ft"}, ao, false},
 		{"getall2", fields{astdb}, args{"ft2"}, ao1, false},
+		{"getall3", fields{astdb}, args{"ft0"}, ao2, false},
 	}
 	for _, tt := range tests {
 		a := &Asset{
@@ -131,6 +135,7 @@ func TestAsset_GetAssetObjectByName(t *testing.T) {
 		if !reflect.DeepEqual(got, tt.want) {
 			t.Errorf("%q. Asset.GetAssetObjectByName() = %v, want %v", tt.name, got, tt.want)
 		}
+		t.Logf("GetAssetObjectByName asset dec=%v", got.Decimals)
 	}
 }
 
@@ -142,7 +147,7 @@ func TestAsset_addNewAssetObject(t *testing.T) {
 		ao *AssetObject
 	}
 
-	ao3, _ := NewAssetObject("ft3", "zz3", big.NewInt(1000), 10, common.Name(""), common.Name("a123456789aeee"), big.NewInt(9999999999))
+	ao3, _ := NewAssetObject("ft3", 0, "zz3", big.NewInt(1000), 10, common.Name(""), common.Name("a123456789aeee"), big.NewInt(9999999999), common.Name(""))
 	//ao1.SetAssetId(3)
 
 	tests := []struct {
@@ -154,7 +159,7 @@ func TestAsset_addNewAssetObject(t *testing.T) {
 	}{
 		// TODO: Add test cases.
 		{"addnil", fields{astdb}, args{nil}, 0, true},
-		{"add", fields{astdb}, args{ao3}, 3, false},
+		{"add", fields{astdb}, args{ao3}, 4, false},
 	}
 	for _, tt := range tests {
 		a := &Asset{
@@ -213,7 +218,7 @@ func TestAsset_GetAssetObjectById(t *testing.T) {
 		id uint64
 	}
 
-	ao, _ := NewAssetObject("ft", "zz", big.NewInt(1000), 10, common.Name(""), common.Name("a123456789aeee"), big.NewInt(9999999999))
+	ao, _ := NewAssetObject("ft", 0, "zz", big.NewInt(1000), 10, common.Name(""), common.Name("a123456789aeee"), big.NewInt(9999999999), common.Name(""))
 	ao.SetAssetId(1)
 	ast.IssueAssetObject(ao)
 	tests := []struct {
@@ -254,7 +259,7 @@ func TestAsset_getAssetCount(t *testing.T) {
 		wantErr bool
 	}{
 		// TODO: Add test cases.
-		{"get", fields{astdb}, 3, false},
+		{"get", fields{astdb}, 4, false},
 	}
 	for _, tt := range tests {
 		a := &Asset{
@@ -269,14 +274,14 @@ func TestAsset_getAssetCount(t *testing.T) {
 			t.Errorf("%q. Asset.getAssetCount() = %v, want %v", tt.name, got, tt.want)
 		}
 	}
-	ao, _ := NewAssetObject("ft2", "zz2", big.NewInt(1000), 10, common.Name(""), common.Name("a123456789aeee"), big.NewInt(9999999999))
+	ao, _ := NewAssetObject("ft2", 0, "zz2", big.NewInt(1000), 10, common.Name(""), common.Name("a123456789aeee"), big.NewInt(9999999999), common.Name(""))
 	//ao.SetAssetId(1)
 	ast.IssueAssetObject(ao)
 	num, err := ast.getAssetCount()
 	if err != nil {
 		t.Errorf("get asset count err")
 	}
-	if num != 3 {
+	if num != 4 {
 		t.Errorf("test asset count err")
 	}
 }
@@ -325,9 +330,9 @@ func TestAsset_SetAssetObject(t *testing.T) {
 		ao *AssetObject
 	}
 
-	ao4, _ := NewAssetObject("ft4", "zz4", big.NewInt(1000), 10, common.Name(""), common.Name("a123456789aeee"), big.NewInt(9999999999))
+	ao4, _ := NewAssetObject("ft4", 0, "zz4", big.NewInt(1000), 10, common.Name(""), common.Name("a123456789aeee"), big.NewInt(9999999999), common.Name(""))
 	ao4.SetAssetId(0)
-	ao5, _ := NewAssetObject("ft5", "zz5", big.NewInt(1000), 10, common.Name(""), common.Name("a123456789aeee"), big.NewInt(9999999999))
+	ao5, _ := NewAssetObject("ft5", 0, "zz5", big.NewInt(1000), 10, common.Name(""), common.Name("a123456789aeee"), big.NewInt(9999999999), common.Name(""))
 	ao5.SetAssetId(55)
 	tests := []struct {
 		name    string
@@ -357,7 +362,7 @@ func TestAsset_IssueAssetObject(t *testing.T) {
 	type args struct {
 		ao *AssetObject
 	}
-	ao6, _ := NewAssetObject("ft6", "zz6", big.NewInt(1000), 10, common.Name(""), common.Name("a123456789aeee"), big.NewInt(9999999999))
+	ao6, _ := NewAssetObject("ft6", 0, "zz6", big.NewInt(1000), 10, common.Name(""), common.Name("a123456789aeee"), big.NewInt(9999999999), common.Name(""))
 	ao6.SetAssetId(11)
 	tests := []struct {
 		name    string
@@ -402,12 +407,20 @@ func TestAsset_IssueAsset(t *testing.T) {
 		{"nilsym", fields{astdb}, args{"22", "", big.NewInt(2), 2, common.Name(""), common.Name("11")}, true},
 		{"exist", fields{astdb}, args{"ft", "3", big.NewInt(2), 2, common.Name(""), common.Name("11")}, true},
 		{"normal", fields{astdb}, args{"ft22", "23", big.NewInt(2), 2, common.Name(""), common.Name("112345698")}, false},
+		// {"normal1", fields{astdb}, args{"ft22.ft33", "23", big.NewInt(2), 2, common.Name(""), common.Name("112345698")}, false},
+		// {"normal2", fields{astdb}, args{"ft22.ft44.ft55", "23", big.NewInt(2), 2, common.Name(""), common.Name("112345698")}, false},
+		// {"erroronwer", fields{astdb}, args{"ft22.ft44.ft55", "23", big.NewInt(2), 2, common.Name(""), common.Name("11234512")}, true},
+		// {"erroronwer1", fields{astdb}, args{"ft23.ft34", "23", big.NewInt(2), 2, common.Name(""), common.Name("11234512")}, true},
+		// {"erroronwer2", fields{astdb}, args{"ft23", "24", big.NewInt(2), 2, common.Name(""), common.Name("11234512")}, false},
+		// {"erroronwer3", fields{astdb}, args{"ft23.ft34", "24", big.NewInt(2), 2, common.Name(""), common.Name("11234512")}, false},
+		// {"erroronwer4", fields{astdb}, args{"ft24.", "25", big.NewInt(2), 2, common.Name(""), common.Name("11234523")}, true},
+		// {"erroronwer5", fields{astdb}, args{"ft24..", "25", big.NewInt(2), 2, common.Name(""), common.Name("11234523")}, true},
 	}
 	for _, tt := range tests {
 		a := &Asset{
 			sdb: tt.fields.sdb,
 		}
-		if err := a.IssueAsset(tt.args.assetName, tt.args.symbol, tt.args.amount, tt.args.dec, tt.args.founder, tt.args.owner, big.NewInt(9999999999)); (err != nil) != tt.wantErr {
+		if err := a.IssueAsset(tt.args.assetName, 0, tt.args.symbol, tt.args.amount, tt.args.dec, tt.args.founder, tt.args.owner, big.NewInt(9999999999), common.Name("")); (err != nil) != tt.wantErr {
 			t.Errorf("%q. Asset.IssueAsset() error = %v, wantErr %v", tt.name, err, tt.wantErr)
 		}
 	}
@@ -474,3 +487,36 @@ func TestAsset_SetAssetNewOwner(t *testing.T) {
 		}
 	}
 }
+
+func TestAsset_UpdateAsset(t *testing.T) {
+	type fields struct {
+		sdb *state.StateDB
+	}
+	type args struct {
+		accountName common.Name
+		assetId     uint64
+		Owner       common.Name
+		founder     common.Name
+	}
+	tests := []struct {
+		name    string
+		fields  fields
+		args    args
+		wantErr bool
+	}{
+		// TODO: Add test cases
+		{"nilname", fields{astdb}, args{common.Name(""), 1, common.Name(""), common.Name("")}, true},
+		{"wrongassetid", fields{astdb}, args{common.Name("11"), 0, common.Name(""), common.Name("")}, true},
+		{"wrongamount", fields{astdb}, args{common.Name("11"), 123, common.Name(""), common.Name("")}, true},
+		{"nilfounder", fields{astdb}, args{common.Name("a123456789afff"), 1, common.Name("a123456789aeee"), common.Name("")}, false},
+		{"normal", fields{astdb}, args{common.Name("a123456789aeee"), 1, common.Name("a123456789afff"), common.Name("a123456789afff")}, false},
+	}
+	for _, tt := range tests {
+		a := &Asset{
+			sdb: tt.fields.sdb,
+		}
+		if err := a.UpdateAsset(tt.args.accountName, tt.args.assetId, tt.args.Owner, tt.args.founder, common.Name("")); (err != nil) != tt.wantErr {
+			t.Errorf("%q. Asset.updateAsset() error = %v, wantErr %v", tt.name, err, tt.wantErr)
+		}
+	}
+}
diff --git a/wallet/errors.go b/asset/config.go
similarity index 64%
rename from wallet/errors.go
rename to asset/config.go
index 6cbb93a8..b4678ee2 100644
--- a/wallet/errors.go
+++ b/asset/config.go
@@ -14,13 +14,20 @@
 // You should have received a copy of the GNU General Public License
 // along with this program. If not, see <http://www.gnu.org/licenses/>.
 
-package wallet
+package asset
 
-import "errors"
+// Config Asset name level
+type Config struct {
+	AssetNameLevel     uint64 `json:"assetNameLevel"`
+	AssetNameLength    uint64 `json:"assetNameLength"`
+	SubAssetNameLength uint64 `json:"subAssetNameLength"`
+}
 
-var (
-	// ErrNoMatch no key for given address or file
-	ErrNoMatch = errors.New("no key for given address or file")
-	// ErrAccountExists account already exists
-	ErrAccountExists = errors.New("account already exists")
-)
+// DefaultAssetNameConf return asset config
+func DefaultAssetNameConf() *Config {
+	return &Config{
+		AssetNameLevel:     0,
+		AssetNameLength:    16,
+		SubAssetNameLength: 0,
+	}
+}
diff --git a/asset/error.go b/asset/error.go
index ad32253c..d5e563df 100644
--- a/asset/error.go
+++ b/asset/error.go
@@ -19,17 +19,17 @@ package asset
 import "errors"
 
 var (
-	ErrAccountNameNull    = errors.New("account name is null")
-	ErrAssetIsExist       = errors.New("asset is exist")
-	ErrAssetNotExist      = errors.New("asset not exist")
-	ErrOwnerMismatch      = errors.New("asset owner mismatch")
-	ErrAssetNameEmpty     = errors.New("asset name is empty")
-	ErrAssetObjectEmpty   = errors.New("asset object is empty")
-	ErrNewAssetObject     = errors.New("create asset object input invalid")
-	ErrAssetAmountZero    = errors.New("asset amount is zero")
-	ErrUpperLimit         = errors.New("asset amount over the issuance limit")
-	ErrDestoryLimit       = errors.New("asset destroy exceeding the lower limit")
-	ErrAssetCountNotExist = errors.New("asset total count not exist")
-	ErrAssetIdInvalid     = errors.New("asset id invalid")
-	//ErrAddNewAssetId      = errors.New("add new asset return id invalid")
+	ErrAccountNameNull      = errors.New("account name is null")
+	ErrAssetIsExist         = errors.New("asset is exist")
+	ErrAssetNotExist        = errors.New("asset not exist")
+	ErrOwnerMismatch        = errors.New("asset owner mismatch")
+	ErrAssetNameEmpty       = errors.New("asset name is empty")
+	ErrAssetObjectEmpty     = errors.New("asset object is empty")
+	ErrNewAssetObject       = errors.New("create asset object input invalid")
+	ErrAssetAmountZero      = errors.New("asset amount is zero")
+	ErrUpperLimit           = errors.New("asset amount over the issuance limit")
+	ErrDestroyLimit         = errors.New("asset destroy exceeding the lower limit")
+	ErrAssetCountNotExist   = errors.New("asset total count not exist")
+	ErrAssetIdInvalid       = errors.New("asset id invalid")
+	ErrAssetManagerNotExist = errors.New("asset manager name not exist")
 )
diff --git a/asset/interface.go b/asset/interface.go
index 2c6b6b0c..48d0f317 100644
--- a/asset/interface.go
+++ b/asset/interface.go
@@ -17,8 +17,9 @@
 package asset
 
 import (
-	"github.com/fractalplatform/fractal/common"
 	"math/big"
+
+	"github.com/fractalplatform/fractal/common"
 )
 
 //export
diff --git a/blockchain/blockchain.go b/blockchain/blockchain.go
index e76b4621..d50b15b8 100644
--- a/blockchain/blockchain.go
+++ b/blockchain/blockchain.go
@@ -18,7 +18,10 @@ package blockchain
 
 import (
 	"fmt"
+	"io"
 	"math/big"
+	mrand "math/rand"
+	"strings"
 	"sync"
 	"sync/atomic"
 	"time"
@@ -47,39 +50,43 @@ const (
 	maxTimeFutureBlocks = 30
 	badBlockLimit       = 10
 
-	BlockChainVersion = 3
+	//BlockChainVersion ensures that an incompatible database forces a resync from scratch.
+	BlockChainVersion = 0
 )
 
 // BlockChain represents the canonical chain given a database with a genesis
 // block. The Blockchain manages chain imports, reverts, chain reorganisations.
 type BlockChain struct {
-	chainConfig      *params.ChainConfig // Chain & network configuration
-	vmConfig         vm.Config           // vm configuration
-	genesisBlock     *types.Block        // genesis block
-	db               fdb.Database        // Low level persistent database to store final content in
-	mu               sync.RWMutex        // global mutex for locking chain operations
-	chainmu          sync.RWMutex        // blockchain insertion lock
-	procmu           sync.RWMutex        // block processor lock
-	currentBlock     atomic.Value        // Current head of the block chain
-	currentFastBlock atomic.Value        // Current head of the fast-sync chain (may be above the block chain!)
-	stateCache       state.Database      // State database to reuse between imports (contains state cache)
-	headerCache      *lru.Cache          // Cache for the most recent block headers
-	tdCache          *lru.Cache          // Cache for the most recent block total difficulties
-	numberCache      *lru.Cache          // Cache for the most recent block numbers
-	bodyCache        *lru.Cache          // Cache for the most recent block bodies
-	bodyRLPCache     *lru.Cache          // Cache for the most recent block bodies in RLP encoded format
-	blockCache       *lru.Cache          // Cache for the most recent entire blocks
-	futureBlocks     *lru.Cache          // future blocks are blocks added for later processing
-	badBlocks        *lru.Cache          // Bad block cache
-	quit             chan struct{}       // blockchain quit channel
-	running          int32               // running must be called atomically
-	procInterrupt    int32               // procInterrupt must be atomically called, interrupt signaler for block processing
-	wg               sync.WaitGroup      // chain processing wait group for shutting down
-	senderCacher     TxSenderCacher      // senderCacher is a concurrent tranaction sender recoverer sender cacher.
-	fcontroller      *ForkController
-	processor        processor.Processor // block processor interface
-	validator        processor.Validator // block and state validator interface
-	station          *BlockchainStation  // p2p station
+	chainConfig        *params.ChainConfig // Chain & network configuration
+	vmConfig           vm.Config           // vm configuration
+	genesisBlock       *types.Block        // genesis block
+	db                 fdb.Database        // Low level persistent database to store final content in
+	mu                 sync.RWMutex        // global mutex for locking chain operations
+	chainmu            sync.RWMutex        // blockchain insertion lock
+	procmu             sync.RWMutex        // block processor lock
+	currentBlock       atomic.Value        // Current head of the block chain
+	irreversibleNumber atomic.Value        // irreversible Number of the block chain
+
+	stateCache state.Database // State database to reuse between imports (contains state cache)
+
+	running       int32               // running must be called atomically
+	procInterrupt int32               // procInterrupt must be atomically called, interrupt signaler for block processing
+	wg            sync.WaitGroup      // chain processing wait group for shutting down
+	senderCacher  TxSenderCacher      // senderCacher is a concurrent tranaction sender recoverer sender cacher.
+	fcontroller   *ForkController     // fcontroller
+	processor     processor.Processor // block processor interface
+	validator     processor.Validator // block and state validator interface
+	station       *BlockchainStation  // p2p station
+
+	headerCache  *lru.Cache    // Cache for the most recent block headers
+	tdCache      *lru.Cache    // Cache for the most recent block total difficulties
+	numberCache  *lru.Cache    // Cache for the most recent block numbers
+	bodyCache    *lru.Cache    // Cache for the most recent block bodies
+	bodyRLPCache *lru.Cache    // Cache for the most recent block bodies in RLP encoded format
+	blockCache   *lru.Cache    // Cache for the most recent entire blocks
+	futureBlocks *lru.Cache    // future blocks are blocks added for later processing
+	badBlocks    *lru.Cache    // Bad block cache
+	quit         chan struct{} // blockchain quit channel
 }
 
 // NewBlockChain returns a fully initialised block chain using information available in the database.
@@ -108,7 +115,10 @@ func NewBlockChain(db fdb.Database, vmConfig vm.Config, chainConfig *params.Chai
 		futureBlocks: futureBlocks,
 		badBlocks:    badBlocks,
 		senderCacher: senderCacher,
-		fcontroller:  NewForkController(defaultForkConfig, chainConfig),
+		fcontroller: NewForkController(&ForkConfig{
+			ForkBlockNum:   chainConfig.ForkedCfg.ForkBlockNum,
+			Forkpercentage: chainConfig.ForkedCfg.Forkpercentage,
+		}, chainConfig),
 	}
 
 	bc.genesisBlock = bc.GetBlockByNumber(0)
@@ -140,35 +150,28 @@ func (bc *BlockChain) loadLastBlock() error {
 		return bc.Reset()
 	}
 
+	// Make sure the state associated with the block is available
+	if _, err := state.New(currentBlock.Root(), bc.stateCache); err != nil {
+		// Dangling block without a state associated, init from scratch
+		log.Warn("Head state missing, repairing chain", "number", currentBlock.Number(), "hash", currentBlock.Hash())
+		if err := bc.repair(&currentBlock); err != nil {
+			return err
+		}
+	}
+
 	// Everything seems to be fine, set as the head block
 	bc.currentBlock.Store(currentBlock)
 
 	// Restore the last known head header
 	currentHeader := currentBlock.Header()
-	if head := rawdb.ReadHeadHeaderHash(bc.db); head != (common.Hash{}) {
-		if header := bc.GetHeaderByHash(head); header != nil {
-			currentHeader = header
-		}
-	}
 
 	rawdb.WriteHeadHeaderHash(bc.db, currentHeader.Hash())
-
-	// Restore the last known head fast block
-	bc.currentFastBlock.Store(currentBlock)
-	if head := rawdb.ReadHeadFastBlockHash(bc.db); head != (common.Hash{}) {
-		if block := bc.GetBlockByHash(head); block != nil {
-			bc.currentFastBlock.Store(block)
-		}
-	}
-
-	// Issue a status log for the user
-	currentFastBlock := bc.CurrentFastBlock()
-
 	blockTd := bc.GetTd(currentBlock.Hash(), currentBlock.NumberU64())
-	fastTd := bc.GetTd(currentFastBlock.Hash(), currentFastBlock.NumberU64())
 
-	log.Info("Loaded most recent local full block", "number", currentBlock.Number(), "hash", currentBlock.Hash(), "td", blockTd)
-	log.Info("Loaded most recent local fast block", "number", currentFastBlock.Number(), "hash", currentFastBlock.Hash(), "td", fastTd)
+	inum := rawdb.ReadIrreversibleNumber(bc.db)
+	bc.irreversibleNumber.Store(inum)
+
+	log.Info("Loaded most recent local full block", "number", currentBlock.Number(), "hash", currentBlock.Hash(), "td", blockTd, "irreversible number", inum)
 	return nil
 }
 
@@ -177,6 +180,22 @@ func (bc *BlockChain) Reset() error {
 	return bc.ResetWithGenesisBlock(bc.genesisBlock)
 }
 
+func (bc *BlockChain) repair(head **types.Block) error {
+	for {
+		// Abort if we've rewound to a head block that does have associated state
+		if _, err := state.New((*head).Root(), bc.stateCache); err == nil {
+			log.Info("Rewound blockchain to past state", "number", (*head).Number(), "hash", (*head).Hash())
+			return nil
+		}
+		// Otherwise rewind one block and recheck state availability there
+		block := bc.GetBlock((*head).ParentHash(), (*head).NumberU64()-1)
+		if block == nil {
+			return fmt.Errorf("missing block %d [%x]", (*head).NumberU64()-1, (*head).ParentHash())
+		}
+		*head = block
+	}
+}
+
 // ResetWithGenesisBlock purges the entire blockchain, restoring it to the specified genesis state.
 func (bc *BlockChain) ResetWithGenesisBlock(genesis *types.Block) error {
 	// Dump the entire block chain and purge the caches
@@ -194,8 +213,12 @@ func (bc *BlockChain) ResetWithGenesisBlock(genesis *types.Block) error {
 	if err := batch.Write(); err != nil {
 		return err
 	}
+
+	rawdb.WriteIrreversibleNumber(bc.db, bc.genesisBlock.NumberU64())
+
 	bc.currentBlock.Store(bc.genesisBlock)
-	bc.currentFastBlock.Store(bc.genesisBlock)
+	bc.irreversibleNumber.Store(bc.genesisBlock.NumberU64())
+
 	return nil
 }
 
@@ -219,40 +242,13 @@ func (bc *BlockChain) SetHead(head uint64) error {
 	if currentBlock := bc.CurrentBlock(); currentBlock == nil {
 		bc.currentBlock.Store(bc.genesisBlock)
 	}
-	if currentFastBlock := bc.CurrentFastBlock(); currentFastBlock == nil {
-		bc.currentFastBlock.Store(bc.genesisBlock)
-	}
+
 	currentBlock := bc.CurrentBlock()
-	currentFastBlock := bc.CurrentFastBlock()
 
 	rawdb.WriteHeadBlockHash(bc.db, currentBlock.Hash())
-	rawdb.WriteHeadFastBlockHash(bc.db, currentFastBlock.Hash())
 	return bc.loadLastBlock()
 }
 
-// FastSyncCommitHead sets the current head block to the one defined by the hash
-// irrelevant what the chain contents were prior.
-func (bc *BlockChain) FastSyncCommitHead(hash common.Hash) error {
-	// Make sure that both the block as well at its state trie exists
-	block := bc.GetBlockByHash(hash)
-	if block == nil {
-		return fmt.Errorf("non existent block [%x…]", hash[:4])
-	}
-
-	stateOut := rawdb.ReadBlockStateOut(bc.db, hash)
-	if stateOut == nil {
-		return fmt.Errorf("non existent state block [%x…]", hash[:4])
-	}
-
-	// If all checks out, manually set the head block
-	bc.mu.Lock()
-	bc.currentBlock.Store(block)
-	bc.mu.Unlock()
-
-	log.Info("Committed new head block", "number", block.Number(), "hash", hash)
-	return nil
-}
-
 // GasLimit returns the gas limit of the current HEAD block.
 func (bc *BlockChain) GasLimit() uint64 {
 	return bc.CurrentBlock().GasLimit()
@@ -263,9 +259,9 @@ func (bc *BlockChain) CurrentBlock() *types.Block {
 	return bc.currentBlock.Load().(*types.Block)
 }
 
-// CurrentFastBlock retrieves the current fast-sync head block of the canonical chain.
-func (bc *BlockChain) CurrentFastBlock() *types.Block {
-	return bc.currentFastBlock.Load().(*types.Block)
+// IrreversibleNumber retrieves the irreversible block number of the canonical chain.
+func (bc *BlockChain) IrreversibleNumber() uint64 {
+	return bc.irreversibleNumber.Load().(uint64)
 }
 
 // SetProcessor sets the processor required for making state modifications.
@@ -328,13 +324,14 @@ func (bc *BlockChain) StateAt(hash common.Hash) (*state.StateDB, error) {
 
 // insert injects a new head block into the current block chain.
 func (bc *BlockChain) insert(batch fdb.Batch, block *types.Block) {
-	updateHeads := rawdb.ReadCanonicalHash(bc.db, block.NumberU64()) != block.Hash()
 	rawdb.WriteCanonicalHash(batch, block.Hash(), block.NumberU64())
 	rawdb.WriteHeadBlockHash(batch, block.Hash())
+	// store cur block
 	// bc.currentBlock.Store(block)
-	if updateHeads {
-		rawdb.WriteHeadFastBlockHash(batch, block.Hash())
-		bc.currentFastBlock.Store(block)
+
+	if strings.Compare(block.Coinbase().String(), bc.chainConfig.SysName) == 0 {
+		rawdb.WriteIrreversibleNumber(batch, block.NumberU64())
+		bc.irreversibleNumber.Store(block.NumberU64())
 	}
 }
 
@@ -488,38 +485,6 @@ func (bc *BlockChain) procFutureBlocks() {
 	}
 }
 
-// WriteStatus status of write
-type WriteStatus byte
-
-const (
-	NonStatTy WriteStatus = iota
-	CanonStatTy
-	SideStatTy
-)
-
-// Rollback is designed to remove a chain of links from the database that aren't certain enough to be valid.
-func (bc *BlockChain) Rollback(chain []common.Hash) {
-	bc.mu.Lock()
-	defer bc.mu.Unlock()
-
-	for i := len(chain) - 1; i >= 0; i-- {
-		hash := chain[i]
-
-		if currentFastBlock := bc.CurrentFastBlock(); currentFastBlock.Hash() == hash {
-			newFastBlock := bc.GetBlock(currentFastBlock.ParentHash(), currentFastBlock.NumberU64()-1)
-			bc.currentFastBlock.Store(newFastBlock)
-			rawdb.WriteHeadFastBlockHash(bc.db, newFastBlock.Hash())
-		}
-		if currentBlock := bc.CurrentBlock(); currentBlock.Hash() == hash {
-			newBlock := bc.GetBlock(currentBlock.ParentHash(), currentBlock.NumberU64()-1)
-			bc.currentBlock.Store(newBlock)
-			rawdb.WriteHeadBlockHash(bc.db, newBlock.Hash())
-		}
-	}
-}
-
-var lastWrite uint64
-
 // WriteBlockWithoutState writes only the block and its metadata to the database, but does not write any state.
 func (bc *BlockChain) WriteBlockWithoutState(block *types.Block, td *big.Int) (err error) {
 	bc.wg.Add(1)
@@ -532,17 +497,13 @@ func (bc *BlockChain) WriteBlockWithoutState(block *types.Block, td *big.Int) (e
 }
 
 // WriteBlockWithState writes the block and all associated state to the database.
-func (bc *BlockChain) WriteBlockWithState(block *types.Block, receipts []*types.Receipt, state *state.StateDB) (err error) {
+func (bc *BlockChain) WriteBlockWithState(block *types.Block, receipts []*types.Receipt, state *state.StateDB) (isCanon bool, err error) {
 	bc.wg.Add(1)
 	defer bc.wg.Done()
 
-	if block.ParentHash() != bc.CurrentBlock().Hash() {
-		return ErrSideBlock
-	}
-
 	ptd := bc.GetTd(block.ParentHash(), block.NumberU64()-1)
 	if ptd == nil {
-		return processor.ErrUnknownAncestor
+		return false, processor.ErrUnknownAncestor
 	}
 	// Make sure no inconsistent state is leaked during insertion
 	bc.mu.Lock()
@@ -550,7 +511,7 @@ func (bc *BlockChain) WriteBlockWithState(block *types.Block, receipts []*types.
 
 	externTd := new(big.Int).Add(block.Difficulty(), ptd)
 	if err := bc.WriteTd(block.Hash(), block.NumberU64(), externTd); err != nil {
-		return err
+		return false, err
 	}
 
 	// Write other block data using a batch.
@@ -559,32 +520,71 @@ func (bc *BlockChain) WriteBlockWithState(block *types.Block, receipts []*types.
 
 	root, err := state.Commit(batch, block.Hash(), block.NumberU64())
 	if err != nil {
-		return err
+		return false, err
 	}
 
 	triedb := bc.stateCache.TrieDB()
 	if err := triedb.Commit(root, false); err != nil {
-		return err
+		return false, err
 	}
 
 	rawdb.WriteReceipts(batch, block.Hash(), block.NumberU64(), receipts)
-	rawdb.WriteTxLookupEntries(batch, block)
-	rawdb.WritePreimages(batch, block.NumberU64(), state.Preimages())
-	bc.insert(batch, block)
+	if bc.vmConfig.ContractLogFlag {
+		detailtxs := make([]*types.DetailTx, len(receipts))
+		for i := 0; i < len(receipts); i++ {
+			detailtxs[i] = receipts[i].GetInternalTxsLog()
+		}
+		rawdb.WriteDetailTxs(batch, block.Hash(), block.NumberU64(), detailtxs)
+	}
+
+	currentBlock := bc.CurrentBlock()
+	localTd := bc.GetTd(currentBlock.Hash(), currentBlock.NumberU64())
+
+	reorg := externTd.Cmp(localTd) > 0 || strings.Compare(block.Coinbase().String(), bc.chainConfig.SysName) == 0
+	if !reorg && externTd.Cmp(localTd) == 0 {
+		// Split same-difficulty blocks by number, then at random
+		reorg = block.NumberU64() < currentBlock.NumberU64() || (block.NumberU64() == currentBlock.NumberU64() && mrand.Float64() < 0.5)
+	}
+
+	if reorg {
+		// Reorganise the chain if the parent is not the head block
+		if block.ParentHash() != currentBlock.Hash() {
+			if err := bc.reorgChain(currentBlock, block, batch); err != nil {
+				if err == errReorgSystemBlock {
+					goto Target
+				}
+				return false, err
+			}
+
+		}
+
+		// Write the positional metadata for transaction/receipt lookups and preimages
+		rawdb.WriteTxLookupEntries(batch, block)
+		rawdb.WritePreimages(batch, block.NumberU64(), state.Preimages())
+		isCanon = true
+	}
+
+	if isCanon {
+		bc.insert(batch, block)
+	}
+
+Target:
 	if err := batch.Write(); err != nil {
-		return err
+		return false, err
+	}
+
+	if isCanon {
+		bc.currentBlock.Store(block)
 	}
 
-	bc.currentBlock.Store(block)
 	bc.futureBlocks.Remove(block.Hash())
-	log.Debug("Insert new block", "producer", block.Coinbase(), "number", block.Number(), "hash", block.Hash().String(), "time", block.Time().Int64(), "txs", len(block.Txs), "gas", block.GasUsed())
-	return nil
+
+	return isCanon, nil
 }
 
 // InsertChain attempts to insert the given batch of blocks in to the canonical chain or, otherwise, create a fork.
 func (bc *BlockChain) InsertChain(chain types.Blocks) (int, error) {
-	n, events, _, err := bc.insertChain(chain)
-	event.SendEvents(events)
+	n, _, err := bc.insertChain(chain)
 	return n, err
 }
 
@@ -602,13 +602,13 @@ func (bc *BlockChain) sanityCheck(chain types.Blocks) error {
 }
 
 // insertChain will execute the actual chain insertion and event aggregation.
-func (bc *BlockChain) insertChain(chain types.Blocks) (int, []*event.Event, []*types.Log, error) {
+func (bc *BlockChain) insertChain(chain types.Blocks) (int, []*types.Log, error) {
 	if len(chain) == 0 {
-		return 0, nil, nil, nil
+		return 0, nil, nil
 	}
 
 	if err := bc.sanityCheck(chain); err != nil {
-		return 0, nil, nil, err
+		return 0, nil, err
 	}
 
 	bc.wg.Add(1)
@@ -619,8 +619,6 @@ func (bc *BlockChain) insertChain(chain types.Blocks) (int, []*event.Event, []*t
 
 	var (
 		stats         = insertStats{startTime: time.Now()}
-		events        = make([]*event.Event, 0, len(chain))
-		lastCanon     *types.Block
 		coalescedLogs []*types.Log
 	)
 
@@ -647,7 +645,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks) (int, []*event.Event, []*t
 		case err == processor.ErrFutureBlock:
 			max := big.NewInt(time.Now().Unix() + maxTimeFutureBlocks)
 			if block.Time().Cmp(max) > 0 {
-				return i, events, coalescedLogs, fmt.Errorf("future block: %v > %v", block.Time(), max)
+				return i, coalescedLogs, fmt.Errorf("future block: %v > %v", block.Time(), max)
 			}
 			bc.futureBlocks.Add(block.Hash(), block)
 			stats.ignored++
@@ -659,50 +657,14 @@ func (bc *BlockChain) insertChain(chain types.Blocks) (int, []*event.Event, []*t
 			stats.queued++
 			continue
 		case err == processor.ErrPrunedAncestor:
-			// Block competing with the canonical chain, store in the db, but don't process
-			// until the competitor TD goes above the canonical TD
-			currentBlock := bc.CurrentBlock()
-			localTd := bc.GetTd(currentBlock.Hash(), currentBlock.NumberU64())
-			externTd := new(big.Int).Add(bc.GetTd(block.ParentHash(), block.NumberU64()-1), block.Difficulty())
-			if localTd.Cmp(externTd) >= 0 {
-				if err = bc.WriteBlockWithoutState(block, externTd); err != nil {
-					return i, events, coalescedLogs, err
-				}
-			} else {
-				newchain, err := bc.reorgBlock(currentBlock, block)
-				if err != nil {
-					return i, events, coalescedLogs, err
-				}
-				for j := 0; j < len(newchain)/2; j++ {
-					newchain[j], newchain[len(newchain)-1-j] = newchain[len(newchain)-1-j], newchain[j]
-				}
-
-				bc.chainmu.Unlock()
-				_, evs, logs, err := bc.insertChain(newchain)
-				bc.chainmu.Lock()
-				events, coalescedLogs = evs, logs
-				if err != nil {
-					return i, events, coalescedLogs, err
-				}
+			coalescedLogs, err := bc.insertSideChain(block)
+			if err != nil {
+				return i, coalescedLogs, err
 			}
 			continue
 		case err != nil:
 			bc.reportBlock(block, nil, err)
-			return i, events, coalescedLogs, err
-		}
-
-		currentBlock := bc.CurrentBlock()
-		if currentBlock.Hash() != block.ParentHash() {
-			// check totally difficulty
-			localTd := bc.GetTd(currentBlock.Hash(), currentBlock.NumberU64())
-			externTd := new(big.Int).Add(bc.GetTd(block.ParentHash(), block.NumberU64()-1), block.Difficulty())
-
-			if localTd.Cmp(externTd) >= 0 {
-				if err = bc.WriteBlockWithoutState(block, externTd); err != nil {
-					return i, events, coalescedLogs, err
-				}
-				continue
-			}
+			return i, coalescedLogs, err
 		}
 
 		var parent *types.Block
@@ -715,39 +677,90 @@ func (bc *BlockChain) insertChain(chain types.Blocks) (int, []*event.Event, []*t
 
 		state, err := state.New(parent.Root(), bc.stateCache)
 		if err != nil {
-			return i, events, coalescedLogs, err
+			return i, coalescedLogs, err
 		}
 
 		receipts, logs, usedGas, err := bc.processor.Process(block, state, bc.vmConfig)
 		if err != nil {
 			bc.reportBlock(block, receipts, err)
-			return i, events, coalescedLogs, err
+			return i, coalescedLogs, err
 		}
 
 		err = bc.validator.ValidateState(block, parent, state, receipts, usedGas)
 		if err != nil {
 			bc.reportBlock(block, receipts, err)
-			return i, events, coalescedLogs, err
+			return i, coalescedLogs, err
+		}
+
+		isCanon, err := bc.WriteBlockWithState(block, receipts, state)
+		if err != nil {
+			return i, coalescedLogs, err
 		}
 
-		if err := bc.WriteBlockWithState(block, receipts, state); err != nil {
-			return i, events, coalescedLogs, err
+		if isCanon {
+			log.Debug("Inserted new block", "number", block.Number(), "hash", block.Hash(),
+				"txs", len(block.Transactions()), "gas", block.GasUsed())
+			coalescedLogs = append(coalescedLogs, logs...)
+			event.SendEvent(&event.Event{Typecode: event.ChainHeadEv, Data: block})
+		} else {
+			log.Debug("Inserted forked block", "number", block.Number(), "hash", block.Hash(), "diff", block.Difficulty(),
+				"txs", len(block.Transactions()), "gas", block.GasUsed())
 		}
+
 		stats.processed++
 		stats.txsCnt += len(block.Txs)
 		stats.usedGas += usedGas
 		stats.report(chain, i)
-		coalescedLogs = append(coalescedLogs, logs...)
-		lastCanon = block
+
+	}
+
+	return 0, coalescedLogs, nil
+}
+
+func (bc *BlockChain) insertSideChain(block *types.Block) ([]*types.Log, error) {
+	var systemBlock bool
+	if strings.Compare(block.Coinbase().String(), bc.chainConfig.SysName) == 0 {
+		systemBlock = true
 	}
-	if lastCanon != nil && bc.CurrentBlock().Hash() == lastCanon.Hash() {
-		events = append(events, &event.Event{Typecode: event.ChainHeadEv, Data: lastCanon})
+
+	currentBlock := bc.CurrentBlock()
+	localTd := bc.GetTd(currentBlock.Hash(), currentBlock.NumberU64())
+	externTd := new(big.Int).Add(bc.GetTd(block.ParentHash(), block.NumberU64()-1), block.Difficulty())
+	if localTd.Cmp(externTd) >= 0 && !systemBlock {
+		start := time.Now()
+		if err := bc.WriteBlockWithoutState(block, externTd); err != nil {
+			return nil, err
+		}
+
+		log.Debug("Injected sidechain block", "number", block.Number(), "hash", block.Hash(),
+			"diff", block.Difficulty(), "elapsed", common.PrettyDuration(time.Since(start)),
+			"txs", len(block.Transactions()), "gas", block.GasUsed(), "root", block.Root())
+	} else {
+		var blocks []*types.Block
+		blocks = append(blocks, block)
+		parent := bc.GetBlock(block.ParentHash(), block.NumberU64()-1)
+		for parent != nil && !bc.HasState(parent.Root()) {
+			blocks = append(blocks, parent)
+			parent = bc.GetBlock(block.ParentHash(), block.NumberU64()-1)
+		}
+
+		for j := 0; j < len(blocks)/2; j++ {
+			blocks[j], blocks[len(blocks)-1-j] = blocks[len(blocks)-1-j], blocks[j]
+		}
+
+		bc.chainmu.Unlock()
+		log.Info("Importing sidechain segment", "start", blocks[0].NumberU64(), "end", blocks[len(blocks)-1].NumberU64())
+		_, logs, err := bc.insertChain(blocks)
+		bc.chainmu.Lock()
+		if err != nil {
+			return logs, err
+		}
 	}
+	return nil, nil
 
-	return 0, events, coalescedLogs, nil
 }
 
-func (bc *BlockChain) reorgBlock(oldBlock, newBlock *types.Block) (types.Blocks, error) {
+func (bc *BlockChain) reorgChain(oldBlock, newBlock *types.Block, batch fdb.Batch) error {
 	var (
 		newChain    types.Blocks
 		oldChain    types.Blocks
@@ -767,10 +780,10 @@ func (bc *BlockChain) reorgBlock(oldBlock, newBlock *types.Block) (types.Blocks,
 	}
 
 	if oldBlock == nil {
-		return nil, fmt.Errorf("reorg state not found old block , block hash: %v", oldBlock.Hash().Hex())
+		return fmt.Errorf("reorg chain not found oldblock ")
 	}
 	if newBlock == nil {
-		return nil, fmt.Errorf("reorg state not found new block , block hash: %v", newBlock.Hash().Hex())
+		return fmt.Errorf("reorg chain not found newblock ")
 	}
 
 	for {
@@ -783,41 +796,42 @@ func (bc *BlockChain) reorgBlock(oldBlock, newBlock *types.Block) (types.Blocks,
 		deletedTxs = append(deletedTxs, oldBlock.Txs...)
 		oldBlock, newBlock = bc.GetBlock(oldBlock.ParentHash(), oldBlock.NumberU64()-1), bc.GetBlock(newBlock.ParentHash(), newBlock.NumberU64()-1)
 		if oldBlock == nil {
-			return nil, fmt.Errorf("reorg state not found old block , block hash: %v", oldBlock.Hash().Hex())
+			return fmt.Errorf("reorg chain not found old block ")
 		}
 		if newBlock == nil {
-			return nil, fmt.Errorf("reorg state not found new block , block hash: %v", newBlock.Hash().Hex())
+			return fmt.Errorf("reorg chain not found new block ")
 		}
 	}
 
 	// Ensure the user sees large reorgs
 	if len(oldChain) > 0 && len(newChain) > 0 {
+		if oldChain[len(oldChain)-1].NumberU64() <= bc.IrreversibleNumber() {
+			log.Warn("Do not accept other cadidate fork the system chain", "hash", newBlock.Hash(), "coinbase", newBlock.Coinbase())
+			return errReorgSystemBlock
+		}
+
 		logFn := log.Debug
 		if len(oldChain) > 63 {
 			logFn = log.Warn
 		}
-		logFn("Chain split detected", "number", commonBlock.Number(), "hash", commonBlock.Hash(), "drop", len(oldChain), "dropfrom", oldChain[0].Hash(), "add", len(newChain), "addfrom", newChain[0].Hash())
+		logFn("Chain split detected", "number", commonBlock.Number(), "hash", commonBlock.Hash(), "drop", len(oldChain), "dropNum", oldChain[0].NumberU64(),
+			"dropfrom", oldChain[0].Hash(), "add", len(newChain), "addNum", newChain[0].NumberU64(), "addfrom", newChain[0].Hash())
 	} else {
 		log.Error("Impossible reorg, please file an issue", "oldnum", oldBlock.Number(), "oldhash", oldBlock.Hash(), "newnum", newBlock.Number(), "newhash", newBlock.Hash())
 	}
 
 	var addedTxs []*types.Transaction
 	for i := len(newChain) - 1; i >= 0; i-- {
-		rawdb.WriteTxLookupEntries(bc.db, newChain[i])
+		bc.insert(batch, newChain[i])
+		rawdb.WriteTxLookupEntries(batch, newChain[i])
 		addedTxs = append(addedTxs, newChain[i].Txs...)
 	}
-
 	diff := types.TxDifference(deletedTxs, addedTxs)
-	batch := bc.db.NewBatch()
 	for _, tx := range diff {
 		rawdb.DeleteTxLookupEntry(batch, tx.Hash())
 	}
-	batch.Write()
 
-	if len(oldChain) > 0 {
-		bc.currentBlock.Store(oldBlock)
-	}
-	return newChain, nil
+	return nil
 }
 
 func (bc *BlockChain) update() {
@@ -853,7 +867,6 @@ func (bc *BlockChain) addBadBlock(block *types.Block) {
 // reportBlock logs a bad block error.
 func (bc *BlockChain) reportBlock(block *types.Block, receipts []*types.Receipt, err error) {
 	bc.addBadBlock(block)
-
 	log.Error(fmt.Sprintf(`
 ########## BAD BLOCK #########
 Error: %v
@@ -861,10 +874,10 @@ Error: %v
 Chain config: %v
 
 Number: %v
-Hash: 0x%x
+Hash: %v
 
 ##############################
-`, err, bc.chainConfig, block.Number(), block.Hash()))
+`, err, bc.chainConfig, block.NumberU64(), block.Hash().Hex()))
 }
 
 // GetBlockNumber retrieves the block number belonging to the given hash from the cache or database
@@ -1019,6 +1032,39 @@ func (bc *BlockChain) CalcGasLimit(parent *types.Block) uint64 {
 	return params.CalcGasLimit(parent)
 }
 
+// ForkUpdate .
 func (bc *BlockChain) ForkUpdate(block *types.Block, statedb *state.StateDB) error {
 	return bc.fcontroller.update(block, statedb)
 }
+
+// Export writes the active chain to the given writer.
+func (bc *BlockChain) Export(w io.Writer) error {
+	return bc.ExportN(w, uint64(0), bc.CurrentBlock().NumberU64())
+}
+
+// ExportN writes a subset of the active chain to the given writer.
+func (bc *BlockChain) ExportN(w io.Writer, first uint64, last uint64) error {
+	bc.chainmu.RLock()
+	defer bc.chainmu.RUnlock()
+
+	if first > last {
+		return fmt.Errorf("export failed: first (%d) is greater than last (%d)", first, last)
+	}
+	log.Info("Exporting batch of blocks", "count", last-first+1)
+
+	start, reported := time.Now(), time.Now()
+	for nr := first; nr <= last; nr++ {
+		block := bc.GetBlockByNumber(nr)
+		if block == nil {
+			return fmt.Errorf("export failed on #%d: not found", nr)
+		}
+		if err := block.ExtEncodeRLP(w); err != nil {
+			return err
+		}
+		if time.Since(reported) >= 8*time.Second {
+			log.Info("Exporting blocks", "exported", block.NumberU64()-first, "elapsed", common.PrettyDuration(time.Since(start)))
+			reported = time.Now()
+		}
+	}
+	return nil
+}
diff --git a/blockchain/blockchain_test.go b/blockchain/blockchain_test.go
index 8a54380a..a06b776e 100644
--- a/blockchain/blockchain_test.go
+++ b/blockchain/blockchain_test.go
@@ -18,69 +18,91 @@ package blockchain
 
 import (
 	"testing"
+	"time"
 
-	"github.com/fractalplatform/fractal/rawdb"
+	"github.com/fractalplatform/fractal/params"
 )
 
 func TestTheLastBlock(t *testing.T) {
-	genesis, db, chain, st, err := newCanonical(t, tengine)
-	if err != nil {
-		t.Error("newCanonical err", err)
-	}
+	// printLog(log.LvlDebug)
+	genesis := DefaultGenesis()
+	genesis.AllocAccounts = append(genesis.AllocAccounts, getDefaultGenesisAccounts()...)
+	chain := newCanonical(t, genesis)
 	defer chain.Stop()
 
-	prods, ht := makeProduceAndTime(st, 10)
-	_, _, blocks, err := makeNewChain(t, genesis, chain, &db, len(prods), ht, prods, makeTransferTx)
-	if err != nil {
-		t.Error("makeNewChain err", err)
-	}
-	if blocks[len(blocks)-1].Hash() != rawdb.ReadHeadBlockHash(chain.db) {
-		t.Fatalf("Write/Get HeadBlockHash failed")
-	}
+	allCadidates, allHeaderTimes := genCanonicalCadidatesAndTimes(genesis)
+	_, blocks := makeNewChain(t, genesis, chain, allCadidates, allHeaderTimes)
+
+	// check chain block hash
+	checkBlocksInsert(t, chain, blocks)
 }
 
-func TestForkChain(t *testing.T) {
-	genesis, db, chain, st, err := newCanonical(t, tengine)
-	if err != nil {
-		t.Error("newCanonical err", err)
-	}
-	defer chain.Stop()
+func TestSystemForkChain(t *testing.T) {
+	var (
+		allCadidates, allCadidates1     []string
+		allHeaderTimes, allHeaderTimes1 []uint64
+	)
+	// printLog(log.LvlTrace)
+	genesis := DefaultGenesis()
 
-	prods, ht := makeProduceAndTime(st, 10)
-	_, _, blocks, err := makeNewChain(t, genesis, chain, &db, len(prods), ht, prods, nil)
-	if err != nil {
-		t.Error("makeNewChain err", err)
-	}
+	allCadidates, allHeaderTimes = genCanonicalCadidatesAndTimes(genesis)
 
-	prods = append(prods[0:3], prods[10:]...)
-	ht = append(ht[0:3], ht[10:]...)
-	genesis1, db1, chain1, _, err := newCanonical(t, tengine)
-	if err != nil {
-		t.Error("newCanonical err", err)
-	}
-	defer chain.Stop()
+	allCadidates1 = append(allCadidates1, allCadidates...)
+	allCadidates1 = append(allCadidates1, "syscadidate0")
+	allCadidates1 = append(allCadidates1, params.DefaultChainconfig.SysName)
 
-	_, _, _, err = makeNewChain(t, genesis1, chain1, &db1, len(prods), ht, prods, makeTransferTx)
-	if err != nil {
-		t.Error("makeNewChain err", err)
-	}
-	_, err = chain1.InsertChain(blocks)
-	if err != nil {
-		t.Error(err)
-	}
-	if chain1.CurrentBlock().Hash() != blocks[len(blocks)-1].Hash() {
-		t.Fatalf("fork chain err! actual hash %x,  want hash %x ", chain1.CurrentBlock().Hash(), blocks[len(blocks)-1].Hash())
-	}
+	allHeaderTimes1 = append(allHeaderTimes1, allHeaderTimes...)
+	allHeaderTimes1 = append(allHeaderTimes1, allHeaderTimes[len(allHeaderTimes)-1]+1000*uint64(time.Millisecond)*3*7)
+	allHeaderTimes1 = append(allHeaderTimes1, allHeaderTimes1[len(allHeaderTimes1)-1]+1000*uint64(time.Millisecond)*3)
+
+	testFork(t, allCadidates, allCadidates1, allHeaderTimes, allHeaderTimes1)
 }
 
-func TestFullTxChain(t *testing.T) {
-	genesis, db, chain, st, err := newCanonical(t, tengine)
-	if err != nil {
-		t.Error("newCanonical err", err)
-	}
-	prods, ht := makeProduceAndTime(st, 100)
-	_, _, _, err = makeNewChain(t, genesis, chain, &db, len(prods), ht, prods, makeTransferTx)
+func genCanonicalCadidatesAndTimes(genesis *Genesis) ([]string, []uint64) {
+	var (
+		dposEpochNum   uint64 = 1
+		allCadidates   []string
+		allHeaderTimes []uint64
+	)
+
+	// geaerate block's cadidates and block header time
+	// system's cadidates headertimes
+	sysCadidates, sysHeaderTimes := makeSystemCadidatesAndTime(genesis.Timestamp, genesis)
+	allCadidates = append(allCadidates, sysCadidates...)
+	allHeaderTimes = append(allHeaderTimes, sysHeaderTimes...)
+
+	// elected cadidates headertimes
+	cadidates, headerTimes := makeCadidatesAndTime(sysHeaderTimes[len(sysHeaderTimes)-1], genesis, dposEpochNum)
+	allCadidates = append(allCadidates, cadidates[:12]...)
+	allHeaderTimes = append(allHeaderTimes, headerTimes[:12]...)
+
+	// elected cadidates headertimes
+	cadidates, headerTimes = makeCadidatesAndTime(headerTimes[len(headerTimes)-1], genesis, dposEpochNum)
+	allCadidates = append(allCadidates, cadidates[:12]...)
+	allHeaderTimes = append(allHeaderTimes, headerTimes[:12]...)
+
+	return allCadidates, allHeaderTimes
+}
+
+func testFork(t *testing.T, cadidates, forkCadidates []string, headerTimes, forkHeaderTimes []uint64) {
+	genesis := DefaultGenesis()
+	genesis.AllocAccounts = append(genesis.AllocAccounts, getDefaultGenesisAccounts()...)
+	chain := newCanonical(t, genesis)
+	defer chain.Stop()
+
+	chain, _ = makeNewChain(t, genesis, chain, cadidates, headerTimes)
+
+	// generate fork blocks
+	blocks := generateForkBlocks(t, DefaultGenesis(), forkCadidates, forkHeaderTimes)
+
+	_, err := chain.InsertChain(blocks)
 	if err != nil {
-		t.Error("makeNewChain err", err)
+		t.Fatal(err)
 	}
+
+	// check chain block hash
+	checkBlocksInsert(t, chain, blocks)
+
+	// check if is complete block chain
+	checkCompleteChain(t, chain)
 }
diff --git a/blockchain/blockgenerator.go b/blockchain/blockgenerator.go
index 67e20c63..65b6d368 100644
--- a/blockchain/blockgenerator.go
+++ b/blockchain/blockgenerator.go
@@ -17,6 +17,7 @@
 package blockchain
 
 import (
+	"fmt"
 	"math/big"
 
 	"github.com/fractalplatform/fractal/accountmanager"
@@ -42,7 +43,7 @@ type BlockGenerator struct {
 
 	config *params.ChainConfig
 	engine consensus.IEngine
-	bc     *BlockChain
+	*BlockChain
 }
 
 // SetCoinbase sets the coinbase of the generated block.
@@ -61,9 +62,9 @@ func (bg *BlockGenerator) SetCoinbase(addr common.Name) {
 func (bg *BlockGenerator) OffsetTime(seconds int64) {
 	bg.header.Time.Add(bg.header.Time, new(big.Int).SetInt64(seconds))
 	if bg.header.Time.Cmp(bg.parent.Header().Time) <= 0 {
-		panic("block time out of range")
+		panic(fmt.Sprintf("header time %d less than parent header time %v ", bg.header.Time.Uint64(), bg.parent.Time().Uint64()))
 	}
-	bg.header.Difficulty = bg.engine.CalcDifficulty(bg.bc, bg.header.Time.Uint64(), bg.parent.Header())
+	bg.header.Difficulty = bg.engine.CalcDifficulty(bg, bg.header.Time.Uint64(), bg.parent.Header())
 }
 
 // AddTx adds a transaction to the generated block.
@@ -72,20 +73,16 @@ func (bg *BlockGenerator) AddTx(tx *types.Transaction) {
 }
 
 // TxNonce retrun nonce
-func (bg *BlockGenerator) TxNonce(addr common.Name) uint64 {
+func (bg *BlockGenerator) TxNonce(name common.Name) uint64 {
 	am, _ := accountmanager.NewAccountManager(bg.statedb)
-	a, err := am.GetAccountByName(addr)
+	a, err := am.GetAccountByName(name)
 	if err != nil {
-		return 0
+		panic(fmt.Sprintf("name: %v, GetTxNonce failed: %v", name, err))
 	}
 	if a == nil {
 		panic("Account Not exist")
 	}
-	nonce := a.GetNonce()
-	//if err != nil {
-	//	panic(fmt.Sprintf("addr GetTxNonce failed: %v", err))
-	//}
-	return nonce
+	return a.GetNonce()
 }
 
 type chainContext struct {
@@ -99,16 +96,20 @@ func (cc *chainContext) Author(header *types.Header) (common.Name, error) {
 // AddTxWithChain adds a transaction to the generated block.
 func (bg *BlockGenerator) AddTxWithChain(tx *types.Transaction) {
 	if bg.gasPool == nil {
-		bg.SetCoinbase(bg.bc.genesisBlock.Coinbase())
+		bg.SetCoinbase(bg.genesisBlock.Coinbase())
 	}
 
 	bg.statedb.Prepare(tx.Hash(), common.Hash{}, len(bg.txs))
 
-	receipt, _, err := bg.bc.processor.ApplyTransaction(&bg.header.Coinbase, bg.gasPool, bg.statedb, bg.header, tx, &bg.header.GasUsed, vm.Config{})
+	receipt, _, err := bg.processor.ApplyTransaction(&bg.header.Coinbase, bg.gasPool, bg.statedb, bg.header, tx, &bg.header.GasUsed, vm.Config{})
 	if err != nil {
-		panic(err)
+		panic(fmt.Sprintf(" apply transaction hash:%v ,err %v", tx.Hash().Hex(), err))
 	}
 
 	bg.txs = append(bg.txs, tx)
 	bg.receipts = append(bg.receipts, receipt)
 }
+
+func (bg *BlockGenerator) CurrentHeader() *types.Header {
+	return bg.parent.Head
+}
diff --git a/blockchain/error.go b/blockchain/error.go
index 9e045dc7..411d02e0 100644
--- a/blockchain/error.go
+++ b/blockchain/error.go
@@ -28,6 +28,8 @@ var (
 
 	ErrNoGenesis = errors.New("Genesis not found in chain")
 
+	errReorgSystemBlock = errors.New("not reorg system block")
+
 	errGenesisNoConfig = errors.New("genesis has no chain configuration")
 
 	errGenesisNoDpos = errors.New("genesis has no dpos configuration")
@@ -40,5 +42,5 @@ type GenesisMismatchError struct {
 }
 
 func (e *GenesisMismatchError) Error() string {
-	return fmt.Sprintf("database already contains an incompatible genesis block (have %x, new %x)", e.Stored[:8], e.New[:8])
+	return fmt.Sprintf("database already contains an incompatible genesis block (have %x, new %x)", e.Stored[:], e.New[:])
 }
diff --git a/blockchain/forkcontroller.go b/blockchain/forkcontroller.go
index 9214906f..b2a4ea8a 100644
--- a/blockchain/forkcontroller.go
+++ b/blockchain/forkcontroller.go
@@ -62,7 +62,7 @@ func NewForkController(cfg *ForkConfig, chaincfg *params.ChainConfig) *ForkContr
 func (fc *ForkController) getForkInfo(statedb *state.StateDB) (ForkInfo, error) {
 	info := ForkInfo{}
 
-	infoBytes, err := statedb.Get(fc.chainCfg.SysName.String(), forkInfo)
+	infoBytes, err := statedb.Get(fc.chainCfg.ChainName, forkInfo)
 	if err != nil {
 		return info, err
 	}
@@ -84,22 +84,18 @@ func (fc *ForkController) putForkInfo(info ForkInfo, statedb *state.StateDB) err
 		return err
 	}
 
-	statedb.Put(fc.chainCfg.SysName.String(), forkInfo, infoBytes)
+	statedb.Put(fc.chainCfg.ChainName, forkInfo, infoBytes)
 	return nil
 }
 
 func (fc *ForkController) update(block *types.Block, statedb *state.StateDB) error {
-	// first hard fork at a specific height
-	if block.NumberU64() < params.TheForkNum {
-		return nil
-	}
-
 	info, err := fc.getForkInfo(statedb)
 	if err != nil {
 		return err
 	}
 
-	if block.CurForkID() != block.NextForkID() {
+	// treat older version as oldest version
+	if block.CurForkID() != block.NextForkID() && info.NextForkID <= block.NextForkID() {
 		if info.NextForkID < block.NextForkID() {
 			// update next forkID
 			info.NextForkID = block.NextForkID()
@@ -108,11 +104,7 @@ func (fc *ForkController) update(block *types.Block, statedb *state.StateDB) err
 
 		info.NextForkIDBlockNum++
 		if info.CurForkIDBlockNum+info.NextForkIDBlockNum >= fc.cfg.ForkBlockNum {
-			if info.CurForkIDBlockNum != 0 {
-				info.CurForkIDBlockNum--
-			} else {
-				info.NextForkIDBlockNum--
-			}
+			info.CurForkIDBlockNum--
 		}
 	} else {
 		info.CurForkIDBlockNum++
@@ -143,28 +135,22 @@ func (fc *ForkController) currentForkID(statedb *state.StateDB) (uint64, uint64,
 }
 
 func (fc *ForkController) checkForkID(header *types.Header, state *state.StateDB) error {
-	// first hard fork at a specific height
-	if header.Number.Uint64() >= params.TheForkNum {
-		// check current fork id and next fork id
-		if curForkID, _, err := fc.currentForkID(state); err != nil {
-			return err
-		} else if header.CurForkID() != curForkID || header.NextForkID() < curForkID {
-			return fmt.Errorf("invild header curForkID: %v, header nextForkID: %v,actual curForkID %v, header hash: %v, header number: %v",
-				header.CurForkID(), header.NextForkID(), curForkID, header.Hash().Hex(), header.Number.Uint64())
-		}
+	// check current fork id and next fork id
+	if curForkID, _, err := fc.currentForkID(state); err != nil {
+		return err
+	} else if header.CurForkID() != curForkID || header.NextForkID() < curForkID {
+		return fmt.Errorf("invild header curForkID: %v, header nextForkID: %v,actual curForkID %v, header hash: %v, header number: %v",
+			header.CurForkID(), header.NextForkID(), curForkID, header.Hash().Hex(), header.Number.Uint64())
 	}
 	return nil
 }
 
 func (fc *ForkController) fillForkID(header *types.Header, state *state.StateDB) error {
-	// first hard fork at a specific height
-	if header.Number.Uint64() >= params.TheForkNum {
-		// check current fork id and next fork id
-		curForkID, nextForkID, err := fc.currentForkID(state)
-		if err != nil {
-			return err
-		}
-		header.WithForkID(curForkID, nextForkID)
+	// check current fork id and next fork id
+	curForkID, nextForkID, err := fc.currentForkID(state)
+	if err != nil {
+		return err
 	}
+	header.WithForkID(curForkID, nextForkID)
 	return nil
 }
diff --git a/blockchain/forkcontroller_test.go b/blockchain/forkcontroller_test.go
index 75530198..3af4141f 100644
--- a/blockchain/forkcontroller_test.go
+++ b/blockchain/forkcontroller_test.go
@@ -36,7 +36,7 @@ func TestForkController(t *testing.T) {
 	)
 
 	fc := NewForkController(testcfg, params.DefaultChainconfig)
-	var height = int64(params.TheForkNum)
+	var height int64
 	for j := 0; j < 2; j++ {
 		for i := 0; i < 8; i++ {
 
@@ -71,7 +71,7 @@ func TestUpdateDifferentForkBlock(t *testing.T) {
 	)
 
 	fc := NewForkController(testcfg, params.DefaultChainconfig)
-	var height = int64(params.TheForkNum)
+	var height int64
 	for j := 0; j < 2; j++ {
 		for i := 0; i < 7; i++ {
 			block := &types.Block{Head: &types.Header{Number: big.NewInt(height)}}
@@ -99,7 +99,7 @@ func TestFillForkID(t *testing.T) {
 
 	fc := NewForkController(testcfg, params.DefaultChainconfig)
 
-	header := &types.Header{Number: big.NewInt(int64(params.TheForkNum))}
+	header := &types.Header{Number: big.NewInt(0)}
 
 	assert.NoError(t, fc.fillForkID(header, statedb))
 
diff --git a/blockchain/gen_genesis.go b/blockchain/gen_genesis.go
index 121d8765..84feb783 100644
--- a/blockchain/gen_genesis.go
+++ b/blockchain/gen_genesis.go
@@ -16,90 +16,10 @@
 
 package blockchain
 
-import (
-	"encoding/json"
-	"math/big"
+// func (g *Genesis) MarshalJSON() ([]byte, error) {
+// 	return json.Marshal(g)
+// }
 
-	"github.com/ethereum/go-ethereum/common/hexutil"
-	"github.com/ethereum/go-ethereum/common/math"
-	"github.com/fractalplatform/fractal/asset"
-	"github.com/fractalplatform/fractal/common"
-	"github.com/fractalplatform/fractal/consensus/dpos"
-	"github.com/fractalplatform/fractal/params"
-)
-
-func (g Genesis) MarshalJSON() ([]byte, error) {
-	type genesisJSON struct {
-		Config        *params.ChainConfig   `json:"config"`
-		Dpos          *dpos.Config          `json:"dpos"`
-		Nonce         math.HexOrDecimal64   `json:"nonce"`
-		Timestamp     math.HexOrDecimal64   `json:"timestamp"`
-		ExtraData     hexutil.Bytes         `json:"extraData"`
-		GasLimit      math.HexOrDecimal64   `json:"gasLimit"`
-		Difficulty    *math.HexOrDecimal256 `json:"difficulty"`
-		Mixhash       common.Hash           `json:"mixHash"`
-		Coinbase      common.Name           `json:"coinbase"`
-		AllocAccounts []*GenesisAccount     `json:"allocAccounts"`
-		AllocAssets   []*asset.AssetObject  `json:"allocAssets"`
-	}
-	var enc genesisJSON
-	enc.Config = g.Config
-	enc.Dpos = g.Dpos
-	enc.Timestamp = math.HexOrDecimal64(g.Timestamp)
-	enc.ExtraData = g.ExtraData
-	enc.GasLimit = math.HexOrDecimal64(g.GasLimit)
-	enc.Difficulty = (*math.HexOrDecimal256)(g.Difficulty)
-	enc.Coinbase = g.Coinbase
-	enc.AllocAccounts = g.AllocAccounts
-	enc.AllocAssets = g.AllocAssets
-	return json.Marshal(&enc)
-}
-
-func (g *Genesis) UnmarshalJSON(input []byte) error {
-	type genesisJSON struct {
-		Config        *params.ChainConfig   `json:"config"`
-		Dpos          *dpos.Config          `json:"dpos"`
-		Nonce         *math.HexOrDecimal64  `json:"nonce"`
-		Timestamp     *math.HexOrDecimal64  `json:"timestamp"`
-		ExtraData     *hexutil.Bytes        `json:"extraData"`
-		GasLimit      *math.HexOrDecimal64  `json:"gasLimit"`
-		Difficulty    *math.HexOrDecimal256 `json:"difficulty"`
-		Mixhash       *common.Hash          `json:"mixHash"`
-		Coinbase      common.Name           `json:"coinbase"`
-		AllocAccounts []*GenesisAccount     `json:"allocAccounts"`
-		AllocAssets   []*asset.AssetObject  `json:"allocAssets"`
-	}
-	var dec genesisJSON
-	if err := json.Unmarshal(input, &dec); err != nil {
-		return err
-	}
-	if dec.Config != nil {
-		g.Config = dec.Config
-	}
-	if dec.Dpos != nil {
-		g.Dpos = dec.Dpos
-	}
-	if dec.Timestamp != nil {
-		g.Timestamp = uint64(*dec.Timestamp)
-	}
-	if dec.ExtraData != nil {
-		g.ExtraData = *dec.ExtraData
-	}
-	if dec.GasLimit != nil {
-		g.GasLimit = uint64(*dec.GasLimit)
-	}
-	if dec.Difficulty != nil {
-		g.Difficulty = (*big.Int)(dec.Difficulty)
-	}
-	if len(dec.Coinbase) > 0 {
-		g.Coinbase = dec.Coinbase
-	}
-	if len(dec.AllocAccounts) > 0 {
-		g.AllocAccounts = dec.AllocAccounts
-	}
-
-	if len(dec.AllocAssets) > 0 {
-		g.AllocAssets = dec.AllocAssets
-	}
-	return nil
-}
+// func (g *Genesis) UnmarshalJSON(input []byte) error {
+// 	return json.Unmarshal(input, &g)
+// }
diff --git a/blockchain/gen_genesis_test.go b/blockchain/gen_genesis_test.go
index 66ab0150..aee957ba 100644
--- a/blockchain/gen_genesis_test.go
+++ b/blockchain/gen_genesis_test.go
@@ -16,6 +16,7 @@
 package blockchain
 
 import (
+	"bytes"
 	"encoding/json"
 	"fmt"
 	"testing"
@@ -24,64 +25,22 @@ import (
 func TestGenGenesis(t *testing.T) {
 	genesis := DefaultGenesis()
 
-	j, err := genesis.MarshalJSON()
+	j, err := json.Marshal(genesis)
 	if err != nil {
 		t.Fatal(fmt.Sprintf("genesis marshal --- %v", err))
 	}
 
-	if err := genesis.UnmarshalJSON(j); err != nil {
+	//fmt.Println(string(j))
+
+	if err := json.Unmarshal(j, &genesis); err != nil {
 		t.Fatal(fmt.Sprintf("genesis Unmarshal --- %v", err))
 	}
-	_, err = genesis.MarshalJSON()
+	nj, err := json.Marshal(genesis)
 	if err != nil {
 		t.Fatal(fmt.Sprintf("genesis marshal --- %v", err))
 	}
 
-	s := `{
-		"config": {
-			"chainId": 1,
-			"sysName": "ftsystemio",
-			"sysToken": "fractalfoundation"
-		},
-		"dpos": {
-			"MaxURLLen": 512,
-			"UnitStake": 1000,
-			"ProducerMinQuantity": 10000,
-			"VoterMinQuantity": 1,
-			"ActivatedMinQuantity": 1000000,
-			"BlockInterval": 3000000000,
-			"BlockFrequency": 6,
-			"ProducerScheduleSize": 21,
-			"DelayEcho": 0,
-			"AccountName": "fdpos",
-			"SystemName": "ft",
-			"ExtraBlockRewardUnit": 1,
-			"BlockReward": 20
-		},
-		"timestamp": "0x0",
-		"extraData": "0x5a302047656e6573697320426c6f636b",
-		"gasLimit": "0x5f5e100",
-		"difficulty": "0x20000",
-		"coinbase": "systemio",
-		"allocAccounts": [{
-			"name": "ftsystemio",
-			"pubKey": "0x047db227d7094ce215c3a0f57e1bcc732551fe351f94249471934567e0f5dc1bf795962b8cccb87a2eb56b29fbe37d614e2f4c3c45b789ae4f1f51f4cb21972ffd"
-		}],
-		"allocAssets": [{
-			"assetname": "ftperfoundation",
-			"symbol": "ft",
-			"amount": 100000000,
-			"decimals": 18,
-			"owner": "ftsystemio"
-		}]
-	}`
-	if err := json.Unmarshal([]byte(s), genesis); err != nil {
-		t.Fatal(fmt.Sprintf("genesis unmarshal --- %v", err))
-	}
-
-	j, err = json.Marshal(genesis)
-	if err != nil {
-		t.Fatal(fmt.Sprintf("genesis marshal --- %v", err))
+	if bytes.Compare(j, nj) != 0 {
+		t.Fatal(fmt.Sprintf("genesis mismatch --- %v", err))
 	}
-
 }
diff --git a/blockchain/genesis.go b/blockchain/genesis.go
index 30029ae1..d8316b91 100644
--- a/blockchain/genesis.go
+++ b/blockchain/genesis.go
@@ -17,16 +17,19 @@
 package blockchain
 
 import (
+	"encoding/json"
+	"errors"
 	"fmt"
 	"math/big"
+	"strings"
 	"time"
 
-	"github.com/ethereum/go-ethereum/common/hexutil"
+	"github.com/fractalplatform/fractal/consensus/dpos"
+
 	"github.com/ethereum/go-ethereum/log"
 	am "github.com/fractalplatform/fractal/accountmanager"
-	"github.com/fractalplatform/fractal/asset"
+	at "github.com/fractalplatform/fractal/asset"
 	"github.com/fractalplatform/fractal/common"
-	"github.com/fractalplatform/fractal/consensus/dpos"
 	"github.com/fractalplatform/fractal/p2p/enode"
 	"github.com/fractalplatform/fractal/params"
 	"github.com/fractalplatform/fractal/rawdb"
@@ -34,34 +37,77 @@ import (
 	"github.com/fractalplatform/fractal/types"
 	"github.com/fractalplatform/fractal/utils/fdb"
 	memdb "github.com/fractalplatform/fractal/utils/fdb/memdb"
+	"github.com/fractalplatform/fractal/utils/rlp"
 )
 
 // GenesisAccount is an account in the state of the genesis block.
 type GenesisAccount struct {
-	Name   common.Name   `json:"name,omitempty"`
+	Name   string        `json:"name,omitempty"`
 	PubKey common.PubKey `json:"pubKey,omitempty"`
 }
 
+// GenesisCadidate is an cadicate in the state of the genesis block.
+type GenesisCadidate struct {
+	Name  string   `json:"name,omitempty"`
+	URL   string   `json:"url,omitempty"`
+	Stake *big.Int `json:"stake,omitempty"`
+}
+
+// GenesisAsset is an asset in the state of the genesis block.
+type GenesisAsset struct {
+	Name       string   `json:"name,omitempty"`
+	Symbol     string   `json:"symbol,omitempty"`
+	Amount     *big.Int `json:"amount,omitempty"`
+	Decimals   uint64   `json:"decimals,omitempty"`
+	Founder    string   `json:"founder,omitempty"`
+	Owner      string   `json:"owner,omitempty"`
+	UpperLimit *big.Int `json:"upperLimit,omitempty"`
+}
+
 // Genesis specifies the header fields, state of a genesis block.
 type Genesis struct {
-	Config        *params.ChainConfig  `json:"config"`
-	Dpos          *dpos.Config         `json:"dpos"`
-	Timestamp     uint64               `json:"timestamp"`
-	ExtraData     []byte               `json:"extraData"`
-	GasLimit      uint64               `json:"gasLimit" `
-	Difficulty    *big.Int             `json:"difficulty" `
-	Coinbase      common.Name          `json:"coinbase"`
-	AllocAccounts []*GenesisAccount    `json:"allocAccounts"`
-	AllocAssets   []*asset.AssetObject `json:"allocAssets"`
+	Config         *params.ChainConfig `json:"config,omitempty"`
+	Timestamp      uint64              `json:"timestamp,omitempty"`
+	GasLimit       uint64              `json:"gasLimit,omitempty" `
+	Difficulty     *big.Int            `json:"difficulty,omitempty" `
+	AllocAccounts  []*GenesisAccount   `json:"allocAccounts,omitempty"`
+	AllocCadidates []*GenesisCadidate  `json:"allocCadidates,omitempty"`
+	AllocAssets    []*GenesisAsset     `json:"allocAssets,omitempty"`
+}
+
+func dposConfig(cfg *params.ChainConfig) *dpos.Config {
+	return &dpos.Config{
+		MaxURLLen:            cfg.DposCfg.MaxURLLen,
+		UnitStake:            cfg.DposCfg.UnitStake,
+		CadidateMinQuantity:  cfg.DposCfg.CadidateMinQuantity,
+		VoterMinQuantity:     cfg.DposCfg.VoterMinQuantity,
+		ActivatedMinQuantity: cfg.DposCfg.ActivatedMinQuantity,
+		BlockInterval:        cfg.DposCfg.BlockInterval,
+		BlockFrequency:       cfg.DposCfg.BlockFrequency,
+		CadidateScheduleSize: cfg.DposCfg.CadidateScheduleSize,
+		DelayEcho:            cfg.DposCfg.DelayEcho,
+		AccountName:          cfg.DposName,
+		SystemName:           cfg.SysName,
+		SystemURL:            cfg.ChainURL,
+		ExtraBlockReward:     cfg.DposCfg.ExtraBlockReward,
+		BlockReward:          cfg.DposCfg.BlockReward,
+		Decimals:             cfg.SysTokenDecimals,
+	}
 }
 
 // SetupGenesisBlock The returned chain configuration is never nil.
-func SetupGenesisBlock(db fdb.Database, genesis *Genesis) (*params.ChainConfig, *dpos.Config, common.Hash, error) {
+func SetupGenesisBlock(db fdb.Database, genesis *Genesis) (chainCfg *params.ChainConfig, dcfg *dpos.Config, hash common.Hash, err error) {
+	chainCfg = params.DefaultChainconfig
+	dcfg = dpos.DefaultConfig
+	hash = common.Hash{}
+	defer func() {
+		if e := recover(); e != nil {
+			err = errors.New(e.(string))
+		}
+	}()
+
 	if genesis != nil && genesis.Config == nil {
-		return params.DefaultChainconfig, dpos.DefaultConfig, common.Hash{}, errGenesisNoConfig
-	}
-	if genesis != nil && genesis.Dpos == nil {
-		return params.DefaultChainconfig, dpos.DefaultConfig, common.Hash{}, errGenesisNoDpos
+		return params.DefaultChainconfig, dposConfig(params.DefaultChainconfig), common.Hash{}, errGenesisNoConfig
 	}
 
 	// Just commit the new block if there is no stored genesis block.
@@ -72,37 +118,64 @@ func SetupGenesisBlock(db fdb.Database, genesis *Genesis) (*params.ChainConfig,
 		}
 		block, err := genesis.Commit(db)
 		log.Info("Writing genesis block", "hash", block.Hash().Hex())
-		return genesis.Config, genesis.Dpos, block.Hash(), err
+
+		return genesis.Config, dposConfig(genesis.Config), block.Hash(), err
 	}
 
 	// Check whether the genesis block is already written.
 	if genesis != nil {
-		hash := genesis.ToBlock(nil).Hash()
+		blk, _ := genesis.ToBlock(nil)
+		hash := blk.Hash()
 		if hash != stored {
-			return genesis.Config, genesis.Dpos, hash, &GenesisMismatchError{stored, hash}
+			return genesis.Config, dposConfig(genesis.Config), hash, &GenesisMismatchError{stored, hash}
 		}
 	}
-	// Get the existing dpos configuration.
-	newdpos := genesis.dposOrDefault(stored)
-
-	// Get the existing chain configuration.
 	newcfg := genesis.configOrDefault(stored)
 
 	height := rawdb.ReadHeaderNumber(db, rawdb.ReadHeadHeaderHash(db))
 	if height == nil {
-		return newcfg, newdpos, stored, fmt.Errorf("missing block number for head header hash")
+		return newcfg, dposConfig(newcfg), common.Hash{}, fmt.Errorf("missing block number for head header hash")
 	}
-	err := newdpos.Write(db, append([]byte("ft-dpos-"), stored.Bytes()...))
-	rawdb.WriteChainConfig(db, stored, newcfg)
-	return newcfg, newdpos, stored, err
+
+	storedcfg := rawdb.ReadChainConfig(db, stored)
+	if storedcfg == nil {
+		return newcfg, dposConfig(newcfg), common.Hash{}, fmt.Errorf("Found genesis block without chain config")
+	}
+	am.SetAccountNameConfig(&am.Config{
+		AccountNameLevel:     storedcfg.AccountNameCfg.Level,
+		AccountNameLength:    storedcfg.AccountNameCfg.Length,
+		SubAccountNameLength: storedcfg.AccountNameCfg.SubLength,
+	})
+	at.SetAssetNameConfig(&at.Config{
+		AssetNameLength:    storedcfg.AssetNameCfg.Length,
+		AssetNameLevel:     storedcfg.AssetNameCfg.Level,
+		SubAssetNameLength: storedcfg.AssetNameCfg.SubLength,
+	})
+	am.SetSysName(common.StrToName(storedcfg.AccountName))
+	return storedcfg, dposConfig(storedcfg), stored, nil
 }
 
 // ToBlock creates the genesis block and writes state of a genesis specification
 // to the given database (or discards it if nil).
-func (g *Genesis) ToBlock(db fdb.Database) *types.Block {
+func (g *Genesis) ToBlock(db fdb.Database) (*types.Block, []*types.Receipt) {
+	verify := true
 	if db == nil {
+		verify = false
 		db = memdb.NewMemDatabase()
 	}
+	detailTx := &types.DetailTx{}
+	var internals []*types.DetailAction
+	am.SetAccountNameConfig(&am.Config{
+		AccountNameLevel:     g.Config.AccountNameCfg.Level,
+		AccountNameLength:    g.Config.AccountNameCfg.Length,
+		SubAccountNameLength: g.Config.AccountNameCfg.SubLength,
+	})
+	at.SetAssetNameConfig(&at.Config{
+		AssetNameLength:    g.Config.AssetNameCfg.Length,
+		AssetNameLevel:     g.Config.AssetNameCfg.Level,
+		SubAssetNameLength: g.Config.AssetNameCfg.SubLength,
+	})
+	am.SetSysName(common.StrToName(g.Config.AccountName))
 	number := big.NewInt(0)
 	statedb, err := state.New(common.Hash{}, state.NewDatabase(db))
 	if err != nil {
@@ -114,37 +187,139 @@ func (g *Genesis) ToBlock(db fdb.Database) *types.Block {
 	}
 	//p2p
 	for _, node := range g.Config.BootNodes {
+		if len(node) == 0 {
+			continue
+		}
 		if _, err := enode.ParseV4(node); err != nil {
 			panic(fmt.Sprintf("genesis bootnodes err: %v in %v", err, node))
 		}
 	}
 
-	// dpos
-	if !common.IsValidName(g.Dpos.SystemName) {
-		panic(fmt.Sprintf("genesis invalid dpos account name %v", g.Dpos.SystemName))
+	actActions := []*types.Action{}
+	if err := dpos.Genesis(dposConfig(g.Config), statedb, number.Uint64()); err != nil {
+		panic(fmt.Sprintf("genesis dpos err %v", err))
 	}
-	g.AllocAccounts = append(g.AllocAccounts, &GenesisAccount{
-		Name:   common.StrToName(g.Dpos.AccountName),
-		PubKey: common.PubKey{},
-	})
-	if err := dpos.Genesis(g.Dpos, statedb, number.Uint64()); err != nil {
-		panic(fmt.Sprintf("genesis dpos err %v", g.Dpos.SystemName))
+
+	chainName := common.Name(g.Config.ChainName)
+	accoutName := common.Name(g.Config.AccountName)
+	// chain name
+	act := &am.AccountAction{
+		AccountName: chainName,
+		PublicKey:   common.PubKey{},
 	}
+	payload, _ := rlp.EncodeToBytes(act)
+	actActions = append(actActions, types.NewAction(
+		types.CreateAccount,
+		common.Name(""),
+		accoutName,
+		0,
+		0,
+		0,
+		big.NewInt(0),
+		payload,
+	))
 
 	for _, account := range g.AllocAccounts {
-		if err := accountManager.CreateAccount(account.Name, common.Name(""), 0, account.PubKey); err != nil {
-			panic(fmt.Sprintf("genesis create account err %v", err))
+		pname := common.Name("")
+		slt := strings.Split(account.Name, ".")
+		if len(slt) > 1 {
+			pname = common.Name(slt[0])
 		}
+		act := &am.AccountAction{
+			AccountName: common.StrToName(account.Name),
+			PublicKey:   account.PubKey,
+		}
+		payload, _ := rlp.EncodeToBytes(act)
+		actActions = append(actActions, types.NewAction(
+			types.CreateAccount,
+			pname,
+			accoutName,
+			0,
+			0,
+			0,
+			big.NewInt(0),
+			payload,
+		))
 	}
 
+	for index, action := range actActions {
+		internalLogs, err := accountManager.Process(&types.AccountManagerContext{Action: action, Number: 0})
+		if err != nil {
+			panic(fmt.Sprintf("genesis create account %v,err %v", index, err))
+		}
+		internals = append(internals, &types.DetailAction{InternalActions: internalLogs})
+	}
+
+	astActions := []*types.Action{}
 	for _, asset := range g.AllocAssets {
-		if err := accountManager.IssueAsset(asset); err != nil {
-			panic(fmt.Sprintf("genesis issue asset err %v", err))
+		pname := common.Name("")
+		slt := strings.Split(asset.Name, ".")
+		if len(slt) > 1 {
+			if ast, _ := accountManager.GetAssetInfoByName(slt[0]); ast == nil {
+				panic(fmt.Sprintf("parent asset not exist %v", ast.AssetName))
+			} else {
+				pname = ast.Owner
+			}
+		}
+		ast := &at.AssetObject{
+			AssetName:  asset.Name,
+			Symbol:     asset.Symbol,
+			Amount:     asset.Amount,
+			Decimals:   asset.Decimals,
+			Founder:    common.StrToName(asset.Founder),
+			Owner:      common.StrToName(asset.Owner),
+			UpperLimit: asset.UpperLimit,
 		}
+		payload, _ := rlp.EncodeToBytes(ast)
+		astActions = append(astActions, types.NewAction(
+			types.IssueAsset,
+			pname,
+			accoutName,
+			0,
+			0,
+			0,
+			big.NewInt(0),
+			payload,
+		))
+	}
+
+	for index, action := range astActions {
+		internalLogs, err := accountManager.Process(&types.AccountManagerContext{Action: action, Number: 0})
+		if err != nil {
+			panic(fmt.Sprintf("genesis create asset %v,err %v", index, err))
+		}
+		internals = append(internals, &types.DetailAction{InternalActions: internalLogs})
+	}
+
+	if verify {
+		if ok, err := accountManager.AccountIsExist(common.StrToName(g.Config.SysName)); !ok {
+			panic(fmt.Sprintf("system is not exist %v", err))
+		}
+		if ok, err := accountManager.AccountIsExist(common.StrToName(g.Config.AccountName)); !ok {
+			panic(fmt.Sprintf("account is not exist %v", err))
+		}
+		if ok, err := accountManager.AccountIsExist(common.StrToName(g.Config.DposName)); !ok {
+			panic(fmt.Sprintf("dpos is not exist %v", err))
+		}
+		assetInfo, err := accountManager.GetAssetInfoByName(g.Config.SysToken)
+		if err != nil {
+			panic(fmt.Sprintf("genesis system asset err %v", err))
+		}
+		g.Config.SysTokenID = assetInfo.AssetId
+		g.Config.SysTokenDecimals = assetInfo.Decimals
+	}
+	sys := dpos.NewSystem(statedb, dposConfig(g.Config))
+	for _, cadidate := range g.AllocCadidates {
+		_ = cadidate
+		_ = sys
 	}
 
 	root := statedb.IntermediateRoot()
-	gjson, _ := g.MarshalJSON()
+	gjson, err := json.Marshal(g)
+	if err != nil {
+		panic(fmt.Sprintf("genesis json marshal json err %v", err))
+	}
+
 	head := &types.Header{
 		Number:     number,
 		Time:       new(big.Int).SetUint64(g.Timestamp),
@@ -153,11 +328,30 @@ func (g *Genesis) ToBlock(db fdb.Database) *types.Block {
 		GasLimit:   g.GasLimit,
 		GasUsed:    0,
 		Difficulty: g.Difficulty,
-		Coinbase:   g.Coinbase,
+		Coinbase:   common.StrToName(g.Config.SysName),
 		Root:       root,
 	}
 
-	block := types.NewBlock(head, nil, nil)
+	actions := []*types.Action{}
+	actions = append(actions, actActions...)
+	actions = append(actions, astActions...)
+	tx := types.NewTransaction(0, big.NewInt(0), actions...)
+	receipt := types.NewReceipt(root[:], 0, 0)
+	receipt.TxHash = tx.Hash()
+	for index := range actions {
+		receipt.ActionResults = append(receipt.ActionResults, &types.ActionResult{
+			Status:  1,
+			Index:   uint64(index),
+			GasUsed: 0,
+		})
+	}
+
+	detailTx.TxHash = receipt.TxHash
+	detailTx.Actions = internals
+	receipt.SetInternalTxsLog(detailTx)
+
+	receipts := []*types.Receipt{receipt}
+	block := types.NewBlock(head, []*types.Transaction{tx}, receipts)
 	batch := db.NewBatch()
 	roothash, err := statedb.Commit(batch, block.Hash(), block.NumberU64())
 	if err != nil {
@@ -167,43 +361,30 @@ func (g *Genesis) ToBlock(db fdb.Database) *types.Block {
 	if err := batch.Write(); err != nil {
 		panic(fmt.Sprintf("genesis batch write err: %v", err))
 	}
-	return block
+	return block, receipts
 }
 
 // Commit writes the block and state of a genesis specification to the database.
 // The block is committed as the canonical head block.
 func (g *Genesis) Commit(db fdb.Database) (*types.Block, error) {
-	block := g.ToBlock(db)
+	block, receipts := g.ToBlock(db)
 	if block.Number().Sign() != 0 {
 		return nil, fmt.Errorf("can't commit genesis block with number > 0")
 	}
 	rawdb.WriteTd(db, block.Hash(), block.NumberU64(), g.Difficulty)
 	rawdb.WriteBlock(db, block)
-	rawdb.WriteReceipts(db, block.Hash(), block.NumberU64(), nil)
+	rawdb.WriteTxLookupEntries(db, block)
+	rawdb.WriteReceipts(db, block.Hash(), block.NumberU64(), receipts)
 	rawdb.WriteCanonicalHash(db, block.Hash(), block.NumberU64())
 	rawdb.WriteHeadBlockHash(db, block.Hash())
 	rawdb.WriteHeadHeaderHash(db, block.Hash())
 
-	config := g.Config
-	if config == nil {
-		config = params.DefaultChainconfig
-	}
-	dposConfig := g.Dpos
-	if dposConfig == nil {
-		dposConfig = dpos.DefaultConfig
-	}
+	rawdb.WriteChainConfig(db, block.Hash(), g.Config)
+	rawdb.WriteIrreversibleNumber(db, uint64(0))
 
-	rawdb.WriteChainConfig(db, block.Hash(), config)
 	return block, nil
 }
 
-func (g *Genesis) dposOrDefault(ghash common.Hash) *dpos.Config {
-	if g != nil {
-		return g.Dpos
-	}
-	return dpos.DefaultConfig
-}
-
 func (g *Genesis) configOrDefault(ghash common.Hash) *params.ChainConfig {
 	if g != nil {
 		return g.Config
@@ -215,36 +396,46 @@ func (g *Genesis) configOrDefault(ghash common.Hash) *params.ChainConfig {
 func DefaultGenesis() *Genesis {
 	gtime, _ := time.Parse("2006-01-02 15:04:05.999999999", "2019-01-16 00:00:00")
 	return &Genesis{
-		Config:        params.DefaultChainconfig,
-		Dpos:          dpos.DefaultConfig,
-		Timestamp:     uint64(gtime.UnixNano()),
-		ExtraData:     hexutil.MustDecode(hexutil.Encode([]byte("ft Genesis Block"))),
-		GasLimit:      params.GenesisGasLimit,
-		Difficulty:    params.GenesisDifficulty,
-		Coinbase:      params.DefaultChainconfig.SysName,
-		AllocAccounts: DefaultGenesisAccounts(),
-		AllocAssets:   DefaultGenesisAssets(),
+		Config:         params.DefaultChainconfig,
+		Timestamp:      uint64(gtime.UnixNano()),
+		GasLimit:       params.GenesisGasLimit,
+		Difficulty:     params.GenesisDifficulty,
+		AllocAccounts:  DefaultGenesisAccounts(),
+		AllocCadidates: DefaultGenesisCadidates(),
+		AllocAssets:    DefaultGenesisAssets(),
 	}
 }
 
 // DefaultGenesisAccounts returns the ft net genesis accounts.
 func DefaultGenesisAccounts() []*GenesisAccount {
-	pubKey := common.HexToPubKey(params.DefaultPubkeyHex)
 	return []*GenesisAccount{
 		&GenesisAccount{
 			Name:   params.DefaultChainconfig.SysName,
-			PubKey: pubKey,
+			PubKey: common.HexToPubKey("047db227d7094ce215c3a0f57e1bcc732551fe351f94249471934567e0f5dc1bf795962b8cccb87a2eb56b29fbe37d614e2f4c3c45b789ae4f1f51f4cb21972ffd"),
+		},
+		&GenesisAccount{
+			Name:   params.DefaultChainconfig.AccountName,
+			PubKey: common.HexToPubKey(""),
+		},
+		&GenesisAccount{
+			Name:   params.DefaultChainconfig.DposName,
+			PubKey: common.HexToPubKey(""),
 		},
 	}
 }
 
+// DefaultGenesisCadidates returns the ft net genesis cadidates.
+func DefaultGenesisCadidates() []*GenesisCadidate {
+	return []*GenesisCadidate{}
+}
+
 // DefaultGenesisAssets returns the ft net genesis assets.
-func DefaultGenesisAssets() []*asset.AssetObject {
+func DefaultGenesisAssets() []*GenesisAsset {
 	supply := new(big.Int)
 	supply.SetString("100000000000000000000000000000", 10)
-	return []*asset.AssetObject{
-		&asset.AssetObject{
-			AssetName:  params.DefaultChainconfig.SysToken,
+	return []*GenesisAsset{
+		&GenesisAsset{
+			Name:       params.DefaultChainconfig.SysToken,
 			Symbol:     "ft",
 			Amount:     supply,
 			Decimals:   18,
diff --git a/blockchain/genesis_test.go b/blockchain/genesis_test.go
index 145bcafa..e09edd9d 100644
--- a/blockchain/genesis_test.go
+++ b/blockchain/genesis_test.go
@@ -17,6 +17,8 @@
 package blockchain
 
 import (
+	"bytes"
+	"encoding/json"
 	"math/big"
 	"reflect"
 	"testing"
@@ -30,10 +32,10 @@ import (
 	memdb "github.com/fractalplatform/fractal/utils/fdb/memdb"
 )
 
-var defaultgenesisBlockHash = common.HexToHash("0x045dae5bce93fa1e02abba85ee6f645bf45ed54b2c60fdf238b03ffeaca46792")
+var defaultgenesisBlockHash = common.HexToHash("0x7c65665abff5ddcdeed945b7e373e742f0ceac50040bef2d71e2bbaf8e982d91")
 
 func TestDefaultGenesisBlock(t *testing.T) {
-	block := DefaultGenesis().ToBlock(nil)
+	block, _ := DefaultGenesis().ToBlock(nil)
 	if block.Hash() != defaultgenesisBlockHash {
 		t.Errorf("wrong mainnet genesis hash, got %v, want %v", block.Hash().Hex(), defaultgenesisBlockHash.Hex())
 	}
@@ -41,18 +43,19 @@ func TestDefaultGenesisBlock(t *testing.T) {
 
 func TestSetupGenesis(t *testing.T) {
 	var (
-		customghash = common.HexToHash("0x0a7c7f5747fc4c0820fc3322f9367383c827a3417448f5e0f870b69689c6646f")
+		customghash = common.HexToHash("0x1395829e52af8d75022d363a1645467235f3862fd1dbed71de90fb6cf1f8aeff")
 		customg     = Genesis{
-			Config:        &params.ChainConfig{ChainID: big.NewInt(3), SysName: "systemio", SysToken: "fractalfoundation"},
-			Dpos:          dpos.DefaultConfig,
-			Coinbase:      "coinbase",
-			AllocAccounts: DefaultGenesisAccounts(),
-			AllocAssets:   DefaultGenesisAssets(),
+			Config:         params.DefaultChainconfig.Copy(),
+			AllocAccounts:  DefaultGenesisAccounts(),
+			AllocAssets:    DefaultGenesisAssets(),
+			AllocCadidates: DefaultGenesisCadidates(),
 		}
 		oldcustomg     = customg
-		oldcustomghash = common.HexToHash("0xd713f99f8172e387789aafcfb3bd5b9a3101f1a3dfcce7b696dc44f716c17ad5")
+		oldcustomghash = common.HexToHash("18212fd24fb4a27d4a35731d85615a0a050970e6b0443db6011c46e6258c5e66")
 	)
-	oldcustomg.Config = &params.ChainConfig{ChainID: big.NewInt(2), SysName: "ftsystem", SysToken: "ftoken"}
+	customg.Config.ChainID = big.NewInt(5)
+	oldcustomg.Config = customg.Config.Copy()
+	oldcustomg.Config.ChainID = big.NewInt(6)
 
 	tests := []struct {
 		name       string
@@ -69,7 +72,6 @@ func TestSetupGenesis(t *testing.T) {
 			},
 			wantErr:    errGenesisNoConfig,
 			wantConfig: params.DefaultChainconfig,
-			wantDpos:   dpos.DefaultConfig,
 		},
 		{
 			name: "no block in DB, genesis == nil",
@@ -78,7 +80,6 @@ func TestSetupGenesis(t *testing.T) {
 			},
 			wantHash:   defaultgenesisBlockHash,
 			wantConfig: params.DefaultChainconfig,
-			wantDpos:   dpos.DefaultConfig,
 		},
 		{
 			name: "mainnet block in DB, genesis == nil",
@@ -90,7 +91,6 @@ func TestSetupGenesis(t *testing.T) {
 			},
 			wantHash:   defaultgenesisBlockHash,
 			wantConfig: params.DefaultChainconfig,
-			wantDpos:   dpos.DefaultConfig,
 		},
 		{
 			name: "compatible config in DB",
@@ -106,35 +106,33 @@ func TestSetupGenesis(t *testing.T) {
 			},
 			wantHash:   customghash,
 			wantConfig: customg.Config,
-			wantDpos:   customg.Dpos,
 		},
 	}
 
 	for _, test := range tests {
 		db := memdb.NewMemDatabase()
 
-		config, dpos, hash, err := test.fn(db)
+		config, _, hash, err := test.fn(db)
 
 		// Check the return values.
 		if !reflect.DeepEqual(err, test.wantErr) {
 			spew := spew.ConfigState{DisablePointerAddresses: true, DisableCapacities: true}
-			t.Errorf("%s: returned error %#v, want %#v", test.name, spew.NewFormatter(err), spew.NewFormatter(test.wantErr))
-		}
-		if !reflect.DeepEqual(config, test.wantConfig) {
-			t.Errorf("%s:\n returned %v\nwant     %v", test.name, config, test.wantConfig)
+			t.Errorf("%s: 1 returned error %#v, want %#v", test.name, spew.NewFormatter(err), spew.NewFormatter(test.wantErr))
 		}
 
-		if !reflect.DeepEqual(dpos, test.wantDpos) {
-			t.Errorf("%s:\nreturned %v\nwant     %v", test.name, config, test.wantConfig)
+		bts, _ := json.Marshal(config)
+		wbts, _ := json.Marshal(test.wantConfig)
+		if bytes.Compare(bts, wbts) != 0 {
+			t.Errorf("%s:\n 2 returned %v\nwant     %v", test.name, config, test.wantConfig)
 		}
 
 		if hash != test.wantHash {
-			t.Errorf("%s: returned hash %s, want %s", test.name, hash.Hex(), test.wantHash.Hex())
+			t.Errorf("%s: 4 returned hash %s, want %s", test.name, hash.Hex(), test.wantHash.Hex())
 		} else if err == nil {
 			// Check database content.
 			stored := rawdb.ReadBlock(db, test.wantHash, 0)
 			if stored.Hash() != test.wantHash {
-				t.Errorf("%s: block in DB has hash %s, want %s", test.name, stored.Hash(), test.wantHash)
+				t.Errorf("%s: 5 block in DB has hash %s, want %s", test.name, stored.Hash(), test.wantHash)
 			}
 		}
 	}
diff --git a/blockchain/test_utils.go b/blockchain/test_utils.go
index 43a60a7d..7ac2c707 100644
--- a/blockchain/test_utils.go
+++ b/blockchain/test_utils.go
@@ -21,10 +21,14 @@ import (
 	"errors"
 	"fmt"
 	"math/big"
+	"os"
+	"strconv"
 	"testing"
 	"time"
 
+	"github.com/ethereum/go-ethereum/log"
 	"github.com/fractalplatform/fractal/accountmanager"
+	am "github.com/fractalplatform/fractal/accountmanager"
 	"github.com/fractalplatform/fractal/common"
 	"github.com/fractalplatform/fractal/consensus"
 	"github.com/fractalplatform/fractal/consensus/dpos"
@@ -32,6 +36,7 @@ import (
 	"github.com/fractalplatform/fractal/params"
 	"github.com/fractalplatform/fractal/processor"
 	"github.com/fractalplatform/fractal/processor/vm"
+	"github.com/fractalplatform/fractal/rawdb"
 	"github.com/fractalplatform/fractal/state"
 	"github.com/fractalplatform/fractal/txpool"
 	"github.com/fractalplatform/fractal/types"
@@ -40,250 +45,265 @@ import (
 	"github.com/fractalplatform/fractal/utils/rlp"
 )
 
-type tdpos struct {
-	*dpos.Dpos
-}
-
-func (tds *tdpos) VerifySeal(chain consensus.IChainReader, header *types.Header) error {
-	return nil
-}
-
-func (tds *tdpos) Engine() consensus.IEngine {
-	return tds
-}
-
 var (
-	ds                   = dpos.New(dpos.DefaultConfig, nil)
-	tengine              = &tdpos{ds}
-	issurevalue          = "500000000000000000000000"
-	sysnameprikey, _     = crypto.HexToECDSA("289c2857d4598e37fb9647507e47a309d6133539bf21a8b9cb6df88fd5232032")
-	producerScheduleSize = dpos.DefaultConfig.ProducerScheduleSize
-	blockInterval        = dpos.DefaultConfig.BlockInterval
-	blockFrequency       = dpos.DefaultConfig.BlockFrequency
-	epochInterval        = producerScheduleSize * blockFrequency * blockInterval * uint64(time.Millisecond)
+	issurevalue       = "10000000000000000000000000000"
+	syscadidatePrefix = "syscadidate"
+	systemPrikey, _   = crypto.HexToECDSA("289c2857d4598e37fb9647507e47a309d6133539bf21a8b9cb6df88fd5232032")
 )
 
-type producerInfo struct {
+type cadidateInfo struct {
 	name   string
 	prikey *ecdsa.PrivateKey
 }
 
-var producers []*producerInfo
+func getCadidates() map[string]*cadidateInfo {
+	cadidates := make(map[string]*cadidateInfo)
+	pri0, _ := crypto.HexToECDSA("189c2857d4598e37fb9647507e47a309d6133539bf21a8b9cb6df88fd5232032")
+	pri1, _ := crypto.HexToECDSA("9c22ff5f21f0b81b113e63f7db6da94fedef11b2119b4088b89664fb9a3cb658")
+	pri2, _ := crypto.HexToECDSA("8605cf6e76c9fc8ac079d0f841bd5e99bd3ad40fdd56af067993ed14fc5bfca8")
+
+	cadidates["syscadidate0"] = &cadidateInfo{"syscadidate0", pri0}
+	cadidates["syscadidate1"] = &cadidateInfo{"syscadidate1", pri1}
+	cadidates["syscadidate2"] = &cadidateInfo{"syscadidate2", pri2}
+	return cadidates
+}
 
-func init() {
-	producers = make([]*producerInfo, 3)
-	pri1, _ := crypto.HexToECDSA("189c2857d4598e37fb9647507e47a309d6133539bf21a8b9cb6df88fd5232032")
-	pri2, _ := crypto.HexToECDSA("9c22ff5f21f0b81b113e63f7db6da94fedef11b2119b4088b89664fb9a3cb658")
-	pri3, _ := crypto.HexToECDSA("8605cf6e76c9fc8ac079d0f841bd5e99bd3ad40fdd56af067993ed14fc5bfca8")
-	producers[0] = &producerInfo{"sysproducer1", pri1}
-	producers[1] = &producerInfo{"sysproducer2", pri2}
-	producers[2] = &producerInfo{"sysproducer3", pri3}
+func getDefaultGenesisAccounts() (gas []*GenesisAccount) {
+	for i := 0; i < len(getCadidates()); i++ {
+		cadidate := getCadidates()[syscadidatePrefix+strconv.Itoa(i)]
+		gas = append(gas, &GenesisAccount{
+			Name:   cadidate.name,
+			PubKey: common.BytesToPubKey(crypto.FromECDSAPub(&cadidate.prikey.PublicKey)),
+		})
+	}
+	return
+}
 
+func calculateEpochInterval(dposCfg *dpos.Config) uint64 {
+	return dposCfg.CadidateScheduleSize * dposCfg.BlockFrequency * dposCfg.BlockInterval * uint64(time.Millisecond)
 }
 
-func makeProduceAndTime(st uint64, rounds int) ([]string, []uint64) {
-	baseproducers := []string{"sysproducer1", "sysproducer2", "sysproducer3"}
-	firsttime := blockInterval*1000*uint64(time.Microsecond) + st
-	offset := firsttime % epochInterval
-	offset = offset / (blockInterval * uint64(time.Millisecond))
-	var pros []string
-	for i := 0; i < rounds; i++ {
-		for j := 0; j < len(baseproducers); j++ {
-			for k := 0; k < int(blockFrequency); k++ {
-				pros = append(pros, baseproducers[j])
+func makeSystemCadidatesAndTime(parentTime uint64, genesis *Genesis) ([]string, []uint64) {
+	var (
+		cadidates     []string
+		baseCadidates = getCadidates()
+	)
+
+	for i := 0; i < int(genesis.Config.DposCfg.DelayEcho)+1; i++ {
+		for j := 0; j < len(baseCadidates); j++ {
+			for k := 0; k < int(genesis.Config.DposCfg.BlockFrequency); k++ {
+				cadidates = append(cadidates, genesis.Config.SysName)
 			}
 		}
-
 	}
-	pros = pros[offset:]
-	ht := make([]uint64, len(pros))
-	for i := 0; i < len(pros); i++ {
-		ht[i] = blockInterval*1000*uint64(time.Microsecond)*uint64(i+1) + st
+	cadidates = cadidates[1:]
+	headerTimes := make([]uint64, len(cadidates))
+	for i := 0; i < len(cadidates); i++ {
+		headerTimes[i] = genesis.Config.DposCfg.BlockInterval*1000*uint64(time.Microsecond)*uint64(i+1) + parentTime
 	}
-	return pros, ht
+	return cadidates, headerTimes
 }
 
-func newCanonical(t *testing.T, engine consensus.IEngine) (*Genesis, fdb.Database, *BlockChain, uint64, error) {
-
+func makeCadidatesAndTime(parentTime uint64, genesis *Genesis, rounds uint64) ([]string, []uint64) {
 	var (
-		db         = memdb.NewMemDatabase()
-		gspec      = DefaultGenesis()
-		genesis, _ = gspec.Commit(db)
+		cadidates     []string
+		baseCadidates = getCadidates()
 	)
+	for i := 0; uint64(i) < rounds; i++ {
+		for j := 0; j < len(baseCadidates); j++ {
+			for k := 0; k < int(genesis.Config.DposCfg.BlockFrequency); k++ {
+				cadidates = append(cadidates, baseCadidates[syscadidatePrefix+strconv.Itoa(j)].name)
+			}
+		}
+	}
+	headerTimes := make([]uint64, len(cadidates))
+	for i := 0; i < len(cadidates); i++ {
+		headerTimes[i] = genesis.Config.DposCfg.BlockInterval*1000*uint64(time.Microsecond)*uint64(i+1) + parentTime
+	}
+	return cadidates, headerTimes
+}
 
+func newCanonical(t *testing.T, genesis *Genesis) *BlockChain {
 	// Initialize a fresh chain with only a genesis block
-	blockchain, _ := NewBlockChain(db, vm.Config{}, params.DefaultChainconfig, txpool.SenderCacher)
+	chainDb := memdb.NewMemDatabase()
+	chainCfg, dposCfg, _, err := SetupGenesisBlock(chainDb, genesis)
+	if err != nil {
+		t.Fatal(err)
+	}
 
-	type bc struct {
-		*BlockChain
-		consensus.IEngine
+	blockchain, err := NewBlockChain(chainDb, vm.Config{}, chainCfg, txpool.SenderCacher)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	statedb, err := blockchain.State()
+	if err != nil {
+		t.Fatalf("state db err %v", err)
+	}
+	accountManager, err := am.NewAccountManager(statedb)
+	if err != nil {
+		t.Fatalf("genesis accountManager new err: %v", err)
+	}
+	if ok, err := accountManager.AccountIsExist(common.StrToName(chainCfg.SysName)); !ok {
+		t.Fatalf("system account is not exist %v", err)
 	}
 
-	// Create validator and txProcessor
-	cfg := blockchain.Config()
-	cfg.SysTokenID = 1
-	validator := processor.NewBlockValidator(&bc{blockchain, engine}, engine)
-	txProcessor := processor.NewStateProcessor(&bc{blockchain, engine}, engine)
+	assetInfo, err := accountManager.GetAssetInfoByName(chainCfg.SysToken)
+	if err != nil {
+		t.Fatalf("genesis system asset err %v", err)
+	}
+
+	chainCfg.SysTokenID = assetInfo.AssetId
+	chainCfg.SysTokenDecimals = assetInfo.Decimals
+
+	engine := dpos.New(dposCfg, blockchain)
+	bc := struct {
+		*BlockChain
+		consensus.IEngine
+	}{blockchain, engine}
 
+	validator := processor.NewBlockValidator(&bc, engine)
+	txProcessor := processor.NewStateProcessor(&bc, engine)
 	blockchain.SetValidator(validator)
 	blockchain.SetProcessor(txProcessor)
 
-	tmpdb, err := deepCopyDB(db)
-	if err != nil {
-		return nil, nil, nil, uint64(0), fmt.Errorf("failed to deep copy db: %v", err)
-	}
-	starttime := uint64(0)
-	blocks, _ := generateChain(gspec.Config, genesis, tengine, blockchain, tmpdb, 1, func(i int, block *BlockGenerator) {
-		genesisname := genesis.Coinbase()
-		block.SetCoinbase(genesisname)
-		tengine.SetSignFn(func(content []byte, state *state.StateDB) ([]byte, error) {
-			return crypto.Sign(content, sysnameprikey)
-		})
-		st := blockInterval*uint64(time.Millisecond) + block.parent.Head.Time.Uint64()
-		starttime = st
-		block.OffsetTime(int64(tengine.Slot(st)))
-		state, err := state.New(genesis.Root(), state.NewDatabase(tmpdb))
-		if err != nil {
-			t.Error("new state failed")
-		}
-		txs := makeProducersTx(t, params.DefaultChainconfig.SysName.String(), sysnameprikey, producers, state)
-		for _, tx := range txs {
-			block.AddTx(tx)
-		}
-	})
-	_, err = blockchain.InsertChain(blocks)
+	return blockchain
+}
+
+func makeNewChain(t *testing.T, genesis *Genesis, chain *BlockChain, cadidates []string, headerTimes []uint64) (*BlockChain, []*types.Block) {
+
+	tmpdb, err := deepCopyDB(chain.db)
 	if err != nil {
-		t.Error("insert chain err", err)
+		t.Fatal(err)
 	}
-	cnt := int(blockFrequency*producerScheduleSize*3) - 2
-	for index := 0; index < cnt; index++ {
-		blocks1, _ := generateChain(gspec.Config, blockchain.CurrentBlock(), tengine, blockchain, tmpdb, 1, func(i int, block *BlockGenerator) {
-			genesisname := genesis.Coinbase()
-			block.SetCoinbase(genesisname)
-			tengine.SetSignFn(func(content []byte, state *state.StateDB) ([]byte, error) {
-				return crypto.Sign(content, sysnameprikey)
+
+	engine := dpos.New(dposConfig(genesis.Config), chain)
+
+	newblocks, _ := generateChain(genesis.Config, chain.CurrentBlock(), engine, chain, tmpdb,
+		len(headerTimes), func(i int, b *BlockGenerator) {
+
+			baseCadidates := getCadidates()
+
+			baseCadidates[genesis.Config.SysName] = &cadidateInfo{genesis.Config.SysName, systemPrikey}
+
+			minerInfo := baseCadidates[cadidates[i]]
+
+			b.SetCoinbase(common.StrToName(minerInfo.name))
+			engine.SetSignFn(func(content []byte, state *state.StateDB) ([]byte, error) {
+				return crypto.Sign(content, minerInfo.prikey)
 			})
-			st := blockInterval*uint64(time.Millisecond) + starttime
-			starttime = st
-			block.OffsetTime(int64(tengine.Slot(st)))
+			b.OffsetTime(int64(engine.Slot(headerTimes[i])))
+
+			if i == 0 {
+				txs := makeCadidatesTx(t, genesis.Config.SysName, systemPrikey, b.statedb)
+				for _, tx := range txs {
+					b.AddTx(tx)
+				}
+			}
+
 		})
-		_, err = blockchain.InsertChain(blocks1)
-		if err != nil {
-			t.Error("insert chain err", err)
-		}
+
+	_, err = chain.InsertChain(newblocks)
+	if err != nil {
+		t.Fatal("insert chain err", err)
 	}
-	return gspec, db, blockchain, starttime, err
+
+	return chain, newblocks
 }
 
-func makeNewChain(t *testing.T, gspec *Genesis, chain *BlockChain, db *fdb.Database, h int, headertime []uint64, miners []string, f MakeTransferTx) (*fdb.Database, *BlockChain, []*types.Block, error) {
-	var newgenerateblocks []*types.Block
-	tmpdb, err := deepCopyDB(*db)
+func generateForkBlocks(t *testing.T, genesis *Genesis, cadidates []string, headerTimes []uint64) []*types.Block {
+	genesis.AllocAccounts = append(genesis.AllocAccounts, getDefaultGenesisAccounts()...)
+	chain := newCanonical(t, genesis)
+
+	tmpdb, err := deepCopyDB(chain.db)
 	if err != nil {
-		t.Error("copy db err", err)
-		return nil, nil, nil, err
+		t.Fatal(err)
 	}
-	for j := 0; j < h; j++ {
-		newblocks, _ := generateChain(gspec.Config, chain.CurrentBlock(), tengine, chain, tmpdb, 1, func(i int, b *BlockGenerator) {
-			var minerInfo *producerInfo
-			for k := 0; k < len(producers); k++ {
-				if producers[k].name == miners[j] {
-					minerInfo = producers[k]
-				}
-			}
+
+	engine := dpos.New(dposConfig(genesis.Config), chain)
+
+	newblocks, _ := generateChain(genesis.Config, chain.CurrentBlock(), engine, chain, tmpdb,
+		len(headerTimes), func(i int, b *BlockGenerator) {
+			baseCadidates := getCadidates()
+
+			baseCadidates[genesis.Config.SysName] = &cadidateInfo{genesis.Config.SysName, systemPrikey}
+			minerInfo := baseCadidates[cadidates[i]]
+
 			b.SetCoinbase(common.StrToName(minerInfo.name))
-			tengine.SetSignFn(func(content []byte, state *state.StateDB) ([]byte, error) {
+			engine.SetSignFn(func(content []byte, state *state.StateDB) ([]byte, error) {
 				return crypto.Sign(content, minerInfo.prikey)
 			})
-			b.OffsetTime(int64(tengine.Slot(headertime[j])))
-			state, err := state.New(b.parent.Root(), state.NewDatabase(tmpdb))
-			if err != nil {
-				t.Error("new state failed", err)
-			}
-			if f != nil {
-				tx := f(t, params.DefaultChainconfig.SysName.String(), minerInfo.name, sysnameprikey, state)
-				b.AddTx(tx)
+
+			b.OffsetTime(int64(engine.Slot(headerTimes[i])))
+
+			if i == 0 {
+				txs := makeCadidatesTx(t, genesis.Config.SysName, systemPrikey, b.statedb)
+				for _, tx := range txs {
+					b.AddTx(tx)
+				}
 			}
 		})
-		_, err := chain.InsertChain(newblocks)
-		if err != nil {
-			t.Error("insert chain err", err)
-		}
-		newgenerateblocks = append(newgenerateblocks, newblocks...)
-	}
 
-	return db, chain, newgenerateblocks, err
+	return newblocks
 }
-func makeProducersTx(t *testing.T, from string, fromprikey *ecdsa.PrivateKey, newaccount []*producerInfo, state *state.StateDB) []*types.Transaction {
+
+func makeCadidatesTx(t *testing.T, from string, fromprikey *ecdsa.PrivateKey, state *state.StateDB) []*types.Transaction {
 	var txs []*types.Transaction
 	signer := types.NewSigner(params.DefaultChainconfig.ChainID)
 	am, err := accountmanager.NewAccountManager(state)
 	if err != nil {
-		t.Error("new accountmanager failed")
+		t.Fatal("new accountmanager failed")
 	}
 	nonce, err := am.GetNonce(common.StrToName(from))
 	if err != nil {
-		t.Errorf("get name %s nonce failed", from)
+		t.Fatalf("get name %s nonce failed", from)
 	}
+
 	delegateValue := new(big.Int)
-	delegateValue.SetString(issurevalue, 0)
+	delegateValue.SetString(issurevalue, 10)
+
 	var actions []*types.Action
-	for _, to := range newaccount {
+	for i := 0; i < len(getCadidates()); i++ {
 		amount := new(big.Int).Mul(delegateValue, big.NewInt(2))
-		pub := common.BytesToPubKey(crypto.FromECDSAPub(&to.prikey.PublicKey))
-		action := types.NewAction(types.CreateAccount, common.StrToName(from), common.StrToName(to.name), nonce, uint64(1), uint64(210000), amount, pub[:])
+		action := types.NewAction(types.Transfer, common.StrToName(from), common.StrToName(getCadidates()[syscadidatePrefix+strconv.Itoa(i)].name), nonce, uint64(1), uint64(210000), amount, nil)
 		actions = append(actions, action)
 		nonce++
 	}
 	tx := types.NewTransaction(uint64(1), big.NewInt(2), actions...)
+	keyPair := types.MakeKeyPair(fromprikey, []uint64{0})
 	for _, action := range actions {
-		err := types.SignAction(action, tx, signer, fromprikey)
+		err := types.SignActionWithMultiKey(action, tx, signer, []*types.KeyPair{keyPair})
 		if err != nil {
-			t.Errorf(fmt.Sprintf("SignAction err %v", err))
+			t.Fatalf(fmt.Sprintf("SignAction err %v", err))
 		}
 	}
+
 	txs = append(txs, tx)
+
 	var actions1 []*types.Action
-	for _, to := range newaccount {
-		value := big.NewInt(1e5)
+	for i := 0; i < len(getCadidates()); i++ {
+		to := getCadidates()[syscadidatePrefix+strconv.Itoa(i)]
 		url := "www." + to.name + ".io"
-		arg := &dpos.RegisterProducer{
-			Url:   url,
-			Stake: delegateValue,
+		arg := &dpos.RegisterCadidate{
+			Url: url,
 		}
 		payload, _ := rlp.EncodeToBytes(arg)
-		action := types.NewAction(types.RegProducer, common.StrToName(to.name), common.StrToName(to.name), 0, uint64(1), uint64(210000), value, payload)
+		action := types.NewAction(types.RegCadidate, common.StrToName(to.name), common.StrToName(params.DefaultChainconfig.DposName), 0, uint64(1), uint64(210000), delegateValue, payload)
 		actions1 = append(actions1, action)
 	}
+
 	tx1 := types.NewTransaction(uint64(1), big.NewInt(2), actions1...)
-	for i, action := range actions1 {
-		err := types.SignAction(action, tx1, signer, newaccount[i].prikey)
+	for _, action := range actions1 {
+		keyPair = types.MakeKeyPair(getCadidates()[action.Sender().String()].prikey, []uint64{0})
+		err := types.SignActionWithMultiKey(action, tx1, signer, []*types.KeyPair{keyPair})
 		if err != nil {
-			t.Errorf(fmt.Sprintf("SignAction err %v", err))
+			t.Fatalf(fmt.Sprintf("SignAction err %v", err))
 		}
 	}
-	txs = append(txs, tx1)
-	return txs
-}
 
-type MakeTransferTx func(t *testing.T, from, to string, fromprikey *ecdsa.PrivateKey, state *state.StateDB) *types.Transaction
+	txs = append(txs, tx1)
 
-func makeTransferTx(t *testing.T, from, to string, fromprikey *ecdsa.PrivateKey, state *state.StateDB) *types.Transaction {
-	signer := types.NewSigner(params.DefaultChainconfig.ChainID)
-	am, err := accountmanager.NewAccountManager(state)
-	if err != nil {
-		t.Error("new accountmanager failed")
-	}
-	nonce, err := am.GetNonce(common.StrToName(from))
-	if err != nil {
-		t.Errorf("get name %s nonce failed", from)
-	}
-	action := types.NewAction(types.Transfer, common.StrToName(from), common.StrToName(to), nonce, uint64(1), uint64(210000), big.NewInt(1), nil)
-	tx := types.NewTransaction(uint64(1), big.NewInt(2), action)
-	err = types.SignAction(action, tx, signer, fromprikey)
-	if err != nil {
-		t.Errorf(fmt.Sprintf("SignAction err %v", err))
-	}
-	return tx
+	return txs
 }
 
 func deepCopyDB(db fdb.Database) (fdb.Database, error) {
@@ -298,10 +318,13 @@ func generateChain(config *params.ChainConfig, parent *types.Block, engine conse
 	if config == nil {
 		config = params.DefaultChainconfig
 	}
+
+	chain.db = db
+
 	blocks, receipts := make(types.Blocks, n), make([][]*types.Receipt, n)
 	genblock := func(i int, parent *types.Block, statedb *state.StateDB) (*types.Block, []*types.Receipt) {
-		b := &BlockGenerator{i: i, parent: parent, statedb: statedb, config: config, engine: engine, bc: chain}
-		b.header = makeHeader(b.bc, parent, statedb, b.engine)
+		b := &BlockGenerator{i: i, parent: parent, statedb: statedb, config: config, engine: engine, BlockChain: chain}
+		b.header = makeHeader(b, parent, statedb, b.engine)
 
 		// Execute any user modifications to the block
 		if gen != nil {
@@ -310,33 +333,47 @@ func generateChain(config *params.ChainConfig, parent *types.Block, engine conse
 
 		if b.engine != nil {
 			// Finalize and seal the block
-			b.engine.Prepare(b.bc, b.header, b.txs, nil, nil)
-			block, _ := b.engine.Finalize(b.bc, b.header, b.txs, b.receipts, statedb)
-			block, err := b.engine.Seal(b.bc, block, nil)
+			if err := b.engine.Prepare(b, b.header, b.txs, nil, nil); err != nil {
+				panic(fmt.Sprintf("engine prepare error: %v", err))
+			}
+
+			block, err := b.engine.Finalize(b, b.header, b.txs, b.receipts, b.statedb)
+			if err != nil {
+				panic(fmt.Sprintf("engine finalize error: %v", err))
+			}
+
+			block, err = b.engine.Seal(b, block, nil)
+			if err != nil {
+				panic(fmt.Sprintf("engine seal error: %v", err))
+			}
 
 			block.Head.ReceiptsRoot = types.DeriveReceiptsMerkleRoot(b.receipts)
 			block.Head.TxsRoot = types.DeriveTxsMerkleRoot(b.txs)
 			block.Head.Bloom = types.CreateBloom(b.receipts)
-
 			batch := db.NewBatch()
 
-			root, err := statedb.Commit(batch, block.Hash(), block.NumberU64())
+			root, err := b.statedb.Commit(batch, block.Hash(), block.NumberU64())
 			if err != nil {
 				panic(fmt.Sprintf("state Commit error: %v", err))
 			}
-			triedb := statedb.Database().TrieDB()
-			triedb.Commit(root, false)
-			if batch.Write() != nil {
-				panic(fmt.Sprintf("batch Write error: %v", err))
 
+			if err := b.statedb.Database().TrieDB().Commit(root, false); err != nil {
+				panic(fmt.Sprintf("trie write error: %v", err))
 			}
+
+			if err := batch.Write(); err != nil {
+				panic(fmt.Sprintf("batch Write error: %v", err))
+			}
+
+			rawdb.WriteHeader(db, block.Head)
+
 			return block, b.receipts
 		}
 		return nil, nil
 	}
 
 	for i := 0; i < n; i++ {
-		statedb, err := state.New(parent.Root(), state.NewDatabase(db))
+		statedb, err := chain.StateAt(parent.Root())
 		if err != nil {
 			panic(err)
 		}
@@ -345,6 +382,7 @@ func generateChain(config *params.ChainConfig, parent *types.Block, engine conse
 		receipts[i] = receipt
 		parent = block
 	}
+
 	return blocks, receipts
 }
 
@@ -358,3 +396,35 @@ func makeHeader(chain consensus.IChainReader, parent *types.Block, state *state.
 		Time:       big.NewInt(0),
 	}
 }
+
+func printLog(level log.Lvl) {
+	glogger := log.NewGlogHandler(log.StreamHandler(os.Stdout, log.TerminalFormat(false)))
+	glogger.Verbosity(level)
+	log.Root().SetHandler(log.Handler(glogger))
+}
+
+func checkBlocksInsert(t *testing.T, chain *BlockChain, blocks []*types.Block) {
+	block := chain.CurrentBlock()
+	index := 0
+	for block.NumberU64() != 0 {
+		index++
+		if blocks[len(blocks)-index].Hash() != block.Hash() {
+			t.Fatalf("Write/Get HeadBlockHash failed")
+		}
+		block = chain.GetBlockByNumber(block.NumberU64() - 1)
+	}
+
+}
+
+func checkCompleteChain(t *testing.T, chain *BlockChain) {
+	block := chain.CurrentBlock()
+	for block.NumberU64() != 0 {
+		parentBlock := chain.GetBlockByNumber(block.NumberU64() - 1)
+		if block.ParentHash() != parentBlock.Hash() {
+			t.Fatalf("is not complete chain block num: %v,hash:%v, parent hash: %v \n parent block num: %v, hash: %v,",
+				block.NumberU64(), block.Hash().Hex(), block.ParentHash().Hex(),
+				parentBlock.NumberU64(), parentBlock.Hash().Hex())
+		}
+		block = parentBlock
+	}
+}
diff --git a/build/eg_config.yaml b/build/eg_config.yaml
new file mode 100644
index 00000000..81dc611e
--- /dev/null
+++ b/build/eg_config.yaml
@@ -0,0 +1,127 @@
+# Genesis json file
+genesis: "./build/genesis.json"
+
+# log configuration table
+log:
+  # Prepends log messages with call-site location (file and line number)
+  printorigins: false
+  # Logging verbosity: 0=silent, 1=error, 2=warn, 3=info, 4=debug, 5=detail
+  level: 4
+  # Per-module verbosity: comma-separated list of <pattern>=<level> (e.g. ft/*=5,p2p=4)
+  vmodule: ""
+  # Request a stack trace at a specific logging statement (e.g. \"block.go:271\")
+  backtraceat: ""
+
+# node the fractal node configuration table
+node:
+  # the node datadir
+  datadir: "./build/testdatadir"
+  # Reduce key-derivation RAM & CPU usage at some expense of KDF strength
+  lightkdf: false
+  # RPC:ipc file name
+  ipcpath: "ft.ipc"
+  # RPC:http host address
+  httphost: "localhost"
+  # RPC:http host port
+  httpport: 8888
+  # RPC:http api's offered over the HTTP-RPC interface
+  httpmodules: ["ft"]
+  # RPC:Which to accept cross origin
+  httpcors: ["localhost"]
+  # RPC:http virtual hostnames from which to accept requests
+  httpvirtualhosts: ["*"]
+  # RPC:websocket host address
+  wshost: "localhost"
+  # RPC:websocket host port
+  wsport: 8889
+  # RPC:ws api's offered over the WS-RPC interface
+  wsmodules: ["ft"]
+  # RPC:ws origins from which to accept websockets requests
+  wsorigins: []
+  # RPC:ws exposes all API modules via the WebSocket RPC interface rather than just the public ones.
+  wsexposall: true
+  # Node list file. BootstrapNodes are used to establish connectivity with the rest of the network
+  bootnodes: "./build/bootnodes.txt"
+  # Node list file. Static nodes are used as pre-configured connections which are always maintained and re-connected on disconnects
+  staticnodes: "./build/staticnodes.txt"
+  # Node list file. Trusted nodes are usesd as pre-configured connections which are always allowed to connect, even above the peer limit
+  trustnodes: "./build/trustnodes.txt"
+  # P2P configuration table
+  p2p:
+    # The ID of the p2p network. Nodes have different ID cannot communicate, even if they have same chainID and block data.
+    networkid: 1
+    # The name sets the p2p node name of this server
+    name: “ft_p2p”
+    # Maximum number of network peers
+    maxpeers: 20
+    # Maximum number of pending connection attempts
+    maxpendpeers: 10
+    # DialRatio controls the ratio of inbound to dialed connections
+    dialratio: 10
+    # Disables the peer discovery mechanism (manual peer addition)
+    nodiscover: true
+    # The path to the database containing the previously seen live nodes in the network
+    nodedb: "./build/nodedb"
+    # Network listening address
+    listenaddr: ":8000"
+    # The server will not dial any peers.
+    nodial: false
+
+# ftservice the fractal service configuration table
+ftservice:
+  # Megabytes of memory allocated to internal database caching
+  databasecache: 1024
+  # txpool configuration table
+  txpool:
+    # Disables price exemptions for locally submitted transactions
+    nolocals: false
+    # Disk journal for local transaction to survive node restarts
+    journal: "transactions.rlp"
+    # Time interval to regenerate the local transaction journal
+    rejournal: 1h
+    # Minimum gas price limit to enforce for acceptance into the pool
+    pricelimit: 2
+    # Price bump percentage to replace an already existing transaction
+    pricebump: 20
+    # Number of executable transaction slots guaranteed per account
+    accountslots: 256
+    # Maximum number of executable transaction slots for all accounts
+    globalslots: 1024
+    # Maximum number of non-executable transaction slots permitted per account
+    accountqueue: 1024
+    # Maximum number of non-executable transaction slots for all accounts
+    globalqueue: 2048
+    # Maximum amount of time non-executable transaction are queued
+    lifetime: 1h
+  # gas price oracle
+  gpo:
+    # Number of recent blocks to check for gas prices
+    blocks: 30
+    # Suggested gas price is the given percentile of a set of recent transaction gas prices
+    percentile: 50
+  miner:
+    # Start miner generate block and process transaction
+    start: false
+    # Name for block mining rewards
+    name: "testminername"
+    # Hex of private key for block mining rewards
+    private: []
+    # Block extra data set by the miner
+    extra: "system"
+  metrics:
+    # flag that open statistical metrics
+    metrics: false
+    # flag that open influxdb thad store statistical metrics
+    influxdb: false
+    # URL that connect influxdb
+    influxdburl: "http://localhost:8086"
+    # Influxdb database name
+    influxdbname: "metrics"
+    # Indluxdb user name
+    influxdbuser: "test"
+    # Influxdb user passwd
+    influxdbpasswd: "test"
+    # Influxdb namespace
+    influxdbnamespace: "fractal/"
+  # flag for db to store contrat internal transaction log
+  contractlog: false
\ No newline at end of file
diff --git a/build/genesis.json b/build/genesis.json
index b174d273..80336809 100644
--- a/build/genesis.json
+++ b/build/genesis.json
@@ -1,48 +1,66 @@
-{
-	"config": {
-		"chainId": 1,
-		"bootnodes": [],
-		"sysName": "ftsystemio",
-		"sysToken": "ftoken",
-		"assetChargeRatio": 80,
-		"contractChargeRatio": 80
-	},
-	"dpos": {
-		"MaxURLLen": 512,
-		"UnitStake": 1000,
-		"ProducerMinQuantity": 10,
-		"VoterMinQuantity": 1,
-		"ActivatedMinQuantity": 1000,
-		"BlockInterval": 3000,
-		"BlockFrequency": 6,
-		"ProducerScheduleSize": 3,
-		"DelayEcho": 2,
-		"AccountName": "ftsystemdpos",
-		"SystemName": "ftsystemio",
-		"SystemURL": "www.fractalproject.com",
-		"ExtraBlockReward": 1,
-		"BlockReward": 5,
-		"Decimals": 18
-	},
-	"timestamp": "0x0",
-	"gasLimit": "0x5f5e100",
-	"difficulty": "0x20000",
-	"coinbase": "ftsystemio",
-	"allocAccounts": [
-		{
-			"name": "ftsystemio",
-			"pubKey": "0x047db227d7094ce215c3a0f57e1bcc732551fe351f94249471934567e0f5dc1bf795962b8cccb87a2eb56b29fbe37d614e2f4c3c45b789ae4f1f51f4cb21972ffd"
-		}
-	],
-	"allocAssets": [
-		{
-			"assetname": "ftoken",
-			"symbol": "ft",
-			"amount": 10000000000000000000000000000,
-			"decimals": 18,
-			"owner": "ftsystemio",
-			"founder": "ftsystemio",
-			"UpperLimit":10000000000000000000000000000
-		}
-	]
+{
+	"config": {
+		"bootnodes": [],
+		"chainId": 1,
+		"chainName": "fractal",
+		"chainUrl": "https://fractalproject.com",
+		"accountParams": {
+			"level": 1,
+			"length": 16,
+			"subLength": 8
+		},
+		"assetParams": {
+			"level": 1,
+			"length": 16,
+			"subLength": 8
+		},
+		"chargeParams": {
+			"assetRatio": 80,
+			"contractRatio": 80
+		},
+		"upgradeParams": {
+			"blockCnt": 10000,
+			"upgradeRatio": 80
+		},
+		"dposParams": {
+			"maxURLLen": 512,
+			"unitStake": 1000,
+			"cadidateMinQuantity": 10,
+			"voterMinQuantity": 1,
+			"activatedMinQuantity": 100,
+			"blockInterval": 3000,
+			"blockFrequency": 6,
+			"cadidateScheduleSize": 3,
+			"delayEcho": 2,
+			"extraBlockReward": 1,
+			"blockReward": 5
+		},
+		"systemName": "fractal.admin",
+		"accountName": "fractal.account",
+		"dposName": "fractal.dpos",
+		"systemToken": "ftoken"
+	},
+	"timestamp": 1547596800000000000,
+	"gasLimit": 100000000,
+	"difficulty": 131072,
+	"allocAccounts": [{
+		"name": "fractal.admin",
+		"pubKey": "0x047db227d7094ce215c3a0f57e1bcc732551fe351f94249471934567e0f5dc1bf795962b8cccb87a2eb56b29fbe37d614e2f4c3c45b789ae4f1f51f4cb21972ffd"
+	}, {
+		"name": "fractal.account",
+		"pubKey": "0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
+	}, {
+		"name": "fractal.dpos",
+		"pubKey": "0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
+	}],
+	"allocCadidates": [],
+	"allocAssets": [{
+		"name": "ftoken",
+		"symbol": "ft",
+		"amount": 100000000000000000000000000000,
+		"decimals": 18,
+		"founder": "fractal.admin",
+		"owner": "fractal.admin",
+		"upperLimit": 100000000000000000000000000000
+	}]
 }
\ No newline at end of file
diff --git a/build/testnet.json b/build/testnet.json
index 0c153c89..970cdd91 100644
--- a/build/testnet.json
+++ b/build/testnet.json
@@ -1,48 +1,66 @@
-{
-	"config": {
-		"chainId": 45,
-		"bootnodes": ["enode://938597139178830dac79a3c1bcc7be70d41a79a1a1f479cde73862a3d2b808e83f60c6b7d9bd4ff999403828d2b4b5a27ff7323b3467ba3f45db6150db943c32@120.131.7.228:2018","enode://e30016f87e9f32895039c5b4fbbb40fbbf04fc2ef93299124a115df8344d81fff070591b2e455f043d2ccc9ffab3b881ce89c426ae111a5400034bb0fe64e1fa@120.131.7.101:2018"],
-		"sysName": "ftsystemio",
-		"sysToken": "ftoken",
-		"assetChargeRatio": 80,
-		"contractChargeRatio": 80
-	},
-	"dpos": {
-		"MaxURLLen": 512,
-		"UnitStake": 1000,
-		"ProducerMinQuantity": 10,
-		"VoterMinQuantity": 1,
-		"ActivatedMinQuantity": 1000,
-		"BlockInterval": 3000,
-		"BlockFrequency": 6,
-		"ProducerScheduleSize": 15,
-		"DelayEcho": 2,
-		"AccountName": "ftsystemdpos",
-		"SystemName": "ftsystemio",
-		"SystemURL": "www.fractalproject.com",
-		"ExtraBlockReward": 1,
-		"BlockReward": 5,
-		"Decimals": 18
-	},
-	"timestamp": "0x0",
-	"gasLimit": "0x5f5e100",
-	"difficulty": "0x20000",
-	"coinbase": "ftsystemio",
-	"allocAccounts": [
-		{
-			"name": "ftsystemio",
-			"pubKey": "0x04474da0e3024d2089888dd60b7cdd79784725c4074f207b09dd7caa63a5b6ceb226b7141f4720c921003b54be581c84a05072c2d4752a1f5fae698684753424c5"
-		}
-	],
-	"allocAssets": [
-		{
-			"assetname": "ftoken",
-			"symbol": "ft",
-			"amount": 10000000000000000000000000000,
-			"decimals": 18,
-			"owner": "ftsystemio",
-			"founder": "ftsystemio",
-			"UpperLimit":10000000000000000000000000000
-		}
-	]
+{
+	"config": {
+		"bootnodes": ["enode://938597139178830dac79a3c1bcc7be70d41a79a1a1f479cde73862a3d2b808e83f60c6b7d9bd4ff999403828d2b4b5a27ff7323b3467ba3f45db6150db943c32@120.131.7.228:2018","enode://e30016f87e9f32895039c5b4fbbb40fbbf04fc2ef93299124a115df8344d81fff070591b2e455f043d2ccc9ffab3b881ce89c426ae111a5400034bb0fe64e1fa@120.131.7.101:2018"],
+		"chainId": 1,
+		"chainName": "fractal",
+		"chainUrl": "https://fractalproject.com",
+		"accountParams": {
+			"level": 1,
+			"length": 16,
+			"subLength": 8
+		},
+		"assetParams": {
+			"level": 1,
+			"length": 16,
+			"subLength": 8
+		},
+		"chargeParams": {
+			"assetRatio": 80,
+			"contractRatio": 80
+		},
+		"upgradeParams": {
+			"blockCnt": 10000,
+			"upgradeRatio": 80
+		},
+		"dposParams": {
+			"maxURLLen": 512,
+			"unitStake": 1000,
+			"cadidateMinQuantity": 10,
+			"voterMinQuantity": 1,
+			"activatedMinQuantity": 100,
+			"blockInterval": 3000,
+			"blockFrequency": 6,
+			"cadidateScheduleSize": 3,
+			"delayEcho": 2,
+			"extraBlockReward": 1,
+			"blockReward": 5
+		},
+		"systemName": "fractal.admin",
+		"accountName": "fractal.account",
+		"dposName": "fractal.dpos",
+		"systemToken": "ftoken"
+	},
+	"timestamp": 1547596800000000000,
+	"gasLimit": 100000000,
+	"difficulty": 131072,
+	"allocAccounts": [{
+		"name": "fractal.admin",
+		"pubKey": "0x047db227d7094ce215c3a0f57e1bcc732551fe351f94249471934567e0f5dc1bf795962b8cccb87a2eb56b29fbe37d614e2f4c3c45b789ae4f1f51f4cb21972ffd"
+	}, {
+		"name": "fractal.account",
+		"pubKey": "0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
+	}, {
+		"name": "fractal.dpos",
+		"pubKey": "0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
+	}],
+	"allocCadidates": [],
+	"allocAssets": [{
+		"name": "ftoken",
+		"symbol": "ft",
+		"amount": 100000000000000000000000000000,
+		"decimals": 18,
+		"founder": "fractal.admin",
+		"owner": "fractal.admin",
+		"upperLimit": 100000000000000000000000000000
+	}]
 }
\ No newline at end of file
diff --git a/cmd/ft/accountcmd.go b/cmd/ft/accountcmd.go
deleted file mode 100644
index 0e28f72e..00000000
--- a/cmd/ft/accountcmd.go
+++ /dev/null
@@ -1,303 +0,0 @@
-// Copyright 2018 The Fractal Team Authors
-// This file is part of the fractal project.
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-package main
-
-import (
-	"fmt"
-	"io/ioutil"
-	"os"
-	"path/filepath"
-
-	"github.com/spf13/cobra"
-
-	"github.com/fractalplatform/fractal/common"
-	"github.com/fractalplatform/fractal/crypto"
-	"github.com/fractalplatform/fractal/utils/console"
-	"github.com/fractalplatform/fractal/wallet"
-	"github.com/fractalplatform/fractal/wallet/cache"
-	"github.com/fractalplatform/fractal/wallet/keystore"
-)
-
-var walletCmd = &cobra.Command{
-	Use:   "wallet",
-	Short: "Manage Fractal presale wallets",
-	Long: `
-    fractal wallet import /path/to/my/presale.wallet
-
-will prompt for your password and imports your presale account.`,
-	Run: func(cmd *cobra.Command, args []string) {
-	},
-}
-
-var importWalletCmd = &cobra.Command{
-	Use:   "import",
-	Short: "Import Fractal presale wallet",
-	Long: `
-	fractal wallet [options] /path/to/my/presale.wallet
-
-will prompt for your password and imports your presale account.`,
-	Args: cobra.ExactArgs(1),
-	Run: func(cmd *cobra.Command, args []string) {
-		keyfile := args[0]
-		keyJSON, err := ioutil.ReadFile(keyfile)
-		if err != nil {
-			fmt.Println("Could not read wallet file: ", err)
-			return
-		}
-
-		passphrase := getPassPhrase("", false)
-		w, err := getWallet()
-		if err != nil {
-			fmt.Println("get wallet error ", err)
-			return
-		}
-		acct, err := w.Import(keyJSON, passphrase, passphrase)
-		if err != nil {
-			fmt.Println("import wallet error ", err)
-		}
-		fmt.Printf("Address: {%x}\n", acct.Addr)
-	},
-}
-
-var accountCmd = &cobra.Command{
-	Use:   "account",
-	Short: "Manage accounts",
-	Long: `
-
-	Manage accounts, list all existing accounts, import a private key into a new
-	account, create a new account or update an existing account.
-	
-	It supports interactive mode, when you are prompted for password.
-	
-	Make sure you remember the password you gave when creating a new account (with
-	either new or import). Without it you are not able to unlock your account.
-	
-	Note that exporting your key in unencrypted format is NOT supported.
-	
-	Keys are stored under <DATADIR>/keystore.
-	It is safe to transfer the entire directory or the individual keys therein
-	between fractal nodes by simply copying.
-	
-	Make sure you backup your keys regularly.`,
-	Run: func(cmd *cobra.Command, args []string) {
-	},
-}
-
-var listAccountCmd = &cobra.Command{
-	Use:   "list",
-	Short: "Print summary of existing accounts",
-	Long:  "Print a short summary of all accounts",
-	Args:  cobra.ExactArgs(0),
-	Run: func(cmd *cobra.Command, args []string) {
-		wallet, err := getWallet()
-		if err != nil {
-			fmt.Println("get wallet error ", err)
-		}
-		for _, account := range wallet.Accounts() {
-			fmt.Printf("Account: {%x} %s\n", account.Addr, account.Path)
-		}
-	},
-}
-
-var newAccountCmd = &cobra.Command{
-	Use:   "new",
-	Short: "Create a new account",
-	Long: `
-    fractal account new
-
-Creates a new account and prints the address.
-
-The account is saved in encrypted format, you are prompted for a passphrase.
-
-You must remember this passphrase to unlock your account in the future.`,
-	Args: cobra.ExactArgs(0),
-	Run: func(cmd *cobra.Command, args []string) {
-		password := getPassPhrase("Your new account is locked with a password. Please give a password. Do not forget this password.", true)
-		wallet, err := getWallet()
-		if err != nil {
-			fmt.Println("get wallet error ", err)
-			return
-		}
-		account, err := wallet.NewAccount(password)
-		if err != nil {
-			fmt.Println("new account error ", err)
-			return
-		}
-
-		fmt.Printf("Address: {%x}\n", account.Addr)
-	},
-}
-
-var updateAccountCmd = &cobra.Command{
-	Use:   "update",
-	Short: "Update an existing account",
-	Long: `
-    fractal account update <address>
-
-Update an existing account.
-
-The account is saved in the newest version in encrypted format, you are prompted
-for a passphrase to unlock the account and another to save the updated file.
-
-This same command can therefore be used to migrate an account of a deprecated
-format to the newest format or change the password for an account.
-`,
-	Args: cobra.MinimumNArgs(1),
-	Run: func(cmd *cobra.Command, args []string) {
-		w, err := getWallet()
-		if err != nil {
-			fmt.Println("get wallet error ", err)
-			return
-		}
-		for _, addr := range args {
-			account := &cache.Account{Addr: common.HexToAddress(addr)}
-			oldPassword := getPassPhrase("Please give old password.", true)
-			newPassword := getPassPhrase("Please give a new password. Do not forget this password.", true)
-			if err := w.Update(*account, oldPassword, newPassword); err != nil {
-				fmt.Println("Could not update the account: ", addr, " ", err)
-			}
-		}
-	},
-}
-
-var importAccountCmd = &cobra.Command{
-	Use:   "import",
-	Short: "Import a private key into a new account",
-	Long: `
-    fractal account import <keyfile>
-
-Imports an unencrypted private key from <keyfile> and creates a new account.
-Prints the address.
-
-The keyfile is assumed to contain an unencrypted private key in hexadecimal format.
-
-The account is saved in encrypted format, you are prompted for a passphrase.
-
-You must remember this passphrase to unlock your account in the future.
-
-Note:
-As you can directly copy your encrypted accounts to another ethereum instance,
-this import mechanism is not needed when you transfer an account between
-nodes.
-`,
-	Args: cobra.ExactArgs(1),
-	Run: func(cmd *cobra.Command, args []string) {
-		keyfile := args[0]
-		key, err := crypto.LoadECDSA(keyfile)
-		if err != nil {
-			fmt.Println("Failed to load the private key: ", err)
-			return
-		}
-		passphrase := getPassPhrase("Your new account is locked with a password. Please give a password. Do not forget this password.", true)
-
-		w, err := getWallet()
-		if err != nil {
-			fmt.Println("get wallet error ", err)
-			return
-		}
-		acct, err := w.ImportECDSA(key, passphrase)
-		if err != nil {
-			fmt.Println("Could not create the account: ", err)
-			return
-		}
-		fmt.Printf("Address: {%x}\n", acct.Addr)
-	},
-}
-
-func init() {
-	walletCmd.PersistentFlags().StringVarP(&ftconfig.NodeCfg.DataDir, "datadir", "d", ftconfig.NodeCfg.DataDir, "Data directory for the databases and keystore")
-	walletCmd.PersistentFlags().StringVar(&ftconfig.NodeCfg.KeyStoreDir, "keystore", ftconfig.NodeCfg.KeyStoreDir, "Directory for the keystore")
-	walletCmd.PersistentFlags().BoolVar(&ftconfig.NodeCfg.UseLightweightKDF, "lightkdf", ftconfig.NodeCfg.UseLightweightKDF, "Reduce key-derivation RAM & CPU usage at some expense of KDF strength")
-
-	accountCmd.PersistentFlags().StringVarP(&ftconfig.NodeCfg.DataDir, "datadir", "d", ftconfig.NodeCfg.DataDir, "Data directory for the databases and keystore")
-	accountCmd.PersistentFlags().StringVar(&ftconfig.NodeCfg.KeyStoreDir, "keystore", ftconfig.NodeCfg.KeyStoreDir, "Directory for the keystore")
-	accountCmd.PersistentFlags().BoolVar(&ftconfig.NodeCfg.UseLightweightKDF, "lightkdf", ftconfig.NodeCfg.UseLightweightKDF, "Reduce key-derivation RAM & CPU usage at some expense of KDF strength")
-
-	walletCmd.AddCommand(importWalletCmd)
-	accountCmd.AddCommand(listAccountCmd, newAccountCmd, updateAccountCmd, importAccountCmd)
-	RootCmd.AddCommand(walletCmd, accountCmd)
-}
-
-// getPassPhrase retrieves the password associated with an account, either fetched
-// from a list of preloaded passphrases, or requested interactively from the user.
-func getPassPhrase(prompt string, confirmation bool) string {
-	// Otherwise prompt the user for the password
-	if prompt != "" {
-		fmt.Println(prompt)
-	}
-	password, err := console.Stdin.PromptPassword("Passphrase: ")
-	if err != nil {
-		fmt.Println("Failed to read passphrase: ", err)
-		os.Exit(1)
-	}
-	if confirmation {
-		confirm, err := console.Stdin.PromptPassword("Repeat passphrase: ")
-		if err != nil {
-			fmt.Println("Failed to read passphrase confirmation: ", err)
-			os.Exit(1)
-		}
-		if password != confirm {
-			fmt.Println("Passphrases do not match")
-			os.Exit(1)
-		}
-	}
-	return password
-}
-
-func getWallet() (*wallet.Wallet, error) {
-	scryptN := keystore.StandardScryptN
-	scryptP := keystore.StandardScryptP
-	if ftconfig.NodeCfg.UseLightweightKDF {
-		scryptN = keystore.LightScryptN
-		scryptP = keystore.LightScryptP
-	}
-
-	var (
-		keydir string
-		err    error
-	)
-	switch {
-	case filepath.IsAbs(ftconfig.NodeCfg.KeyStoreDir):
-		keydir = ftconfig.NodeCfg.KeyStoreDir
-	case ftconfig.NodeCfg.DataDir != "":
-		if ftconfig.NodeCfg.KeyStoreDir == "" {
-			keydir = filepath.Join(ftconfig.NodeCfg.DataDir, "keystore")
-		} else {
-			keydir, err = filepath.Abs(ftconfig.NodeCfg.KeyStoreDir)
-		}
-	case ftconfig.NodeCfg.KeyStoreDir != "":
-		keydir, err = filepath.Abs(ftconfig.NodeCfg.KeyStoreDir)
-	}
-	if err != nil {
-		fmt.Println("get keydir error ", err)
-		return nil, err
-	}
-
-	if keydir == "" {
-		keydir, err = ioutil.TempDir("", "tmpkeystore")
-		if err != nil {
-			fmt.Println("form keydir error ", err)
-			return nil, err
-		}
-	}
-	fmt.Println("keydir ", keydir)
-	if err := os.MkdirAll(keydir, 0700); err != nil {
-		fmt.Println("mkdir keydir error ", err)
-		return nil, err
-	}
-	return wallet.NewWallet(keydir, scryptN, scryptP), nil
-}
diff --git a/cmd/ft/chain.go b/cmd/ft/chain.go
new file mode 100644
index 00000000..69c497a1
--- /dev/null
+++ b/cmd/ft/chain.go
@@ -0,0 +1,358 @@
+// Copyright 2018 The Fractal Team Authors
+// This file is part of the fractal project.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+package main
+
+import (
+	"compress/gzip"
+	"errors"
+	"fmt"
+	"io"
+	"os"
+	"os/signal"
+	"runtime"
+	"strconv"
+	"strings"
+	"sync/atomic"
+	"syscall"
+	"time"
+
+	"github.com/ethereum/go-ethereum/log"
+	"github.com/fractalplatform/fractal/blockchain"
+	"github.com/fractalplatform/fractal/ftservice"
+	"github.com/fractalplatform/fractal/types"
+	ldb "github.com/fractalplatform/fractal/utils/fdb/leveldb"
+	"github.com/fractalplatform/fractal/utils/rlp"
+	"github.com/spf13/cobra"
+	"github.com/syndtr/goleveldb/leveldb/util"
+)
+
+const (
+	importBatchSize = 2500
+)
+
+var (
+	importCommnad = &cobra.Command{
+		Use:   "import -d <datadir> -g <genesis.json> <block file name>",
+		Short: "Import a blockchain file",
+		Long:  "Import a blockchain file",
+		Run: func(cmd *cobra.Command, args []string) {
+			ftCfgInstance.LogCfg.Setup()
+			if err := importChain(args); err != nil {
+				fmt.Println(err)
+			}
+		},
+	}
+	exportCommand = &cobra.Command{
+		Use:   "export -d <datadir> <block file name> <start num> <end num>",
+		Short: "Export blockchain to file",
+		Long:  "Export blockchain to file",
+		Run: func(cmd *cobra.Command, args []string) {
+			ftCfgInstance.LogCfg.Setup()
+			if err := exportChain(args); err != nil {
+				fmt.Println(err)
+			}
+		},
+	}
+)
+
+func init() {
+	RootCmd.AddCommand(importCommnad, exportCommand)
+	importCommnad.Flags().StringVarP(&ftCfgInstance.NodeCfg.DataDir, "datadir", "d", ftCfgInstance.NodeCfg.DataDir, "Data directory for the databases ")
+	importCommnad.Flags().StringVarP(&ftCfgInstance.GenesisFile, "genesis", "g", "", "genesis json file")
+	exportCommand.Flags().StringVarP(&ftCfgInstance.NodeCfg.DataDir, "datadir", "d", ftCfgInstance.NodeCfg.DataDir, "Data directory for the databases ")
+}
+
+func exportChain(args []string) error {
+	if len(args) < 1 {
+		return errors.New("This command requires an argument")
+	}
+
+	start := time.Now()
+
+	stack, err := makeNode()
+	if err != nil {
+		return err
+	}
+
+	ctx := stack.GetNodeConfig()
+	ftsrv, err := ftservice.New(ctx, ftCfgInstance.FtServiceCfg)
+	if err != nil {
+		return err
+	}
+
+	fp := args[0]
+	if len(args) < 3 {
+		err = exportBlockChain(ftsrv.BlockChain(), fp)
+	} else {
+		first, ferr := strconv.ParseInt(args[1], 10, 64)
+		last, lerr := strconv.ParseInt(args[2], 10, 64)
+		if ferr != nil || lerr != nil {
+			return errors.New("Export error in parsing parameters: block number not an integer")
+		}
+		if first < 0 || last < 0 {
+			return errors.New("Export error: block number must be greater than 0")
+		}
+		err = exportAppendBlockChain(ftsrv.BlockChain(), fp, uint64(first), uint64(last))
+	}
+	log.Info("Export done in ", "time", time.Since(start))
+	if err != nil {
+		return err
+	}
+
+	return nil
+}
+
+func exportBlockChain(b *blockchain.BlockChain, fn string) error {
+	log.Info("Exporting blockchain", "file", fn)
+	// Open the file handle and potentially wrap with a gzip stream
+	fh, err := os.OpenFile(fn, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, os.ModePerm)
+	if err != nil {
+		return err
+	}
+	defer fh.Close()
+
+	var writer io.Writer = fh
+	if strings.HasSuffix(fn, ".gz") {
+		writer = gzip.NewWriter(writer)
+		defer writer.(*gzip.Writer).Close()
+	}
+	// Iterate over the blocks and export them
+	if err := b.Export(writer); err != nil {
+		return err
+	}
+	log.Info("Exported blockchain", "file", fn)
+
+	return nil
+}
+
+// ExportAppendChain exports a blockchain into the specified file, appending to
+// the file if data already exists in it.
+func exportAppendBlockChain(b *blockchain.BlockChain, fn string, first uint64, last uint64) error {
+	log.Info("Exporting blockchain", "file", fn)
+	// Open the file handle and potentially wrap with a gzip stream
+	fh, err := os.OpenFile(fn, os.O_CREATE|os.O_APPEND|os.O_WRONLY, os.ModePerm)
+	if err != nil {
+		return err
+	}
+	defer fh.Close()
+
+	var writer io.Writer = fh
+	if strings.HasSuffix(fn, ".gz") {
+		writer = gzip.NewWriter(writer)
+		defer writer.(*gzip.Writer).Close()
+	}
+	// Iterate over the blocks and export them
+	if err := b.ExportN(writer, first, last); err != nil {
+		return err
+	}
+	log.Info("Exported blockchain to", "file", fn)
+	return nil
+}
+
+func importChain(args []string) error {
+	if len(args) < 1 {
+		return errors.New("This command requires an argument")
+	}
+
+	stack, err := makeNode()
+	if err != nil {
+		return err
+	}
+
+	ctx := stack.GetNodeConfig()
+	ftsrv, err := ftservice.New(ctx, ftCfgInstance.FtServiceCfg)
+	if err != nil {
+		return err
+	}
+
+	// Start periodically gathering memory profiles
+	var peakMemAlloc, peakMemSys uint64
+	go func() {
+		stats := new(runtime.MemStats)
+		for {
+			runtime.ReadMemStats(stats)
+			if atomic.LoadUint64(&peakMemAlloc) < stats.Alloc {
+				atomic.StoreUint64(&peakMemAlloc, stats.Alloc)
+			}
+			if atomic.LoadUint64(&peakMemSys) < stats.Sys {
+				atomic.StoreUint64(&peakMemSys, stats.Sys)
+			}
+			time.Sleep(5 * time.Second)
+		}
+	}()
+
+	start := time.Now()
+
+	fp := args[0]
+	if len(args) == 1 {
+		if err := importBlockchain(ftsrv.BlockChain(), fp); err != nil {
+			return fmt.Errorf("Import error: %v", err)
+		}
+	} else {
+		for i := 0; i < len(args); i++ {
+			if err := importBlockchain(ftsrv.BlockChain(), args[i]); err != nil {
+				return fmt.Errorf("Import error: %v, %v", err, args[i])
+			}
+		}
+	}
+
+	log.Info("Import done in ", "time", time.Since(start))
+
+	db := ftsrv.ChainDb().(*ldb.LDBDatabase)
+	stats, err := db.LDB().GetProperty("leveldb.stats")
+	if err != nil {
+		return fmt.Errorf("Failed to read database stats: %v", err)
+	}
+	fmt.Println(stats)
+
+	ioStats, err := db.LDB().GetProperty("leveldb.iostats")
+	if err != nil {
+		return fmt.Errorf("Failed to read database iostats: %v", err)
+	}
+	fmt.Println(ioStats)
+
+	mem := new(runtime.MemStats)
+	runtime.ReadMemStats(mem)
+
+	fmt.Printf("Object memory: %.3f MB current, %.3f MB peak\n", float64(mem.Alloc)/1024/1024, float64(atomic.LoadUint64(&peakMemAlloc))/1024/1024)
+	fmt.Printf("System memory: %.3f MB current, %.3f MB peak\n", float64(mem.Sys)/1024/1024, float64(atomic.LoadUint64(&peakMemSys))/1024/1024)
+	fmt.Printf("Allocations:   %.3f million\n", float64(mem.Mallocs)/1000000)
+	fmt.Printf("GC pause:      %v\n\n", time.Duration(mem.PauseTotalNs))
+
+	// Compact the entire database to more accurately measure disk io and print the stats
+	start = time.Now()
+	fmt.Println("Compacting entire database...")
+	if err = db.LDB().CompactRange(util.Range{}); err != nil {
+		return fmt.Errorf("Compaction failed: %v", err)
+	}
+	fmt.Printf("Compaction done in %v.\n\n", time.Since(start))
+
+	stats, err = db.LDB().GetProperty("leveldb.stats")
+	if err != nil {
+		return fmt.Errorf("Failed to read database stats: %v", err)
+	}
+	fmt.Println(stats)
+
+	ioStats, err = db.LDB().GetProperty("leveldb.iostats")
+	if err != nil {
+		return fmt.Errorf("Failed to read database iostats: %v", err)
+	}
+	fmt.Println(ioStats)
+
+	return nil
+}
+
+func importBlockchain(chain *blockchain.BlockChain, fn string) error {
+	// Watch for Ctrl-C while the import is running.
+	// If a signal is received, the import will stop at the next batch.
+	interrupt := make(chan os.Signal, 1)
+	stop := make(chan struct{})
+	signal.Notify(interrupt, syscall.SIGINT, syscall.SIGTERM)
+	defer signal.Stop(interrupt)
+	defer close(interrupt)
+	go func() {
+		if _, ok := <-interrupt; ok {
+			log.Info("Interrupted during import, stopping at next batch")
+		}
+		close(stop)
+	}()
+	checkInterrupt := func() bool {
+		select {
+		case <-stop:
+			return true
+		default:
+			return false
+		}
+	}
+
+	log.Info("Importing blockchain", "file", fn)
+
+	// Open the file handle and potentially unwrap the gzip stream
+	fh, err := os.Open(fn)
+	if err != nil {
+		return err
+	}
+	defer fh.Close()
+
+	var reader io.Reader = fh
+	if strings.HasSuffix(fn, ".gz") {
+		if reader, err = gzip.NewReader(reader); err != nil {
+			return err
+		}
+	}
+	stream := rlp.NewStream(reader, 0)
+
+	// Run actual the import.
+	blocks := make(types.Blocks, importBatchSize)
+	n := 0
+	for batch := 0; ; batch++ {
+		// Load a batch of RLP blocks.
+		if checkInterrupt() {
+			return fmt.Errorf("interrupted")
+		}
+		i := 0
+		for ; i < importBatchSize; i++ {
+			var b types.Block
+			if err := stream.Decode(&b); err == io.EOF {
+				break
+			} else if err != nil {
+				return fmt.Errorf("at block %d: %v", n, err)
+			}
+			// don't import first block
+			if b.NumberU64() == 0 {
+				i--
+				continue
+			}
+			blocks[i] = &b
+			n++
+		}
+		if i == 0 {
+			break
+		}
+		// Import the batch.
+		if checkInterrupt() {
+			return fmt.Errorf("interrupted")
+		}
+		missing := missingBlocks(chain, blocks[:i])
+		if len(missing) == 0 {
+			log.Info("Skipping batch as all blocks present", "batch", batch, "first", blocks[0].Hash(), "last", blocks[i-1].Hash())
+			continue
+		}
+		if _, err := chain.InsertChain(missing); err != nil {
+			return fmt.Errorf("invalid block %d: %v", n, err)
+		}
+	}
+	return nil
+}
+
+func missingBlocks(chain *blockchain.BlockChain, blocks []*types.Block) []*types.Block {
+	head := chain.CurrentBlock()
+	for i, block := range blocks {
+		// If we're behind the chain head, only check block, state is available at head
+		if head.NumberU64() > block.NumberU64() {
+			if !chain.HasBlock(block.Hash(), block.NumberU64()) {
+				return blocks[i:]
+			}
+			continue
+		}
+		// If we're above the chain head, state availability is a must
+		if !chain.HasBlockAndState(block.Hash(), block.NumberU64()) {
+			return blocks[i:]
+		}
+	}
+	return nil
+}
diff --git a/cmd/ft/config.go b/cmd/ft/config.go
index 7dd199a9..a468447f 100644
--- a/cmd/ft/config.go
+++ b/cmd/ft/config.go
@@ -13,59 +13,101 @@
 //
 // You should have received a copy of the GNU General Public License
 // along with this program. If not, see <http://www.gnu.org/licenses/>.
+
 package main
 
 import (
-	"io"
-	"os"
-
 	"github.com/ethereum/go-ethereum/log"
+	"github.com/fractalplatform/fractal/cmd/utils"
 	"github.com/fractalplatform/fractal/ftservice"
+	"github.com/fractalplatform/fractal/ftservice/gasprice"
+	"github.com/fractalplatform/fractal/metrics"
 	"github.com/fractalplatform/fractal/node"
-	colorable "github.com/mattn/go-colorable"
-	"github.com/mattn/go-isatty"
+	"github.com/fractalplatform/fractal/p2p"
+	"github.com/fractalplatform/fractal/params"
+	"github.com/fractalplatform/fractal/txpool"
 )
 
-var glogger *log.GlogHandler
+var (
+	//ft config instance
+	ftCfgInstance = defaultFtConfig()
+)
 
 type ftConfig struct {
-	ConfigFileFlag  string
-	GenesisFileFlag string
-	NodeCfg         *node.Config
-	FtServiceCfg    *ftservice.Config
+	GenesisFile  string            `mapstructure:"genesis"`
+	LogCfg       *utils.LogConfig  `mapstructure:"log"`
+	NodeCfg      *node.Config      `mapstructure:"node"`
+	FtServiceCfg *ftservice.Config `mapstructure:"ftservice"`
+}
+
+func defaultFtConfig() *ftConfig {
+	return &ftConfig{
+		LogCfg:       utils.DefaultLogConfig(),
+		NodeCfg:      defaultNodeConfig(),
+		FtServiceCfg: defaultFtServiceConfig(),
+	}
 }
 
-// LogConfig log config
-type LogConfig struct {
-	PrintOrigins bool   `mapstructure:"log-printorigins"`
-	Level        int    `mapstructure:"log-level"`
-	Vmodule      string `mapstructure:"log-vmodule"`
-	BacktraceAt  string `mapstructure:"log-backtraceat"`
+func defaultNodeConfig() *node.Config {
+	return &node.Config{
+		Name:              params.ClientIdentifier,
+		DataDir:           defaultDataDir(),
+		UseLightweightKDF: false,
+		IPCPath:           params.ClientIdentifier + ".ipc",
+		HTTPHost:          "localhost",
+		HTTPPort:          8545,
+		HTTPModules:       []string{"ft", "miner", "dpos", "account", "txpool"},
+		HTTPVirtualHosts:  []string{"localhost"},
+		HTTPCors:          []string{"*"},
+		WSHost:            "localhost",
+		WSPort:            8546,
+		WSModules:         []string{"ft"},
+		Logger:            log.New(),
+		P2PConfig:         defaultP2pConfig(),
+	}
 }
 
-func defaultLogConfig() *LogConfig {
-	return &LogConfig{
-		PrintOrigins: false,
-		Level:        3,
+func defaultP2pConfig() *p2p.Config {
+	cfg := &p2p.Config{
+		MaxPeers:   10,
+		Name:       "Fractal-P2P",
+		ListenAddr: ":2018",
 	}
+	return cfg
 }
 
-func init() {
-	usecolor := (isatty.IsTerminal(os.Stderr.Fd()) || isatty.IsCygwinTerminal(os.Stderr.Fd())) && os.Getenv("TERM") != "dumb"
-	output := io.Writer(os.Stderr)
-	if usecolor {
-		output = colorable.NewColorableStderr()
+func defaultFtServiceConfig() *ftservice.Config {
+	return &ftservice.Config{
+		DatabaseHandles: makeDatabaseHandles(),
+		DatabaseCache:   768,
+		TxPool:          txpool.DefaultTxPoolConfig,
+		Miner:           defaultMinerConfig(),
+		GasPrice: gasprice.Config{
+			Blocks:     20,
+			Percentile: 60,
+		},
+		MetricsConf:     defaultMetricsConfig(),
+		ContractLogFlag: false,
+		Snapshot:        true,
 	}
+}
 
-	glogger = log.NewGlogHandler(log.StreamHandler(output, log.TerminalFormat(usecolor)))
+func defaultMinerConfig() *ftservice.MinerConfig {
+	return &ftservice.MinerConfig{
+		Name:        params.DefaultChainconfig.SysName,
+		PrivateKeys: []string{"289c2857d4598e37fb9647507e47a309d6133539bf21a8b9cb6df88fd5232032"},
+		ExtraData:   "system",
+	}
 }
 
-//Setup initializes logging based on the LogConfig
-func (lc *LogConfig) Setup() {
-	// logging
-	log.PrintOrigins(lc.PrintOrigins)
-	glogger.Verbosity(log.Lvl(lc.Level))
-	glogger.Vmodule(lc.Vmodule)
-	glogger.BacktraceAt(lc.BacktraceAt)
-	log.Root().SetHandler(glogger)
+func defaultMetricsConfig() *metrics.Config {
+	return &metrics.Config{
+		MetricsFlag:  false,
+		InfluxDBFlag: false,
+		URL:          "http://localhost:8086",
+		DataBase:     "metrics",
+		UserName:     "",
+		PassWd:       "",
+		NameSpace:    "fractal/",
+	}
 }
diff --git a/cmd/ft/config.yaml b/cmd/ft/config.yaml
deleted file mode 100644
index d35cdbad..00000000
--- a/cmd/ft/config.yaml
+++ /dev/null
@@ -1,49 +0,0 @@
-log-printorigins: false
-log-level:  4
-log-vmodule:  ""
-log-backtraceat: ""
-
-#node-datadir: ""
-#node-ipcpath: ""
-#node-keystore: ""
-#node-lightkdf: false
-node-httphost:  "localhost"
-node-httpport:  8545
-node-httpmodules: ["ft"]
-#node-httpcors:  ["", ""]
-node-httpvirtualhosts: ["localhost"]
-node-wshost: "localhost"
-node-wsport: 8546
-node-wsmodules: ["ft"]
-
-#node-wsorigins: ["", ""]
-#node-wsexposall:  false
-
-ftservice-databasecache: 768
-
-ethash-cachedir: "zethash"
-ethash-cachesinmem: 2
-ethash-cachesondisk: 3
-#ethash-datasetdir:  ""
-ethash-datasetsinmem: 1
-ethash-datasetsondisk: 2
-#ethash-powmode: 0
-
-#txpool-nolocals:  false
-txpool-journal:   "transactions.rlp"
-#txpool-rejournal: 0
-txpool-pricebump: 10
-txpool-pricelimit: 1
-txpool-accountslots: 16
-txpool-accountqueue: 64
-txpool-globalslots: 4096
-txpool-globalqueue: 1024
-#txpool-lifetime: 0
-
-#test-metricsflag: false
-#test-influxdbflag: false
-#test-influxdburl: ""
-#test-influxdbname: ""
-#test-influxdbuser: ""
-#test-influxdbpasswd: ""
-#test-influxdbnamespace: ""
\ No newline at end of file
diff --git a/cmd/ft/default.go b/cmd/ft/default.go
deleted file mode 100644
index 9a84afe5..00000000
--- a/cmd/ft/default.go
+++ /dev/null
@@ -1,128 +0,0 @@
-// Copyright 2018 The Fractal Team Authors
-// This file is part of the fractal project.
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-package main
-
-import (
-	"time"
-
-	"github.com/ethereum/go-ethereum/log"
-	"github.com/fractalplatform/fractal/ftservice"
-	"github.com/fractalplatform/fractal/ftservice/gasprice"
-	"github.com/fractalplatform/fractal/metrics"
-	"github.com/fractalplatform/fractal/node"
-	"github.com/fractalplatform/fractal/p2p"
-	"github.com/fractalplatform/fractal/params"
-	"github.com/fractalplatform/fractal/txpool"
-)
-
-var (
-	// log config
-	logConfig = defaultLogConfig()
-
-	//ft config
-	ftconfig = defaultFtConfig()
-)
-
-func defaultFtConfig() *ftConfig {
-	return &ftConfig{
-		NodeCfg:      defaultNodeConfig(),
-		FtServiceCfg: defaultFtServiceConfig(),
-	}
-}
-
-func defaultFtServiceConfig() *ftservice.Config {
-	return &ftservice.Config{
-		DatabaseHandles: makeDatabaseHandles(),
-		DatabaseCache:   768,
-		TxPool:          defaultTxPoolConfig(),
-		Miner:           defaultMinerConfig(),
-		GasPrice: gasprice.Config{
-			Blocks:     20,
-			Percentile: 60,
-		},
-		MetricsConf: defaultMetricsConfig(),
-	}
-}
-
-func defaultNodeConfig() *node.Config {
-	return &node.Config{
-		Name:              params.ClientIdentifier,
-		DataDir:           defaultDataDir(),
-		UseLightweightKDF: false,
-		IPCPath:           params.ClientIdentifier + ".ipc",
-
-		HTTPHost:         "localhost",
-		HTTPPort:         8545,
-		HTTPModules:      []string{"ft", "miner", "dpos", "account", "txpool", "keystore"},
-		HTTPVirtualHosts: []string{"localhost"},
-		HTTPCors:         []string{"*"},
-
-		WSHost:    "localhost",
-		WSPort:    8546,
-		WSModules: []string{"ft"},
-		Logger:    log.New(),
-
-		P2PConfig: defaultP2pConfig(),
-	}
-}
-
-func defaultP2pConfig() *p2p.Config {
-	cfg := &p2p.Config{
-		MaxPeers:   10,
-		Name:       "Fractal-P2P",
-		ListenAddr: ":2018",
-	}
-	return cfg
-}
-
-func defaultTxPoolConfig() *txpool.Config {
-	return &txpool.Config{
-		Journal:   "transactions.rlp",
-		Rejournal: time.Hour,
-
-		PriceLimit: 1,
-		PriceBump:  10,
-
-		AccountSlots: 128,
-		GlobalSlots:  4096,
-		AccountQueue: 1280,
-		GlobalQueue:  40960,
-
-		Lifetime:   3 * time.Hour,
-		GasAssetID: 1,
-	}
-}
-
-func defaultMinerConfig() *ftservice.MinerConfig {
-	return &ftservice.MinerConfig{
-		Name:        params.DefaultChainconfig.SysName.String(),
-		PrivateKeys: []string{"289c2857d4598e37fb9647507e47a309d6133539bf21a8b9cb6df88fd5232032"},
-		ExtraData:   "system",
-	}
-}
-
-func defaultMetricsConfig() *metrics.Config {
-	return &metrics.Config{
-		MetricsFlag:  false,
-		InfluxDBFlag: false,
-		Url:          "http://localhost:8086",
-		DataBase:     "metrics",
-		UserName:     "",
-		PassWd:       "",
-		NameSpace:    "fractal/",
-	}
-}
diff --git a/cmd/ft/flags.go b/cmd/ft/flags.go
new file mode 100644
index 00000000..585e0158
--- /dev/null
+++ b/cmd/ft/flags.go
@@ -0,0 +1,488 @@
+// Copyright 2018 The Fractal Team Authors
+// This file is part of the fractal project.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+package main
+
+import (
+	flag "github.com/spf13/pflag"
+	"github.com/spf13/viper"
+)
+
+var (
+	// ConfigFile the Fractal config file
+	ConfigFile string
+)
+
+func addFlags(flags *flag.FlagSet) {
+	// log
+	flags.BoolVar(
+		&ftCfgInstance.LogCfg.PrintOrigins,
+		"log_debug",
+		ftCfgInstance.LogCfg.PrintOrigins,
+		"Prepends log messages with call-site location (file and line number)",
+	)
+	viper.BindPFlag("log.debug", flags.Lookup("log_debug"))
+
+	flags.IntVar(
+		&ftCfgInstance.LogCfg.Level,
+		"log_level",
+		ftCfgInstance.LogCfg.Level,
+		"Logging verbosity: 0=silent, 1=error, 2=warn, 3=info, 4=debug, 5=detail",
+	)
+	viper.BindPFlag("log.level", flags.Lookup("log_level"))
+
+	flags.StringVar(
+		&ftCfgInstance.LogCfg.Vmodule,
+		"log_module",
+		ftCfgInstance.LogCfg.Vmodule,
+		"Per-module verbosity: comma-separated list of <pattern>=<level> (e.g. ft/*=5,p2p=4)",
+	)
+	viper.BindPFlag("log.module", flags.Lookup("log_module"))
+
+	flags.StringVar(
+		&ftCfgInstance.LogCfg.BacktraceAt,
+		"log_backtrace",
+		ftCfgInstance.LogCfg.BacktraceAt,
+		"Request a stack trace at a specific logging statement (e.g. \"block.go:271\")",
+	)
+	viper.BindPFlag("log.backtrace", flags.Lookup("log_backtrace"))
+
+	// config file
+	flags.StringVarP(
+		&ConfigFile,
+		"config", "c",
+		"",
+		"TOML/YAML configuration file",
+	)
+
+	// Genesis File
+	flags.StringVarP(
+		&ftCfgInstance.GenesisFile,
+		"genesis",
+		"g", "",
+		"Genesis json file",
+	)
+	viper.BindPFlag("genesis", flags.Lookup("genesis"))
+
+	// node datadir
+	flags.StringVarP(
+		&ftCfgInstance.NodeCfg.DataDir,
+		"datadir", "d",
+		ftCfgInstance.NodeCfg.DataDir,
+		"Data directory for the databases ",
+	)
+	viper.BindPFlag("node.datadir", flags.Lookup("datadir"))
+
+	// node
+	flags.BoolVar(
+		&ftCfgInstance.NodeCfg.UseLightweightKDF,
+		"lightkdf",
+		ftCfgInstance.NodeCfg.UseLightweightKDF,
+		"Reduce key-derivation RAM & CPU usage at some expense of KDF strength",
+	)
+	viper.BindPFlag("node.lightkdf", flags.Lookup("lightkdf"))
+
+	flags.StringVar(
+		&ftCfgInstance.NodeCfg.IPCPath,
+		"ipcpath",
+		ftCfgInstance.NodeCfg.IPCPath,
+		"RPC:ipc file name",
+	)
+	viper.BindPFlag("node.ipcpath", flags.Lookup("ipcpath"))
+
+	flags.StringVar(
+		&ftCfgInstance.NodeCfg.HTTPHost,
+		"http_host",
+		ftCfgInstance.NodeCfg.HTTPHost,
+		"RPC:http host address",
+	)
+	viper.BindPFlag("node.httphost", flags.Lookup("http_host"))
+
+	flags.IntVar(
+		&ftCfgInstance.NodeCfg.HTTPPort,
+		"http_port",
+		ftCfgInstance.NodeCfg.HTTPPort,
+		"RPC:http host port",
+	)
+	viper.BindPFlag("node.httpport", flags.Lookup("http_port"))
+
+	flags.StringSliceVar(
+		&ftCfgInstance.NodeCfg.HTTPModules,
+		"http_modules",
+		ftCfgInstance.NodeCfg.HTTPModules,
+		"RPC:http api's offered over the HTTP-RPC interface",
+	)
+	viper.BindPFlag("node.httpmodules", flags.Lookup("http_modules"))
+
+	flags.StringSliceVar(
+		&ftCfgInstance.NodeCfg.HTTPCors,
+		"http_cors",
+		ftCfgInstance.NodeCfg.HTTPCors,
+		"RPC:Which to accept cross origin",
+	)
+	viper.BindPFlag("node.httpcors", flags.Lookup("http_cors"))
+
+	flags.StringSliceVar(
+		&ftCfgInstance.NodeCfg.HTTPVirtualHosts,
+		"http_vhosts",
+		ftCfgInstance.NodeCfg.HTTPVirtualHosts,
+		"RPC:http virtual hostnames from which to accept requests",
+	)
+	viper.BindPFlag("node.httpvirtualhosts", flags.Lookup("http_vhosts"))
+
+	flags.StringVar(
+		&ftCfgInstance.NodeCfg.WSHost,
+		"ws_host",
+		ftCfgInstance.NodeCfg.WSHost,
+		"RPC:websocket host address",
+	)
+	viper.BindPFlag("node.wshost", flags.Lookup("ws_host"))
+
+	flags.IntVar(
+		&ftCfgInstance.NodeCfg.WSPort,
+		"ws_port",
+		ftCfgInstance.NodeCfg.WSPort,
+		"RPC:websocket host port",
+	)
+	viper.BindPFlag("node.wsport", flags.Lookup("ws_port"))
+
+	flags.StringSliceVar(
+		&ftCfgInstance.NodeCfg.WSModules,
+		"ws_modules",
+		ftCfgInstance.NodeCfg.WSModules,
+		"RPC:ws api's offered over the WS-RPC interface",
+	)
+	viper.BindPFlag("node.wsmodules", flags.Lookup("ws_modules"))
+
+	flags.StringSliceVar(
+		&ftCfgInstance.NodeCfg.WSOrigins,
+		"ws_origins",
+		ftCfgInstance.NodeCfg.WSOrigins,
+		"RPC:ws origins from which to accept websockets requests",
+	)
+	viper.BindPFlag("node.wsorigins", flags.Lookup("ws_origins"))
+
+	flags.BoolVar(
+		&ftCfgInstance.NodeCfg.WSExposeAll,
+		"ws_exposeall",
+		ftCfgInstance.NodeCfg.WSExposeAll,
+		"RPC:ws exposes all API modules via the WebSocket RPC interface rather than just the public ones.",
+	)
+	viper.BindPFlag("node.wsexposeall", flags.Lookup("ws_exposeall"))
+
+	// ftservice database options
+	flags.IntVar(
+		&ftCfgInstance.FtServiceCfg.DatabaseCache,
+		"database_cache",
+		ftCfgInstance.FtServiceCfg.DatabaseCache,
+		"Megabytes of memory allocated to internal database caching",
+	)
+	viper.BindPFlag("ftservice.databasecache", flags.Lookup("database_cache"))
+
+	flags.BoolVar(
+		&ftCfgInstance.FtServiceCfg.ContractLogFlag,
+		"contractlog",
+		ftCfgInstance.FtServiceCfg.ContractLogFlag,
+		"flag for db to store contrat internal transaction log.",
+	)
+	viper.BindPFlag("ftservice.contractlog", flags.Lookup("contractlog"))
+
+	// txpool
+	flags.BoolVar(
+		&ftCfgInstance.FtServiceCfg.TxPool.NoLocals,
+		"txpool_nolocals",
+		ftCfgInstance.FtServiceCfg.TxPool.NoLocals,
+		"Disables price exemptions for locally submitted transactions",
+	)
+	viper.BindPFlag("ftservice.txpool.nolocals", flags.Lookup("txpool_nolocals"))
+
+	flags.StringVar(
+		&ftCfgInstance.FtServiceCfg.TxPool.Journal,
+		"txpool_journal",
+		ftCfgInstance.FtServiceCfg.TxPool.Journal,
+		"Disk journal for local transaction to survive node restarts",
+	)
+	viper.BindPFlag("ftservice.txpool.journal", flags.Lookup("txpool_journal"))
+
+	flags.DurationVar(
+		&ftCfgInstance.FtServiceCfg.TxPool.Rejournal,
+		"txpool_rejournal",
+		ftCfgInstance.FtServiceCfg.TxPool.Rejournal,
+		"Time interval to regenerate the local transaction journal",
+	)
+	viper.BindPFlag("ftservice.txpool.rejournal", flags.Lookup("txpool_rejournal"))
+
+	flags.Uint64Var(
+		&ftCfgInstance.FtServiceCfg.TxPool.PriceBump,
+		"txpool_pricebump",
+		ftCfgInstance.FtServiceCfg.TxPool.PriceBump,
+		"Price bump percentage to replace an already existing transaction",
+	)
+	viper.BindPFlag("ftservice.txpool.pricebump", flags.Lookup("txpool_pricebump"))
+
+	flags.Uint64Var(
+		&ftCfgInstance.FtServiceCfg.TxPool.PriceLimit,
+		"txpool_pricelimit",
+		ftCfgInstance.FtServiceCfg.TxPool.PriceLimit,
+		"Minimum gas price limit to enforce for acceptance into the pool",
+	)
+	viper.BindPFlag("ftservice.txpool.pricelimit", flags.Lookup("txpool_pricelimit"))
+
+	flags.Uint64Var(
+		&ftCfgInstance.FtServiceCfg.TxPool.AccountSlots,
+		"txpool_accountslots",
+		ftCfgInstance.FtServiceCfg.TxPool.AccountSlots,
+		"Number of executable transaction slots guaranteed per account",
+	)
+	viper.BindPFlag("ftservice.txpool.accountslots", flags.Lookup("txpool_accountslots"))
+
+	flags.Uint64Var(
+		&ftCfgInstance.FtServiceCfg.TxPool.AccountQueue,
+		"txpool_accountqueue",
+		ftCfgInstance.FtServiceCfg.TxPool.AccountQueue,
+		"Maximum number of non-executable transaction slots permitted per account",
+	)
+	viper.BindPFlag("ftservice.txpool.accountqueue", flags.Lookup("txpool_accountqueue"))
+
+	flags.Uint64Var(
+		&ftCfgInstance.FtServiceCfg.TxPool.GlobalSlots,
+		"txpool_globalslots",
+		ftCfgInstance.FtServiceCfg.TxPool.GlobalSlots,
+		"Maximum number of executable transaction slots for all accounts",
+	)
+	viper.BindPFlag("ftservice.txpool.globalslots", flags.Lookup("txpool_globalslots"))
+
+	flags.Uint64Var(
+		&ftCfgInstance.FtServiceCfg.TxPool.GlobalQueue,
+		"txpool_globalqueue",
+		ftCfgInstance.FtServiceCfg.TxPool.GlobalQueue,
+		"Minimum number of non-executable transaction slots for all accounts",
+	)
+	viper.BindPFlag("ftservice.txpool.globalqueue", flags.Lookup("txpool_globalqueue"))
+
+	flags.DurationVar(
+		&ftCfgInstance.FtServiceCfg.TxPool.Lifetime,
+		"txpool_lifetime",
+		ftCfgInstance.FtServiceCfg.TxPool.Lifetime,
+		"Maximum amount of time non-executable transaction are queued",
+	)
+	viper.BindPFlag("ftservice.txpool.lifetime", flags.Lookup("txpool_lifetime"))
+
+	// miner
+	flags.BoolVar(
+		&ftCfgInstance.FtServiceCfg.Miner.Start,
+		"miner_start",
+		ftCfgInstance.FtServiceCfg.Miner.Start,
+		"Start miner generate block and process transaction",
+	)
+	viper.BindPFlag("ftservice.miner.start", flags.Lookup("miner_start"))
+
+	flags.StringVar(
+		&ftCfgInstance.FtServiceCfg.Miner.Name,
+		"miner_name",
+		ftCfgInstance.FtServiceCfg.Miner.Name,
+		"Name for block mining rewards",
+	)
+	viper.BindPFlag("ftservice.miner.name", flags.Lookup("miner_name"))
+
+	flags.StringSliceVar(
+		&ftCfgInstance.FtServiceCfg.Miner.PrivateKeys,
+		"miner_private",
+		ftCfgInstance.FtServiceCfg.Miner.PrivateKeys,
+		"Hex of private key for block mining rewards",
+	)
+	viper.BindPFlag("ftservice.miner.private", flags.Lookup("miner_private"))
+
+	flags.StringVar(
+		&ftCfgInstance.FtServiceCfg.Miner.ExtraData,
+		"miner_extra",
+		ftCfgInstance.FtServiceCfg.Miner.ExtraData,
+		"Block extra data set by the miner",
+	)
+	viper.BindPFlag("ftservice.miner.name", flags.Lookup("miner_extra"))
+
+	// gas price oracle
+	flags.IntVar(
+		&ftCfgInstance.FtServiceCfg.GasPrice.Blocks,
+		"gpo_blocks",
+		ftCfgInstance.FtServiceCfg.GasPrice.Blocks,
+		"Number of recent blocks to check for gas prices",
+	)
+	viper.BindPFlag("ftservice.gpo.blocks", flags.Lookup("gpo_blocks"))
+
+	flags.IntVar(
+		&ftCfgInstance.FtServiceCfg.GasPrice.Percentile,
+		"gpo_percentile",
+		ftCfgInstance.FtServiceCfg.GasPrice.Percentile,
+		"Suggested gas price is the given percentile of a set of recent transaction gas prices",
+	)
+	viper.BindPFlag("ftservice.gpo.percentile", flags.Lookup("gpo_percentile"))
+
+	// metrics
+	flags.BoolVar(
+		&ftCfgInstance.FtServiceCfg.MetricsConf.MetricsFlag,
+		"metrics_start",
+		ftCfgInstance.FtServiceCfg.MetricsConf.MetricsFlag,
+		"flag that open statistical metrics",
+	)
+	viper.BindPFlag("ftservice.metrics.start", flags.Lookup("metrics_start"))
+
+	flags.BoolVar(
+		&ftCfgInstance.FtServiceCfg.MetricsConf.InfluxDBFlag,
+		"metrics_influxdb",
+		ftCfgInstance.FtServiceCfg.MetricsConf.InfluxDBFlag,
+		"flag that open influxdb thad store statistical metrics",
+	)
+	viper.BindPFlag("ftservice.metrics.influxdb", flags.Lookup("metrics_influxdb"))
+
+	flags.StringVar(
+		&ftCfgInstance.FtServiceCfg.MetricsConf.URL,
+		"metrics_influxdb_URL",
+		ftCfgInstance.FtServiceCfg.MetricsConf.URL,
+		"URL that connect influxdb",
+	)
+	viper.BindPFlag("ftservice.metrics.influxdbURL", flags.Lookup("metrics_influxdb_URL"))
+
+	flags.StringVar(
+		&ftCfgInstance.FtServiceCfg.MetricsConf.DataBase,
+		"metrics_influxdb_name",
+		ftCfgInstance.FtServiceCfg.MetricsConf.DataBase,
+		"Influxdb database name",
+	)
+	viper.BindPFlag("ftservice.metrics.influxdbname", flags.Lookup("metrics_influxdb_name"))
+
+	flags.StringVar(
+		&ftCfgInstance.FtServiceCfg.MetricsConf.UserName,
+		"metrics_influxdb_user",
+		ftCfgInstance.FtServiceCfg.MetricsConf.UserName,
+		"Indluxdb user name",
+	)
+	viper.BindPFlag("ftservice.metrics.influxdbuser", flags.Lookup("metrics_influxdb_user"))
+
+	flags.StringVar(
+		&ftCfgInstance.FtServiceCfg.MetricsConf.PassWd,
+		"metrics_influxdb_passwd",
+		ftCfgInstance.FtServiceCfg.MetricsConf.PassWd,
+		"Influxdb user passwd",
+	)
+	viper.BindPFlag("ftservice.metrics.influxdbpasswd", flags.Lookup("metrics_influxdb_passwd"))
+
+	flags.StringVar(
+		&ftCfgInstance.FtServiceCfg.MetricsConf.NameSpace,
+		"metrics_influxdb_namespace",
+		ftCfgInstance.FtServiceCfg.MetricsConf.NameSpace,
+		"Influxdb namespace",
+	)
+	viper.BindPFlag("ftservice.metrics.influxdbnamepace", flags.Lookup("metrics_influxdb_namespace"))
+
+	// p2p
+	flags.UintVar(
+		&ftCfgInstance.NodeCfg.P2PConfig.NetworkID,
+		"p2p_id",
+		ftCfgInstance.NodeCfg.P2PConfig.NetworkID,
+		"The ID of the p2p network. Nodes have different ID cannot communicate, even if they have same chainID and block data.",
+	)
+	viper.BindPFlag("ftservice.p2p.networkid", flags.Lookup("p2p_id"))
+
+	flags.StringVar(
+		&ftCfgInstance.NodeCfg.P2PConfig.Name,
+		"p2p_name",
+		ftCfgInstance.NodeCfg.P2PConfig.Name,
+		"The name sets the p2p node name of this server",
+	)
+	viper.BindPFlag("ftservice.p2p.name", flags.Lookup("p2p_name"))
+
+	flags.IntVar(
+		&ftCfgInstance.NodeCfg.P2PConfig.MaxPeers,
+		"p2p_maxpeers",
+		ftCfgInstance.NodeCfg.P2PConfig.MaxPeers,
+		"Maximum number of network peers ",
+	)
+	viper.BindPFlag("ftservice.p2p.maxpeers", flags.Lookup("p2p_maxpeers"))
+
+	flags.IntVar(
+		&ftCfgInstance.NodeCfg.P2PConfig.MaxPendingPeers,
+		"p2p_maxpendpeers",
+		ftCfgInstance.NodeCfg.P2PConfig.MaxPendingPeers,
+		"Maximum number of pending connection attempts ",
+	)
+	viper.BindPFlag("ftservice.p2p.maxpendpeers", flags.Lookup("p2p_maxpendpeers"))
+
+	flags.IntVar(
+		&ftCfgInstance.NodeCfg.P2PConfig.DialRatio,
+		"p2p_dialratio",
+		ftCfgInstance.NodeCfg.P2PConfig.DialRatio,
+		"DialRatio controls the ratio of inbound to dialed connections",
+	)
+	viper.BindPFlag("ftservice.p2p.dialratio", flags.Lookup("p2p_dialratio"))
+
+	flags.StringVar(
+		&ftCfgInstance.NodeCfg.P2PConfig.ListenAddr,
+		"p2p_listenaddr",
+		ftCfgInstance.NodeCfg.P2PConfig.ListenAddr,
+		"Network listening address",
+	)
+	viper.BindPFlag("ftservice.p2p.listenaddr", flags.Lookup("p2p_listenaddr"))
+
+	flags.StringVar(
+		&ftCfgInstance.NodeCfg.P2PConfig.NodeDatabase,
+		"p2p_nodedb",
+		ftCfgInstance.NodeCfg.P2PConfig.NodeDatabase,
+		"The path to the database containing the previously seen live nodes in the network",
+	)
+	viper.BindPFlag("ftservice.p2p.nodedb", flags.Lookup("p2p_nodedb"))
+
+	flags.BoolVar(
+		&ftCfgInstance.NodeCfg.P2PConfig.NoDiscovery,
+		"p2p_nodiscovery",
+		ftCfgInstance.NodeCfg.P2PConfig.NoDiscovery,
+		"Disables the peer discovery mechanism (manual peer addition)",
+	)
+	viper.BindPFlag("ftservice.p2p.nodiscovery", flags.Lookup("p2p_nodiscovery"))
+
+	flags.BoolVar(
+		&ftCfgInstance.NodeCfg.P2PConfig.NoDial,
+		"p2p_nodial",
+		ftCfgInstance.NodeCfg.P2PConfig.NoDial,
+		"The server will not dial any peers.",
+	)
+	viper.BindPFlag("ftservice.p2p.nodial", flags.Lookup("p2p_nodial"))
+
+	flags.StringVar(
+		&ftCfgInstance.NodeCfg.P2PBootNodes,
+		"p2p_bootnodes",
+		ftCfgInstance.NodeCfg.P2PBootNodes,
+		"Node list file. BootstrapNodes are used to establish connectivity with the rest of the network",
+	)
+	viper.BindPFlag("ftservice.p2p.bootnodes", flags.Lookup("p2p_bootnodes"))
+
+	flags.StringVar(
+		&ftCfgInstance.NodeCfg.P2PStaticNodes,
+		"p2p_staticnodes",
+		ftCfgInstance.NodeCfg.P2PStaticNodes,
+		"Node list file. Static nodes are used as pre-configured connections which are always maintained and re-connected on disconnects",
+	)
+	viper.BindPFlag("ftservice.p2p.staticnodes", flags.Lookup("p2p_staticnodes"))
+
+	flags.StringVar(
+		&ftCfgInstance.NodeCfg.P2PTrustNodes,
+		"p2p_trustnodes",
+		ftCfgInstance.NodeCfg.P2PStaticNodes,
+		"Node list file. Trusted nodes are usesd as pre-configured connections which are always allowed to connect, even above the peer limit",
+	)
+	viper.BindPFlag("ftservice.p2p.trustnodes", flags.Lookup("p2p_trustnodes"))
+
+}
diff --git a/cmd/ft/init.go b/cmd/ft/init.go
index 4f4cfc19..2a298e4a 100644
--- a/cmd/ft/init.go
+++ b/cmd/ft/init.go
@@ -17,10 +17,12 @@
 package main
 
 import (
-	"errors"
+	"encoding/json"
 	"fmt"
 	"os"
 
+	"github.com/fractalplatform/fractal/blockchain"
+	"github.com/fractalplatform/fractal/ftservice"
 	"github.com/spf13/cobra"
 )
 
@@ -28,12 +30,12 @@ var dataDir string
 
 // initCmd represents the init command
 var initCmd = &cobra.Command{
-	Use:   "init <genesisPath>",
+	Use:   "init -g <genesis> -d <datadir>",
 	Short: "Bootstrap and initialize a new genesis block",
 	Long:  `Bootstrap and initialize a new genesis block`,
-	Args:  cobra.ExactArgs(1),
 	Run: func(cmd *cobra.Command, args []string) {
-		if err := initGenesis(args); err != nil {
+		ftCfgInstance.LogCfg.Setup()
+		if err := initGenesis(); err != nil {
 			fmt.Println(err)
 		}
 	},
@@ -41,23 +43,35 @@ var initCmd = &cobra.Command{
 
 func init() {
 	RootCmd.AddCommand(initCmd)
-	initCmd.Flags().StringVarP(&ftconfig.NodeCfg.DataDir, "datadir", "d", defaultDataDir(), "Data directory for the databases and keystore")
+	initCmd.Flags().StringVarP(&ftCfgInstance.GenesisFile, "genesis", "g", "", "Genesis json file")
+	initCmd.Flags().StringVarP(&ftCfgInstance.NodeCfg.DataDir, "datadir", "d", ftCfgInstance.NodeCfg.DataDir, "Data directory for the databases ")
 }
 
 // initGenesis will initialise the given JSON format genesis file and writes it as
 // the zero'd block (i.e. genesis) or will fail hard if it can't succeed.
-func initGenesis(args []string) error {
+func initGenesis() error {
 	// Make sure we have a valid genesis JSON
-	genesisPath := args[0]
-	if len(genesisPath) == 0 {
-		return errors.New("Must supply path to genesis JSON file")
+	genesis := new(blockchain.Genesis)
+	if len(ftCfgInstance.GenesisFile) != 0 {
+		file, err := os.Open(ftCfgInstance.GenesisFile)
+		if err != nil {
+			return fmt.Errorf("Failed to read genesis file: %v(%v)", ftCfgInstance.GenesisFile, err)
+		}
+		defer file.Close()
+
+		if err := json.NewDecoder(file).Decode(genesis); err != nil {
+			return fmt.Errorf("invalid genesis file: %v(%v)", ftCfgInstance.GenesisFile, err)
+		}
 	}
-	file, err := os.Open(genesisPath)
+
+	stack, err := makeNode()
 	if err != nil {
-		return fmt.Errorf("Failed to read genesis file: %v", err)
+		return err
 	}
-	defer file.Close()
 
-	// todo init genesis
+	_, err = ftservice.New(stack.GetNodeConfig(), ftCfgInstance.FtServiceCfg)
+	if err != nil {
+		return err
+	}
 	return nil
 }
diff --git a/cmd/ft/root.go b/cmd/ft/root.go
index dc1c3c59..f8a820bd 100644
--- a/cmd/ft/root.go
+++ b/cmd/ft/root.go
@@ -43,11 +43,14 @@ var RootCmd = &cobra.Command{
 	// Uncomment the following line if your bare application
 	// has an action associated with it:
 	Run: func(cmd *cobra.Command, args []string) {
+		var err error
 		if viper.ConfigFileUsed() != "" {
-			viperUmarshalConfig()
+			err = viperUmarshalConfig()
+		}
+		ftCfgInstance.LogCfg.Setup()
+		if err != nil {
+			log.Error("viper umarshal config file faild", "err", err)
 		}
-
-		logConfig.Setup()
 
 		node, err := makeNode()
 		if err != nil {
@@ -66,85 +69,48 @@ var RootCmd = &cobra.Command{
 		}
 
 		node.Wait()
-
 	},
 }
 
-func viperUmarshalConfig() {
-	err := viper.Unmarshal(logConfig)
-	if err != nil {
-		fmt.Println("Unmarshal logConfig err: ", err)
-		os.Exit(-1)
-	}
-
-	err = viper.Unmarshal(ftconfig.NodeCfg)
-	if err != nil {
-		fmt.Println("Unmarshal NodeCfg err: ", err)
-		os.Exit(-1)
-	}
-
-	err = viper.Unmarshal(ftconfig.FtServiceCfg.TxPool)
-	if err != nil {
-		fmt.Println("Unmarshal TxPool err: ", err)
-		os.Exit(-1)
-	}
-
-	err = viper.Unmarshal(&ftconfig.FtServiceCfg.Miner)
-	if err != nil {
-		fmt.Println("Unmarshal miner err: ", err)
-		os.Exit(-1)
-	}
-
-	err = viper.Unmarshal(ftconfig.FtServiceCfg)
-	if err != nil {
-		fmt.Println("Unmarshal FtServiceCfg err: ", err)
-		os.Exit(-1)
-	}
-
-	err = viper.Unmarshal(ftconfig.FtServiceCfg.Miner)
-	if err != nil {
-		fmt.Println("Unmarshal MinerConfig err: ", err)
-		os.Exit(-1)
-	}
-
-	err = viper.Unmarshal(ftconfig.NodeCfg.P2PConfig)
+func viperUmarshalConfig() error {
+	err := viper.Unmarshal(ftCfgInstance)
 	if err != nil {
-		fmt.Println("Unmarshal MinerConfig err: ", err)
-		os.Exit(-1)
+		return err
 	}
-
+	return nil
 }
 
 func makeNode() (*node.Node, error) {
 	// set miner config
 	SetupMetrics()
-
 	// Make sure we have a valid genesis JSON
-	if len(ftconfig.GenesisFileFlag) != 0 {
-		file, err := os.Open(ftconfig.GenesisFileFlag)
+	if len(ftCfgInstance.GenesisFile) != 0 {
+		file, err := os.Open(ftCfgInstance.GenesisFile)
 		if err != nil {
-			return nil, fmt.Errorf("Failed to read genesis file: %v(%v)", ftconfig.GenesisFileFlag, err)
+			return nil, fmt.Errorf("Failed to read genesis file: %v(%v)", ftCfgInstance.GenesisFile, err)
 		}
 		defer file.Close()
 
 		genesis := new(blockchain.Genesis)
 		if err := json.NewDecoder(file).Decode(genesis); err != nil {
-			return nil, fmt.Errorf("invalid genesis file: %v(%v)", ftconfig.GenesisFileFlag, err)
+			return nil, fmt.Errorf("invalid genesis file: %v(%v)", ftCfgInstance.GenesisFile, err)
 		}
-		ftconfig.FtServiceCfg.Genesis = genesis
+		ftCfgInstance.FtServiceCfg.Genesis = genesis
 	}
-	return node.New(ftconfig.NodeCfg)
+
+	return node.New(ftCfgInstance.NodeCfg)
 }
 
+// SetupMetrics set metrics
 func SetupMetrics() {
 	//need to set metrice.Enabled = true in metrics source code
-	if ftconfig.FtServiceCfg.MetricsConf.MetricsFlag {
+	if ftCfgInstance.FtServiceCfg.MetricsConf.MetricsFlag {
 		log.Info("Enabling metrics collection")
-		if ftconfig.FtServiceCfg.MetricsConf.InfluxDBFlag {
+		if ftCfgInstance.FtServiceCfg.MetricsConf.InfluxDBFlag {
 			log.Info("Enabling influxdb collection")
-			go influxdb.InfluxDBWithTags(metrics.DefaultRegistry, 10*time.Second, ftconfig.FtServiceCfg.MetricsConf.Url,
-				ftconfig.FtServiceCfg.MetricsConf.DataBase, ftconfig.FtServiceCfg.MetricsConf.UserName, ftconfig.FtServiceCfg.MetricsConf.PassWd,
-				ftconfig.FtServiceCfg.MetricsConf.NameSpace, map[string]string{})
+			go influxdb.InfluxDBWithTags(metrics.DefaultRegistry, 10*time.Second, ftCfgInstance.FtServiceCfg.MetricsConf.URL,
+				ftCfgInstance.FtServiceCfg.MetricsConf.DataBase, ftCfgInstance.FtServiceCfg.MetricsConf.UserName, ftCfgInstance.FtServiceCfg.MetricsConf.PassWd,
+				ftCfgInstance.FtServiceCfg.MetricsConf.NameSpace, map[string]string{})
 		}
 
 	}
@@ -173,115 +139,27 @@ func startNode(stack *node.Node) error {
 }
 
 func registerService(stack *node.Node) error {
-	var err error
-	// register ftservice
-	err = stack.Register(func(ctx *node.ServiceContext) (node.Service, error) {
-		return ftservice.New(ctx, ftconfig.FtServiceCfg)
+	return stack.Register(func(ctx *node.ServiceContext) (node.Service, error) {
+		return ftservice.New(ctx, ftCfgInstance.FtServiceCfg)
 	})
-	return err
 }
 
 func initConfig() {
-	if ftconfig.ConfigFileFlag != "" {
-		viper.SetConfigFile(ftconfig.ConfigFileFlag)
+	if ConfigFile != "" {
+		viper.SetConfigFile(ConfigFile)
 	} else {
-		log.Info("No config file , use default configuration.")
+		fmt.Println("No config file , use default configuration.")
 		return
 	}
 	if err := viper.ReadInConfig(); err != nil {
-		log.Error("Can't read config: %v, use default configuration.", err)
+		fmt.Printf("Can't read config: %v, use default configuration.", err)
 	}
 }
 
 func init() {
-	RootCmd.AddCommand(utils.VersionCmd)
 	cobra.OnInitialize(initConfig)
-	falgs := RootCmd.Flags()
-	// logging
-	falgs.BoolVar(&logConfig.PrintOrigins, "log_debug", logConfig.PrintOrigins, "Prepends log messages with call-site location (file and line number)")
-	falgs.IntVar(&logConfig.Level, "log_level", logConfig.Level, "Logging verbosity: 0=silent, 1=error, 2=warn, 3=info, 4=debug, 5=detail")
-	falgs.StringVar(&logConfig.Vmodule, "log_vmodule", logConfig.Vmodule, "Per-module verbosity: comma-separated list of <pattern>=<level> (e.g. ft/*=5,p2p=4)")
-	falgs.StringVar(&logConfig.BacktraceAt, "log_backtrace", logConfig.BacktraceAt, "Request a stack trace at a specific logging statement (e.g. \"block.go:271\")")
-
-	// config file
-	falgs.StringVarP(&ftconfig.ConfigFileFlag, "config", "c", "", "TOML configuration file")
-	falgs.StringVarP(&ftconfig.GenesisFileFlag, "genesis", "g", "", "genesis json file")
-
-	// node
-	falgs.StringVarP(&ftconfig.NodeCfg.DataDir, "datadir", "d", ftconfig.NodeCfg.DataDir, "Data directory for the databases and keystore")
-	falgs.BoolVar(&ftconfig.NodeCfg.UseLightweightKDF, "lightkdf", ftconfig.NodeCfg.UseLightweightKDF, "Reduce key-derivation RAM & CPU usage at some expense of KDF strength")
-	falgs.StringVar(&ftconfig.NodeCfg.IPCPath, "ipcpath", ftconfig.NodeCfg.IPCPath, "RPC:ipc file name")
-	falgs.StringVar(&ftconfig.NodeCfg.HTTPHost, "http_host", ftconfig.NodeCfg.HTTPHost, "RPC:http host address")
-	falgs.IntVar(&ftconfig.NodeCfg.HTTPPort, "http_port", ftconfig.NodeCfg.HTTPPort, "RPC:http host port")
-	falgs.StringSliceVar(&ftconfig.NodeCfg.HTTPModules, "http_api", ftconfig.NodeCfg.HTTPModules, "RPC:http api's offered over the HTTP-RPC interface")
-	falgs.StringSliceVar(&ftconfig.NodeCfg.HTTPCors, "http_cors", ftconfig.NodeCfg.HTTPCors, "RPC:Which to accept cross origin")
-	falgs.StringSliceVar(&ftconfig.NodeCfg.HTTPVirtualHosts, "http_vhosts", ftconfig.NodeCfg.HTTPVirtualHosts, "virtual hostnames from which to accept requests")
-	falgs.StringVar(&ftconfig.NodeCfg.WSHost, "ws_host", ftconfig.NodeCfg.WSHost, "RPC:websocket host address")
-	falgs.IntVar(&ftconfig.NodeCfg.WSPort, "ws_port", ftconfig.NodeCfg.WSPort, "RPC:websocket host port")
-	falgs.StringSliceVar(&ftconfig.NodeCfg.WSModules, "ws_api", ftconfig.NodeCfg.HTTPModules, "RPC:ws api's offered over the WS-RPC interface")
-	falgs.StringSliceVar(&ftconfig.NodeCfg.WSOrigins, "ws_origins", ftconfig.NodeCfg.WSOrigins, "RPC:ws origins from which to accept websockets requests")
-	falgs.BoolVar(&ftconfig.NodeCfg.WSExposeAll, "ws_exposeall", ftconfig.NodeCfg.WSExposeAll, "RPC:ws exposes all API modules via the WebSocket RPC interface rather than just the public ones.")
-
-	// ftservice
-	falgs.IntVar(&ftconfig.FtServiceCfg.DatabaseCache, "databasecache", ftconfig.FtServiceCfg.DatabaseCache, "Megabytes of memory allocated to internal database caching")
-
-	// txpool
-	falgs.BoolVar(&ftconfig.FtServiceCfg.TxPool.NoLocals, "txpool_nolocals", ftconfig.FtServiceCfg.TxPool.NoLocals, "Disables price exemptions for locally submitted transactions")
-	falgs.StringVar(&ftconfig.FtServiceCfg.TxPool.Journal, "txpool_journal", ftconfig.FtServiceCfg.TxPool.Journal, "Disk journal for local transaction to survive node restarts")
-	falgs.DurationVar(&ftconfig.FtServiceCfg.TxPool.Rejournal, "txpool_rejournal", ftconfig.FtServiceCfg.TxPool.Rejournal, "Time interval to regenerate the local transaction journal")
-	falgs.Uint64Var(&ftconfig.FtServiceCfg.TxPool.PriceBump, "txpool_pricebump", ftconfig.FtServiceCfg.TxPool.PriceBump, "Price bump percentage to replace an already existing transaction")
-	falgs.Uint64Var(&ftconfig.FtServiceCfg.TxPool.PriceLimit, "txpool_pricelimit", ftconfig.FtServiceCfg.TxPool.PriceLimit, "Minimum gas price limit to enforce for acceptance into the pool")
-	falgs.Uint64Var(&ftconfig.FtServiceCfg.TxPool.AccountSlots, "txpool_accountslots", ftconfig.FtServiceCfg.TxPool.AccountSlots, "Minimum number of executable transaction slots guaranteed per account")
-	falgs.Uint64Var(&ftconfig.FtServiceCfg.TxPool.AccountQueue, "txpool_accountqueue", ftconfig.FtServiceCfg.TxPool.AccountQueue, "Maximum number of non-executable transaction slots permitted per account")
-	falgs.Uint64Var(&ftconfig.FtServiceCfg.TxPool.GlobalSlots, "txpool_globalslots", ftconfig.FtServiceCfg.TxPool.GlobalSlots, "Maximum number of executable transaction slots for all accounts")
-	falgs.Uint64Var(&ftconfig.FtServiceCfg.TxPool.GlobalQueue, "txpool_globalqueue", ftconfig.FtServiceCfg.TxPool.GlobalQueue, "Minimum number of non-executable transaction slots for all accounts")
-	falgs.DurationVar(&ftconfig.FtServiceCfg.TxPool.Lifetime, "txpool_lifetime", ftconfig.FtServiceCfg.TxPool.Lifetime, "Maximum amount of time non-executable transaction are queued")
-
-	// miner
-	falgs.BoolVar(&ftconfig.FtServiceCfg.Miner.Start, "miner_start", false, "miner start")
-	falgs.StringVar(&ftconfig.FtServiceCfg.Miner.Name, "miner_coinbase", ftconfig.FtServiceCfg.Miner.Name, "name for block mining rewards")
-	falgs.StringSliceVar(&ftconfig.FtServiceCfg.Miner.PrivateKeys, "miner_private", ftconfig.FtServiceCfg.Miner.PrivateKeys, "hex of private key for block mining rewards")
-	falgs.StringVar(&ftconfig.FtServiceCfg.Miner.ExtraData, "miner_extra", ftconfig.FtServiceCfg.Miner.ExtraData, "Block extra data set by the miner")
-
-	// gas price oracle
-	falgs.IntVar(&ftconfig.FtServiceCfg.GasPrice.Blocks, "gpo_blocks", ftconfig.FtServiceCfg.GasPrice.Blocks, "Number of recent blocks to check for gas prices")
-	falgs.IntVar(&ftconfig.FtServiceCfg.GasPrice.Percentile, "gpo_percentile", ftconfig.FtServiceCfg.GasPrice.Percentile, "Suggested gas price is the given percentile of a set of recent transaction gas prices")
-	falgs.BoolVar(&ftconfig.FtServiceCfg.MetricsConf.MetricsFlag, "test_metricsflag", ftconfig.FtServiceCfg.MetricsConf.MetricsFlag, "flag that open statistical metrics")
-	falgs.BoolVar(&ftconfig.FtServiceCfg.MetricsConf.InfluxDBFlag, "test_influxdbflag", ftconfig.FtServiceCfg.MetricsConf.InfluxDBFlag, "flag that open influxdb thad store statistical metrics")
-	falgs.StringVar(&ftconfig.FtServiceCfg.MetricsConf.Url, "test_influxdburl", ftconfig.FtServiceCfg.MetricsConf.Url, "url that connect influxdb")
-	falgs.StringVar(&ftconfig.FtServiceCfg.MetricsConf.DataBase, "test_influxdbname", ftconfig.FtServiceCfg.MetricsConf.DataBase, "influxdb database name")
-	falgs.StringVar(&ftconfig.FtServiceCfg.MetricsConf.UserName, "test_influxdbuser", ftconfig.FtServiceCfg.MetricsConf.UserName, "indluxdb user name")
-	falgs.StringVar(&ftconfig.FtServiceCfg.MetricsConf.PassWd, "test_influxdbpasswd", ftconfig.FtServiceCfg.MetricsConf.PassWd, "influxdb user passwd")
-	falgs.StringVar(&ftconfig.FtServiceCfg.MetricsConf.NameSpace, "test_influxdbnamespace", ftconfig.FtServiceCfg.MetricsConf.NameSpace, "influxdb namespace")
-
-	// p2p
-	falgs.IntVar(&ftconfig.NodeCfg.P2PConfig.MaxPeers, "p2p_maxpeers", ftconfig.NodeCfg.P2PConfig.MaxPeers,
-		"Maximum number of network peers (network disabled if set to 0)")
-	falgs.IntVar(&ftconfig.NodeCfg.P2PConfig.MaxPendingPeers, "p2p_maxpendpeers", ftconfig.NodeCfg.P2PConfig.MaxPendingPeers,
-		"Maximum number of pending connection attempts (defaults used if set to 0)")
-	falgs.IntVar(&ftconfig.NodeCfg.P2PConfig.DialRatio, "p2p_dialratio", ftconfig.NodeCfg.P2PConfig.DialRatio,
-		"DialRatio controls the ratio of inbound to dialed connections")
-	falgs.StringVar(&ftconfig.NodeCfg.P2PConfig.ListenAddr, "p2p_listenaddr", ftconfig.NodeCfg.P2PConfig.ListenAddr,
-		"Network listening address")
-	falgs.StringVar(&ftconfig.NodeCfg.P2PConfig.NodeDatabase, "p2p_nodedb", ftconfig.NodeCfg.P2PConfig.NodeDatabase,
-		"The path to the database containing the previously seen live nodes in the network")
-	falgs.StringVar(&ftconfig.NodeCfg.P2PConfig.Name, "p2p_nodename", ftconfig.NodeCfg.P2PConfig.Name,
-		"The node name of this server")
-	falgs.BoolVar(&ftconfig.NodeCfg.P2PConfig.NoDiscovery, "p2p_nodiscover", ftconfig.NodeCfg.P2PConfig.NoDiscovery,
-		"Disables the peer discovery mechanism (manual peer addition)")
-	falgs.BoolVar(&ftconfig.NodeCfg.P2PConfig.NoDial, "p2p_nodial", ftconfig.NodeCfg.P2PConfig.NoDial,
-		"The server will not dial any peers.")
-	falgs.UintVar(&ftconfig.NodeCfg.P2PConfig.NetworkID, "p2p_id", ftconfig.NodeCfg.P2PConfig.NetworkID,
-		"The ID of the p2p network. Nodes have different ID cannot communicate, even if they have same chainID and block data.")
-	falgs.StringVar(&ftconfig.NodeCfg.P2PBootNodes, "p2p_bootnodes", ftconfig.NodeCfg.P2PBootNodes,
-		"Node list file. BootstrapNodes are used to establish connectivity with the rest of the network")
-	falgs.StringVar(&ftconfig.NodeCfg.P2PStaticNodes, "p2p_staticnodes", ftconfig.NodeCfg.P2PStaticNodes,
-		"Node list file. Static nodes are used as pre-configured connections which are always maintained and re-connected on disconnects")
-	falgs.StringVar(&ftconfig.NodeCfg.P2PTrustNodes, "p2p_trustnodes", ftconfig.NodeCfg.P2PStaticNodes,
-		"Node list file. Trusted nodes are usesd as pre-configured connections which are always allowed to connect, even above the peer limit")
-
-	// snapshot
-	falgs.BoolVar(&ftconfig.FtServiceCfg.Snapshot, "snapshot_enable", false, "snapshot enable")
+	RootCmd.AddCommand(utils.VersionCmd)
+	addFlags(RootCmd.Flags())
 }
 
 // Execute adds all child commands to the root command sets flags appropriately.
diff --git a/cmd/ftfinder/root.go b/cmd/ftfinder/root.go
index eea47016..acc69816 100644
--- a/cmd/ftfinder/root.go
+++ b/cmd/ftfinder/root.go
@@ -35,9 +35,9 @@ var nodeConfig = node.Config{
 
 // RootCmd represents the base command when called without any subcommands
 var RootCmd = &cobra.Command{
-	//	Use:   "ftfinder",
-	//	Short: "ftfinder is a fractal node discoverer",
-	//	Long:  `ftfinder is a fractal node discoverer`,
+	Use:   "ftfinder",
+	Short: "ftfinder is a fractal node discoverer",
+	Long:  `ftfinder is a fractal node discoverer`,
 
 	// Uncomment the following line if your bare application
 	// has an action associated with it:
@@ -62,18 +62,42 @@ var RootCmd = &cobra.Command{
 
 func init() {
 	RootCmd.AddCommand(utils.VersionCmd)
-	falgs := RootCmd.Flags()
+	flags := RootCmd.Flags()
 	// p2p
-	falgs.StringVarP(&nodeConfig.DataDir, "datadir", "d", nodeConfig.DataDir, "Data directory for the databases and keystore")
-	falgs.StringVar(&nodeConfig.P2PConfig.ListenAddr, "p2p_listenaddr", nodeConfig.P2PConfig.ListenAddr,
-		"Network listening address")
-	falgs.StringVar(&nodeConfig.P2PConfig.NodeDatabase, "p2p_nodedb", nodeConfig.P2PConfig.NodeDatabase,
-		"The path to the database containing the previously seen live nodes in the network")
+	flags.StringVarP(
+		&nodeConfig.DataDir,
+		"datadir", "d",
+		nodeConfig.DataDir,
+		"Data directory for the databases ",
+	)
 
-	falgs.UintVar(&nodeConfig.P2PConfig.NetworkID, "p2p_id", nodeConfig.P2PConfig.NetworkID,
-		"The ID of the p2p network. Nodes have different ID cannot communicate, even if they have same chainID and block data.")
-	falgs.StringVar(&nodeConfig.P2PBootNodes, "p2p_bootnodes", nodeConfig.P2PBootNodes,
-		"Node list file. BootstrapNodes are used to establish connectivity with the rest of the network")
+	flags.StringVar(
+		&nodeConfig.P2PConfig.ListenAddr,
+		"p2p_listenaddr",
+		nodeConfig.P2PConfig.ListenAddr,
+		"Network listening address",
+	)
+
+	flags.StringVar(
+		&nodeConfig.P2PConfig.NodeDatabase,
+		"p2p_nodedb",
+		nodeConfig.P2PConfig.NodeDatabase,
+		"The path to the database containing the previously seen live nodes in the network",
+	)
+
+	flags.UintVar(
+		&nodeConfig.P2PConfig.NetworkID,
+		"p2p_id",
+		nodeConfig.P2PConfig.NetworkID,
+		"The ID of the p2p network. Nodes have different ID cannot communicate, even if they have same chainID and block data.",
+	)
+
+	flags.StringVar(
+		&nodeConfig.P2PBootNodes,
+		"p2p_bootnodes",
+		nodeConfig.P2PBootNodes,
+		"Node list file. BootstrapNodes are used to establish connectivity with the rest of the network",
+	)
 	defaultLogConfig().Setup()
 }
 
diff --git a/cmd/ftkey/changepassphrase.go b/cmd/ftkey/changepassphrase.go
deleted file mode 100644
index a4426732..00000000
--- a/cmd/ftkey/changepassphrase.go
+++ /dev/null
@@ -1,90 +0,0 @@
-// Copyright 2018 The Fractal Team Authors
-// This file is part of the fractal project.
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-package main
-
-import (
-	"fmt"
-	"io/ioutil"
-	"strings"
-
-	"github.com/spf13/cobra"
-
-	"github.com/fractalplatform/fractal/wallet/keystore"
-)
-
-var (
-	newPassphraseFlag string
-)
-
-var changePassphraseCmd = &cobra.Command{
-	Use:   "changepassphrase",
-	Short: "change the passphrase on a keyfile",
-	Long: `
-Change the passphrase of a keyfile.`,
-	Args: cobra.ExactArgs(1),
-	Run: func(cmd *cobra.Command, args []string) {
-		keyfilepath := args[0]
-		// Read key from file.
-		keyjson, err := ioutil.ReadFile(keyfilepath)
-		if err != nil {
-			fmt.Println("Failed to read the keyfile at ", keyfilepath, " : ", err)
-			return
-		}
-
-		// Decrypt key with passphrase.
-		passphrase := getPassphrase()
-		key, err := keystore.DecryptKey(keyjson, passphrase)
-		if err != nil {
-			fmt.Println("Error decrypting key: ", err)
-			return
-		}
-
-		// Get a new passphrase.
-		fmt.Println("Please provide a new passphrase")
-		var newPhrase string
-		if newPassphraseFlag != "" {
-			content, err := ioutil.ReadFile(newPassphraseFlag)
-			if err != nil {
-				fmt.Println("Failed to read new passphrase file ", newPassphraseFlag, " : ", err)
-			}
-			newPhrase = strings.TrimRight(string(content), "\r\n")
-		} else {
-			newPhrase = promptPassphrase(true)
-		}
-
-		// Encrypt the key with the new passphrase.
-		newJSON, err := keystore.EncryptKey(key, newPhrase, keystore.StandardScryptN, keystore.StandardScryptP)
-		if err != nil {
-			fmt.Println("Error encrypting with new passphrase: ", err)
-			return
-		}
-
-		// Then write the new keyfile in place of the old one.
-		if err := ioutil.WriteFile(keyfilepath, newJSON, 600); err != nil {
-			fmt.Println("Error writing new keyfile to disk: ", err)
-			return
-		}
-
-		// Don't print anything.  Just return successfully,
-		// producing a positive exit code.
-	},
-}
-
-func init() {
-	changePassphraseCmd.Flags().StringVar(&newPassphraseFlag, "newpasswordfile", "", "the file that contains the new passphrase for the keyfile")
-	RootCmd.AddCommand(changePassphraseCmd)
-}
diff --git a/cmd/ftkey/generate.go b/cmd/ftkey/generate.go
deleted file mode 100644
index 3d02757e..00000000
--- a/cmd/ftkey/generate.go
+++ /dev/null
@@ -1,126 +0,0 @@
-// Copyright 2018 The Fractal Team Authors
-// This file is part of the fractal project.
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-package main
-
-import (
-	"crypto/ecdsa"
-	"fmt"
-	"io/ioutil"
-	"os"
-	"path/filepath"
-
-	"github.com/fractalplatform/fractal/crypto"
-	"github.com/fractalplatform/fractal/wallet/keystore"
-	"github.com/spf13/cobra"
-)
-
-const (
-	defaultKeyfileName = "keyfile.json"
-)
-
-type outputGenerate struct {
-	Address      string
-	AddressEIP55 string
-}
-
-var (
-	privatekeyFlag string
-)
-
-var generateCmd = &cobra.Command{
-	Use:   "generate",
-	Short: "generate new keyfile",
-	Long: `
-	Generate a new keyfile.
-	
-	If you want to encrypt an existing private key, it can be specified by setting
-	--privatekey with the location of the file containing the private key.
-	`,
-	Args: cobra.RangeArgs(0, 1),
-	Run: func(cmd *cobra.Command, args []string) {
-		keyfilepath := defaultKeyfileName
-		if len(args) > 0 && args[0] != "" {
-			keyfilepath = args[0]
-		}
-
-		if _, err := os.Stat(keyfilepath); err == nil {
-			fmt.Println("Keyfile already exists at ", keyfilepath)
-			return
-		} else if !os.IsNotExist(err) {
-			fmt.Println("Error checking if keyfile exists: ", err)
-			return
-		}
-
-		var privateKey *ecdsa.PrivateKey
-		var err error
-		if privatekeyFlag != "" {
-			// Load private key from file.
-			privateKey, err = crypto.LoadECDSA(privatekeyFlag)
-			if err != nil {
-				fmt.Println("Can't load private key: ", err)
-				return
-			}
-		} else {
-			// If not loaded, generate random.
-			privateKey, err = crypto.GenerateKey()
-			if err != nil {
-				fmt.Println("Failed to generate random private key: ", err)
-				return
-			}
-		}
-
-		// Create the keyfile object with a random UUID.
-		key := &keystore.Key{
-			Addr:       crypto.PubkeyToAddress(privateKey.PublicKey),
-			PrivateKey: privateKey,
-		}
-
-		// Encrypt key with passphrase.
-		passphrase := promptPassphrase(true)
-		keyjson, err := keystore.EncryptKey(key, passphrase, keystore.StandardScryptN, keystore.StandardScryptP)
-		if err != nil {
-			fmt.Println("Error encrypting key: ", err)
-			return
-		}
-
-		// Store the file to disk.
-		if err := os.MkdirAll(filepath.Dir(keyfilepath), 0700); err != nil {
-			fmt.Println("Could not create directory ", filepath.Dir(keyfilepath))
-			return
-		}
-		if err := ioutil.WriteFile(keyfilepath, keyjson, 0600); err != nil {
-			fmt.Println("Failed to write keyfile to : ", keyfilepath, " ", err)
-			return
-		}
-
-		// Output some information.
-		out := outputGenerate{
-			Address: key.Addr.Hex(),
-		}
-
-		if jsonFlag {
-			mustPrintJSON(out)
-		} else {
-			fmt.Println("Address:", out.Address)
-		}
-	},
-}
-
-func init() {
-	generateCmd.Flags().StringVar(&privatekeyFlag, "privatekey", "", "file containing a raw private key to encrypt")
-	RootCmd.AddCommand(generateCmd)
-}
diff --git a/cmd/ftkey/inspect.go b/cmd/ftkey/inspect.go
deleted file mode 100644
index 58c8e525..00000000
--- a/cmd/ftkey/inspect.go
+++ /dev/null
@@ -1,91 +0,0 @@
-// Copyright 2018 The Fractal Team Authors
-// This file is part of the fractal project.
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-package main
-
-import (
-	"encoding/hex"
-	"fmt"
-	"io/ioutil"
-
-	"github.com/fractalplatform/fractal/crypto"
-	"github.com/fractalplatform/fractal/wallet/keystore"
-	"github.com/spf13/cobra"
-)
-
-var (
-	privateFlag bool
-)
-
-type outputInspect struct {
-	Address    string
-	PublicKey  string
-	PrivateKey string
-}
-
-var inspectCmd = &cobra.Command{
-	Use:   "inspect",
-	Short: "inspect a keyfile",
-	Long: `
-Print various information about the keyfile.
-
-Private key information can be printed by using the --private flag;
-make sure to use this feature with great caution!`,
-	Args: cobra.ExactArgs(1),
-	Run: func(cmd *cobra.Command, args []string) {
-		keyfilepath := args[0]
-
-		// Read key from file.
-		keyjson, err := ioutil.ReadFile(keyfilepath)
-		if err != nil {
-			fmt.Println("Failed to read the keyfile at ", keyfilepath, " : ", err)
-			return
-		}
-
-		// Decrypt key with passphrase.
-		passphrase := getPassphrase()
-		key, err := keystore.DecryptKey(keyjson, passphrase)
-		if err != nil {
-			fmt.Println("Error decrypting key: ", err)
-			return
-		}
-
-		// Output all relevant information we can retrieve.
-		out := outputInspect{
-			Address: key.Addr.Hex(),
-			PublicKey: hex.EncodeToString(
-				crypto.FromECDSAPub(&key.PrivateKey.PublicKey)),
-		}
-		if privateFlag {
-			out.PrivateKey = hex.EncodeToString(crypto.FromECDSA(key.PrivateKey))
-		}
-
-		if jsonFlag {
-			mustPrintJSON(out)
-		} else {
-			fmt.Println("Address:       ", out.Address)
-			fmt.Println("Public key:    ", out.PublicKey)
-			if privateFlag {
-				fmt.Println("Private key:   ", out.PrivateKey)
-			}
-		}
-	},
-}
-
-func init() {
-	inspectCmd.Flags().BoolVar(&privateFlag, "private", false, "include the private key in the output")
-	RootCmd.AddCommand(inspectCmd)
-}
diff --git a/cmd/ftkey/message.go b/cmd/ftkey/message.go
deleted file mode 100644
index cefb4d36..00000000
--- a/cmd/ftkey/message.go
+++ /dev/null
@@ -1,162 +0,0 @@
-// Copyright 2018 The Fractal Team Authors
-// This file is part of the fractal project.
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-package main
-
-import (
-	"encoding/hex"
-	"fmt"
-	"io/ioutil"
-	"os"
-
-	"github.com/spf13/cobra"
-
-	"github.com/fractalplatform/fractal/common"
-	"github.com/fractalplatform/fractal/crypto"
-	"github.com/fractalplatform/fractal/wallet/keystore"
-)
-
-type outputSign struct {
-	Signature string
-}
-
-var (
-	msgfileFlag string
-)
-
-var signMessageCmd = &cobra.Command{
-	Use:   "signmessage",
-	Short: "sign a message",
-	Long: `
-Sign the message with a keyfile.
-
-To sign a message contained in a file, use the --msgfile flag.
-`,
-	Args: cobra.RangeArgs(1, 2),
-	Run: func(cmd *cobra.Command, args []string) {
-		message := getMessage(args, 1)
-
-		// Load the keyfile.
-		keyfilepath := args[0]
-		keyjson, err := ioutil.ReadFile(keyfilepath)
-		if err != nil {
-			fmt.Println("Failed to read the keyfile at ", keyfilepath, " : ", err)
-			return
-		}
-
-		// Decrypt key with passphrase.
-		passphrase := getPassphrase()
-		key, err := keystore.DecryptKey(keyjson, passphrase)
-		if err != nil {
-			fmt.Println("Error decrypting key: ", err)
-			return
-		}
-
-		signature, err := crypto.Sign(signHash(message), key.PrivateKey)
-		if err != nil {
-			fmt.Println("Failed to sign message: ", err)
-			return
-		}
-		out := outputSign{Signature: hex.EncodeToString(signature)}
-		if jsonFlag {
-			mustPrintJSON(out)
-		} else {
-			fmt.Println("Signature:", out.Signature)
-		}
-	},
-}
-
-type outputVerify struct {
-	Success            bool
-	RecoveredAddress   string
-	RecoveredPublicKey string
-}
-
-var verifyMessageCmd = &cobra.Command{
-	Use:   "verifymessage",
-	Short: "verify the signature of a signed message",
-	Long: `
-Verify the signature of the message.
-It is possible to refer to a file containing the message.`,
-	Args: cobra.RangeArgs(2, 3),
-	Run: func(cmd *cobra.Command, args []string) {
-		addressStr := args[0]
-		signatureHex := args[1]
-		message := getMessage(args, 2)
-
-		if !common.IsHexAddress(addressStr) {
-			fmt.Println("Invalid address: ", addressStr)
-			return
-		}
-		address := common.HexToAddress(addressStr)
-		signature, err := hex.DecodeString(signatureHex)
-		if err != nil {
-			fmt.Println("Signature encoding is not hexadecimal: ", err)
-			return
-		}
-
-		recoveredPubkey, err := crypto.SigToPub(signHash(message), signature)
-		if err != nil || recoveredPubkey == nil {
-			fmt.Println("Signature verification failed: ", err)
-			return
-		}
-		recoveredPubkeyBytes := crypto.FromECDSAPub(recoveredPubkey)
-		recoveredAddress := crypto.PubkeyToAddress(*recoveredPubkey)
-		success := address == recoveredAddress
-
-		out := outputVerify{
-			Success:            success,
-			RecoveredPublicKey: hex.EncodeToString(recoveredPubkeyBytes),
-			RecoveredAddress:   recoveredAddress.Hex(),
-		}
-		if jsonFlag {
-			mustPrintJSON(out)
-		} else {
-			if out.Success {
-				fmt.Println("Signature verification successful!")
-			} else {
-				fmt.Println("Signature verification failed!")
-			}
-			fmt.Println("Recovered public key:", out.RecoveredPublicKey)
-			fmt.Println("Recovered address:", out.RecoveredAddress)
-		}
-	},
-}
-
-func getMessage(args []string, msgarg int) []byte {
-	if msgfileFlag != "" {
-		if len(args) > msgarg {
-			fmt.Println("Can't use --msgfile and message argument at the same time.")
-			os.Exit(1)
-		}
-		msg, err := ioutil.ReadFile(msgfileFlag)
-		if err != nil {
-			fmt.Println("Can't read message file: ", err)
-			os.Exit(1)
-		}
-		return msg
-	} else if len(args) == msgarg+1 {
-		return []byte(args[msgarg])
-	}
-	fmt.Println("Invalid number of arguments: want ", msgarg+1, ", got ", len(args))
-	return nil
-}
-
-func init() {
-	signMessageCmd.Flags().StringVar(&msgfileFlag, "msgfile", "", "file containing the message to sign/verify")
-	RootCmd.AddCommand(signMessageCmd)
-	RootCmd.AddCommand(verifyMessageCmd)
-}
diff --git a/cmd/ftkey/root.go b/cmd/ftkey/root.go
deleted file mode 100644
index e3522493..00000000
--- a/cmd/ftkey/root.go
+++ /dev/null
@@ -1,58 +0,0 @@
-// Copyright 2018 The Fractal Team Authors
-// This file is part of the fractal project.
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-package main
-
-import (
-	"fmt"
-	"os"
-
-	"github.com/fractalplatform/fractal/cmd/utils"
-	"github.com/spf13/cobra"
-)
-
-var (
-	passphraseFlag string
-	jsonFlag       bool
-)
-
-// RootCmd represents the base command when called without any subcommands
-var RootCmd = &cobra.Command{
-	Use:   "fkey",
-	Short: "fkey is a fractal key manager",
-	Long:  `fkey is a fractal key manager`,
-
-	// Uncomment the following line if your bare application
-	// has an action associated with it:
-	Run: func(cmd *cobra.Command, args []string) {
-		cmd.HelpFunc()(cmd, args)
-	},
-}
-
-func init() {
-	RootCmd.AddCommand(utils.VersionCmd)
-	RootCmd.PersistentFlags().StringVar(&passphraseFlag, "passwordfile", "", "the file that contains the passphrase for the keyfile")
-	RootCmd.PersistentFlags().BoolVar(&jsonFlag, "json", false, "output JSON instead of human-readable format")
-}
-
-// Execute adds all child commands to the root command sets flags appropriately.
-// This is called by main.main(). It only needs to happen once to the rootCmd.
-func Execute() {
-	if err := RootCmd.Execute(); err != nil {
-		fmt.Fprintln(os.Stderr, err)
-		os.Exit(-1)
-	}
-}
diff --git a/cmd/ftkey/utils.go b/cmd/ftkey/utils.go
deleted file mode 100644
index 14e2ad19..00000000
--- a/cmd/ftkey/utils.go
+++ /dev/null
@@ -1,89 +0,0 @@
-// Copyright 2018 The Fractal Team Authors
-// This file is part of the fractal project.
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-package main
-
-import (
-	"encoding/json"
-	"fmt"
-	"io/ioutil"
-	"strings"
-
-	"github.com/ethereum/go-ethereum/log"
-	"github.com/fractalplatform/fractal/crypto"
-	"github.com/fractalplatform/fractal/utils/console"
-)
-
-// promptPassphrase prompts the user for a passphrase.  Set confirmation to true
-// to require the user to confirm the passphrase.
-func promptPassphrase(confirmation bool) string {
-	passphrase, err := console.Stdin.PromptPassword("Passphrase: ")
-	if err != nil {
-		log.Crit("Failed to read passphrase: %v", err)
-	}
-
-	if confirmation {
-		confirm, err := console.Stdin.PromptPassword("Repeat passphrase: ")
-		if err != nil {
-			log.Crit("Failed to read passphrase confirmation: %v", err)
-		}
-		if passphrase != confirm {
-			log.Crit("Passphrases do not match")
-		}
-	}
-
-	return passphrase
-}
-
-// getPassphrase obtains a passphrase given by the user.  It first checks the
-// --passfile command line flag and ultimately prompts the user for a
-// passphrase.
-func getPassphrase() string {
-	// Look for the --passwordfile flag.
-	if passphraseFlag != "" {
-		content, err := ioutil.ReadFile(passphraseFlag)
-		if err != nil {
-			log.Crit("Failed to read passphrase file '%s': %v",
-				passphraseFlag, err)
-		}
-		return strings.TrimRight(string(content), "\r\n")
-	}
-
-	// Otherwise prompt the user for the passphrase.
-	return promptPassphrase(false)
-}
-
-// signHash is a helper function that calculates a hash for the given message
-// that can be safely used to calculate a signature from.
-//
-// The hash is calulcated as
-//   keccak256("\x19Ethereum Signed Message:\n"${message length}${message}).
-//
-// This gives context to the signed message and prevents signing of transactions.
-func signHash(data []byte) []byte {
-	msg := fmt.Sprintf("\x19Ethereum Signed Message:\n%d%s", len(data), data)
-	return crypto.Keccak256([]byte(msg))
-}
-
-// mustPrintJSON prints the JSON encoding of the given object and
-// exits the program with an error message when the marshaling fails.
-func mustPrintJSON(jsonObject interface{}) {
-	str, err := json.MarshalIndent(jsonObject, "", "  ")
-	if err != nil {
-		log.Crit("Failed to marshal JSON object: %v", err)
-	}
-	fmt.Println(string(str))
-}
diff --git a/cmd/utils/logconfig.go b/cmd/utils/logconfig.go
new file mode 100644
index 00000000..65815230
--- /dev/null
+++ b/cmd/utils/logconfig.go
@@ -0,0 +1,63 @@
+// Copyright 2018 The Fractal Team Authors
+// This file is part of the fractal project.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+package utils
+
+import (
+	"io"
+	"os"
+
+	"github.com/ethereum/go-ethereum/log"
+	colorable "github.com/mattn/go-colorable"
+	"github.com/mattn/go-isatty"
+)
+
+var glogger *log.GlogHandler
+
+// LogConfig represents a log config
+type LogConfig struct {
+	PrintOrigins bool   `mapstructure:"printorigins"`
+	Level        int    `mapstructure:"level"`
+	Vmodule      string `mapstructure:"vmodule"`
+	BacktraceAt  string `mapstructure:"backtraceat"`
+}
+
+// DefaultLogConfig returns a default config
+func DefaultLogConfig() *LogConfig {
+	return &LogConfig{
+		PrintOrigins: false,
+		Level:        3,
+	}
+}
+
+func init() {
+	usecolor := (isatty.IsTerminal(os.Stderr.Fd()) || isatty.IsCygwinTerminal(os.Stderr.Fd())) && os.Getenv("TERM") != "dumb"
+	output := io.Writer(os.Stderr)
+	if usecolor {
+		output = colorable.NewColorableStderr()
+	}
+	glogger = log.NewGlogHandler(log.StreamHandler(output, log.TerminalFormat(usecolor)))
+}
+
+//Setup initializes logging based on the LogConfig
+func (lc *LogConfig) Setup() {
+	// logging
+	log.PrintOrigins(lc.PrintOrigins)
+	glogger.Verbosity(log.Lvl(lc.Level))
+	glogger.Vmodule(lc.Vmodule)
+	glogger.BacktraceAt(lc.BacktraceAt)
+	log.Root().SetHandler(glogger)
+}
diff --git a/common/address.go b/common/address.go
index ce24620d..0f970b3f 100644
--- a/common/address.go
+++ b/common/address.go
@@ -17,6 +17,7 @@
 package common
 
 import (
+	"bytes"
 	"encoding/hex"
 	"encoding/json"
 	"fmt"
@@ -117,6 +118,10 @@ func (a Address) MarshalText() ([]byte, error) {
 	return hexutil.Bytes(a[:]).MarshalText()
 }
 
+func (a Address) Compare(x Address) int {
+	return bytes.Compare(a.Bytes(), x.Bytes())
+}
+
 // UnmarshalText parses a hash in hex syntax.
 func (a *Address) UnmarshalText(input []byte) error {
 	return hexutil.UnmarshalFixedText("Address", input, a[:])
diff --git a/common/author.go b/common/author.go
new file mode 100644
index 00000000..b8439db0
--- /dev/null
+++ b/common/author.go
@@ -0,0 +1,126 @@
+package common
+
+import (
+	"errors"
+	"io"
+
+	"github.com/fractalplatform/fractal/utils/rlp"
+)
+
+type AuthorType uint8
+
+const (
+	AccountNameType AuthorType = iota
+	PubKeyType
+	AddressType
+)
+
+type (
+	Author struct {
+		Owner
+		Weight uint64 `json:"weight"`
+	}
+	Owner interface {
+		String() string
+	}
+)
+
+type AccountAuthor struct {
+	Account Name
+}
+type StorageAuthor struct {
+	Type    AuthorType
+	DataRaw rlp.RawValue
+	Weight  uint64
+}
+
+func NewAuthor(owner Owner, weight uint64) *Author {
+	return &Author{Owner: owner, Weight: weight}
+}
+
+func (a *Author) GetWeight() uint64 {
+	return a.Weight
+}
+
+func (a *Author) EncodeRLP(w io.Writer) error {
+	storageAuthor, err := a.encode()
+	if err != nil {
+		return err
+	}
+	return rlp.Encode(w, storageAuthor)
+}
+
+func (a *Author) encode() (*StorageAuthor, error) {
+	switch aTy := a.Owner.(type) {
+	case Name:
+		value, err := rlp.EncodeToBytes(&aTy)
+		if err != nil {
+			return nil, err
+		}
+		return &StorageAuthor{
+			Type:    AccountNameType,
+			DataRaw: value,
+			Weight:  a.Weight,
+		}, nil
+	case PubKey:
+		value, err := rlp.EncodeToBytes(&aTy)
+		if err != nil {
+			return nil, err
+		}
+		return &StorageAuthor{
+			Type:    PubKeyType,
+			DataRaw: value,
+			Weight:  a.Weight,
+		}, nil
+	case Address:
+		value, err := rlp.EncodeToBytes(&aTy)
+		if err != nil {
+			return nil, err
+		}
+		return &StorageAuthor{
+			Type:    AddressType,
+			DataRaw: value,
+			Weight:  a.Weight,
+		}, nil
+	}
+	return nil, errors.New("Author encode failed")
+}
+
+func (a *Author) DecodeRLP(s *rlp.Stream) error {
+	storageAuthor := new(StorageAuthor)
+	err := s.Decode(storageAuthor)
+	if err != nil {
+		return err
+	}
+	return a.decode(storageAuthor)
+}
+
+func (a *Author) decode(sa *StorageAuthor) error {
+	switch sa.Type {
+	case AccountNameType:
+		var name Name
+		if err := rlp.DecodeBytes(sa.DataRaw, &name); err != nil {
+			return err
+		}
+		a.Owner = name
+		a.Weight = sa.Weight
+		return nil
+	case PubKeyType:
+		var pubKey PubKey
+		if err := rlp.DecodeBytes(sa.DataRaw, &pubKey); err != nil {
+			return err
+		}
+		a.Owner = pubKey
+		a.Weight = sa.Weight
+		return nil
+	case AddressType:
+		var address Address
+		if err := rlp.DecodeBytes(sa.DataRaw, &address); err != nil {
+			return err
+		}
+		a.Owner = address
+		a.Weight = sa.Weight
+		return nil
+	}
+	return errors.New("Author decode failed")
+}
diff --git a/common/name.go b/common/name.go
index 761a918a..52996078 100644
--- a/common/name.go
+++ b/common/name.go
@@ -23,15 +23,65 @@ import (
 	"regexp"
 	"strings"
 
+	"github.com/ethereum/go-ethereum/log"
 	"github.com/fractalplatform/fractal/utils/rlp"
 )
 
 // Name represents the account name
 type Name string
 
-// IsValidName verifies whether a string can represent a valid name or not.
-func IsValidName(s string) bool {
-	return regexp.MustCompile("^[a-z0-9]{8,16}$").MatchString(s)
+var accountNameCheck *regexp.Regexp
+var assetNameCheck *regexp.Regexp
+
+var (
+	AccountNameLevel  uint64 = 1
+	AccountNameLen    uint64 = 16
+	SubAccountNameLen uint64 = 8
+	AssetNameLevel    uint64 = 1
+	AssetNameLen      uint64 = 16
+	SubAssetNameLen   uint64 = 8
+)
+
+func init() {
+	SetAccountNameCheckRule(AccountNameLevel, AccountNameLen, SubAccountNameLen)
+	SetAssetNameCheckRule(AssetNameLevel, AssetNameLen, SubAssetNameLen)
+}
+
+func SetAccountNameCheckRule(nameLevel, nameLen, subNameLen uint64) {
+	var nameCheck string
+	if nameLevel == 0 {
+		nameCheck = fmt.Sprintf("^[a-z0-9]{7,%d}$", nameLen)
+	} else {
+		nameCheck = fmt.Sprintf("^[a-z0-9]{7,%d}(\\.[a-z0-9]{1,%d}){0,%d}$", nameLen, subNameLen, nameLevel)
+	}
+	log.Info("Account name level", "level", nameLevel, "name length", nameLen, "sub name length", subNameLen)
+	accountNameCheck = regexp.MustCompile(nameCheck)
+}
+
+func SetAssetNameCheckRule(nameLevel, nameLen, subNameLen uint64) {
+	var nameCheck string
+	if nameLevel == 0 {
+		nameCheck = fmt.Sprintf("^[a-z0-9]{2,%d}$", nameLen)
+	} else {
+		nameCheck = fmt.Sprintf("^[a-z0-9]{2,%d}(\\.[a-z0-9]{1,%d}){0,%d}$", nameLen, subNameLen, nameLevel)
+	}
+	log.Info("Asset name level", "level", nameLevel, "name length", nameLen, "sub name length", subNameLen)
+	assetNameCheck = regexp.MustCompile(nameCheck)
+}
+
+// IsValidAccountName verifies whether a string can represent a valid name or not.
+func IsValidAccountName(s string) bool {
+	if accountNameCheck == nil {
+		return false
+	}
+	return accountNameCheck.MatchString(s)
+}
+
+func IsValidAssetName(s string) bool {
+	if assetNameCheck == nil {
+		return false
+	}
+	return assetNameCheck.MatchString(s)
 }
 
 // StrToName  returns Name with string of s.
@@ -43,6 +93,15 @@ func StrToName(s string) Name {
 	return n
 }
 
+// StrToName  returns Name with string of s.
+func StringToName(s string) (Name, error) {
+	var n Name
+	if !n.SetString(s) {
+		return n, fmt.Errorf("invalid name %v", s)
+	}
+	return n, nil
+}
+
 func parseName(s string) (Name, error) {
 	var n Name
 	if !n.SetString(s) {
@@ -61,7 +120,7 @@ func BigToName(b *big.Int) (Name, error) { return BytesToName(b.Bytes()) }
 
 // SetString  sets the name to the value of b..
 func (n *Name) SetString(s string) bool {
-	if !IsValidName(s) {
+	if !IsValidAccountName(s) {
 		return false
 	}
 	*n = Name(s)
@@ -90,7 +149,7 @@ func (n *Name) UnmarshalJSON(data []byte) error {
 }
 
 // EncodeRLP implements rlp.Encoder
-func (n *Name) EncodeRLP(w io.Writer) error {
+func (n Name) EncodeRLP(w io.Writer) error {
 	str := n.String()
 	if len(str) != 0 {
 		if _, err := parseName(str); err != nil {
@@ -124,3 +183,37 @@ func (n Name) String() string {
 
 // Big converts a name to a big integer.
 func (n Name) Big() *big.Int { return new(big.Int).SetBytes([]byte(n.String())) }
+
+func (n Name) IsValidCreator(name string) bool {
+
+	creator := n.String()
+	current := name
+	trimName := strings.TrimPrefix(current, creator)
+
+	if strings.Index(trimName, ".") != 0 {
+		return false
+	}
+
+	return true
+}
+
+func (n Name) AccountNameLevel() int {
+	return len(strings.Split(n.String(), "."))
+}
+
+func SplitString(s string) []string {
+	return strings.Split(s, ".")
+}
+
+func IsValidCreator(name string, subName string) bool {
+
+	creator := name
+	current := subName
+	trimName := strings.TrimPrefix(current, creator)
+
+	if strings.Index(trimName, ".") != 0 {
+		return false
+	}
+
+	return true
+}
diff --git a/common/name_test.go b/common/name_test.go
index 0d38dd30..9321e517 100644
--- a/common/name_test.go
+++ b/common/name_test.go
@@ -42,8 +42,8 @@ func TestValidateName(t *testing.T) {
 	}
 
 	for _, test := range tests {
-		if result := IsValidName(test.str); result != test.exp {
-			t.Errorf("IsValidName(%s) == %v; expected %v, len:%v",
+		if result := IsValidAccountName(test.str); result != test.exp {
+			t.Errorf("IsValidAccountName(%s) == %v; expected %v, len:%v",
 				test.str, result, test.exp, len(test.str))
 		}
 	}
@@ -65,6 +65,7 @@ func TestNameUnmarshalJSON(t *testing.T) {
 		{"short", true},
 		{"longnamelongnamelongnamelongname", true},
 	}
+
 	for i, test := range tests {
 
 		bytes, err := json.Marshal(test.Input)
diff --git a/common/pubkey_test.go b/common/pubkey_test.go
index 905dc196..12402bec 100644
--- a/common/pubkey_test.go
+++ b/common/pubkey_test.go
@@ -18,7 +18,6 @@ package common
 
 import (
 	"encoding/json"
-	"fmt"
 	"math/big"
 	"testing"
 )
@@ -48,9 +47,6 @@ func TestIsHexPubkey(t *testing.T) {
 	p1 := HexToPubKey("0x0462ad0e026eb91232feec4f333108b7f658ea34bc2715e0f4d575930398853942c9a09e638d19f9a18d47085e7b8ae59e257bd97e85acf9107947b5acbd8f969e")
 
 	p.SetBytes(p1.Bytes())
-
-	fmt.Println("====>", p.String())
-
 }
 
 func TestPubKeyUnmarshalJSON(t *testing.T) {
diff --git a/consensus/consensus.go b/consensus/consensus.go
index 7c8c3f05..6b44fb23 100644
--- a/consensus/consensus.go
+++ b/consensus/consensus.go
@@ -56,7 +56,7 @@ type IChainReader interface {
 	StateAt(hash common.Hash) (*state.StateDB, error)
 
 	// WriteBlockWithState writes the block and all associated state to the database.
-	WriteBlockWithState(block *types.Block, receipts []*types.Receipt, state *state.StateDB) error
+	WriteBlockWithState(block *types.Block, receipts []*types.Receipt, state *state.StateDB) (bool, error)
 
 	// CalcGasLimit computes the gas limit of the next block after parent.
 	CalcGasLimit(parent *types.Block) uint64
@@ -98,7 +98,9 @@ type IEngine interface {
 
 	Engine() IEngine
 
-	ProcessAction(chainCfg *params.ChainConfig, state *state.StateDB, action *types.Action) error
+	ProcessAction(chainCfg *params.ChainConfig, state *state.StateDB, action *types.Action) ([]*types.InternalAction, error)
+
+	GetDelegatedByTime(name string, timestamp uint64, state *state.StateDB) (*big.Int, *big.Int, uint64, error)
 
 	IAPI
 }
diff --git a/consensus/dpos/README.md b/consensus/dpos/README.md
deleted file mode 100644
index 161aad7d..00000000
--- a/consensus/dpos/README.md
+++ /dev/null
@@ -1,55 +0,0 @@
-## dpos生成者注册及投票者投票
-
-### 参数说明
-- `UnitStake`  一票所代表的权益
-- `MaxURLLen`  生产者URL最大长度
-- `ProducerMinQuantity` 生成者需要抵押的最低票数
-- `VoterMinQuantity`   投票者需要抵押的最低票数
-- `ActivatedMinQuantity` dpos启动需要的最低票数
-- `BlockInterval`  每轮生产者出块间隔
-- `BlockFrequency` 每轮生产者连续出块个数
-- `ProducerScheduleSize`: 每轮生成者最大个数
-
-### dpos启动
-- 网络投票总数 >= `ActivatedMinQuantity`  && 已注册的生成者个数 >= `ProducerScheduleSize` * 2 / 3 + 1 
-- 启动后, 启动条件必须一直满足
-
-### 注册生产者/更新生产者 
-> RegProducer(producer string, address string, url string, stake *big.Int) error
-- 账户名必须存在
-- 账户名与提供的公钥匹配
-- 提供的URL长度 <= `MaxURLLen`
-- 抵押stake 需满足`UnitStake`的整数倍, 且商 >= `ProducerMinQuantity`
-- 未投票
-
-### 注销生成者
-> UnregProducer(producer string) error
-- 有效生产者
-- 注销后,已注册生产者个数 >= `ProducerScheduleSize` * 2 / 3 + 1
-- 注销后,网络投票总数 >= `ActivatedMinQuantity`
-- 未存在投票者投票
-
-### 投票者投票
-> VoteProducer(voter string, producer string, stake *big.Int) error
-- 账户名必须存在
-- 抵押stake 需满足`UnitStake`的整数倍, 且商 >= `VoterMinQuantity`
-- 未注册生产者
-- 未投票
-- 有效的生产者
-
-### 投票者改票
-> ChangeProducer(voter string, producer string) error
-- 已投票
-- 不是相同的生产者
-- 有效的生产者
-
-### 投票者取消投票
-> UnvoteProducer(voter string) error
-- 已投票
-- 取消后,网络投票总数 >= `ActivatedMinQuantity`
-
-### 生产者取消投票者的投票
-> UnvoteVoter(producer string, voter string) error
-- 投票者已投票
-- 投票的生产者确实是该生产者
-- 取消后,网络投票总数 >= `ActivatedMinQuantity`
diff --git a/consensus/dpos/api.go b/consensus/dpos/api.go
index 62c683ae..49e4bf68 100644
--- a/consensus/dpos/api.go
+++ b/consensus/dpos/api.go
@@ -32,9 +32,9 @@ type API struct {
 }
 
 type Irreversible_Ret struct {
-	ProposedIrreversible uint64
-	LastIrreversible     uint64
-	BftIrreversible      uint64
+	ProposedIrreversible uint64 `json:"proposedIrreversible"`
+	BftIrreversible      uint64 `json:"bftIrreversible"`
+	Reversible           uint64 `json:"reversible"`
 }
 
 func (api *API) Info() (interface{}, error) {
@@ -43,10 +43,9 @@ func (api *API) Info() (interface{}, error) {
 
 func (api *API) Irreversible() (interface{}, error) {
 	ret := &Irreversible_Ret{}
-
-	ret.ProposedIrreversible = api.dpos.proposedIrreversibleNum
-	ret.LastIrreversible = api.dpos.calcLastIrreversible()
-	ret.BftIrreversible = api.dpos.bftIrreversibleNum
+	ret.Reversible = api.chain.CurrentHeader().Number.Uint64()
+	ret.ProposedIrreversible = api.dpos.CalcProposedIrreversible(api.chain, nil, false)
+	ret.BftIrreversible = api.dpos.CalcBFTIrreversible()
 
 	return ret, nil
 }
@@ -63,7 +62,7 @@ func (api *API) Account(name string) (interface{}, error) {
 		return vote, err
 	}
 
-	if prod, err := sys.GetProducer(name); err != nil {
+	if prod, err := sys.GetCadidate(name); err != nil {
 		return nil, err
 	} else if prod != nil {
 		return prod, err
@@ -72,20 +71,20 @@ func (api *API) Account(name string) (interface{}, error) {
 	return nil, nil
 }
 
-func (api *API) Producers() ([]map[string]interface{}, error) {
+func (api *API) Cadidates() ([]map[string]interface{}, error) {
 	pfileds := []map[string]interface{}{}
 
 	sys, err := api.system()
 	if err != nil {
 		return nil, err
 	}
-	producers, err := sys.Producers()
-	if err != nil || len(producers) == 0 {
+	cadidates, err := sys.Cadidates()
+	if err != nil || len(cadidates) == 0 {
 		return pfileds, err
 	}
 
-	prods := producerInfoArray{}
-	for _, prod := range producers {
+	prods := cadidateInfoArray{}
+	for _, prod := range cadidates {
 		prods = append(prods, prod)
 	}
 	sort.Sort(prods)
@@ -123,22 +122,15 @@ func (api *API) LatestEpcho() (interface{}, error) {
 }
 
 func (api *API) ValidateEpcho() (interface{}, error) {
-
-	cur_header := api.chain.CurrentHeader()
-	height := cur_header.Number.Uint64() - 1
-
-	target_ts := big.NewInt(cur_header.Time.Int64() - int64(api.dpos.config.DelayEcho*api.dpos.config.epochInterval()))
-
-	for height > 0 {
-		pheader := api.chain.GetHeaderByNumber(height)
-		if pheader.Time.Cmp(target_ts) != 1 {
+	curHeader := api.chain.CurrentHeader()
+	targetTS := big.NewInt(curHeader.Time.Int64() - int64(api.dpos.config.DelayEcho*api.dpos.config.epochInterval()))
+	for curHeader.Number.Uint64() > 0 {
+		if curHeader.Time.Cmp(targetTS) == -1 {
 			break
-		} else {
-			height -= 1
 		}
+		curHeader = api.chain.GetHeaderByHash(curHeader.ParentHash)
 	}
-
-	return api.Epcho(height)
+	return api.Epcho(curHeader.Number.Uint64() + 1)
 }
 
 func (api *API) system() (*System, error) {
diff --git a/consensus/dpos/config.go b/consensus/dpos/config.go
index aca8a4f5..53a6f5b5 100644
--- a/consensus/dpos/config.go
+++ b/consensus/dpos/config.go
@@ -30,12 +30,12 @@ import (
 var DefaultConfig = &Config{
 	MaxURLLen:            512,
 	UnitStake:            big.NewInt(1000),
-	ProducerMinQuantity:  big.NewInt(10),
+	CadidateMinQuantity:  big.NewInt(10),
 	VoterMinQuantity:     big.NewInt(1),
 	ActivatedMinQuantity: big.NewInt(100),
 	BlockInterval:        3000,
 	BlockFrequency:       6,
-	ProducerScheduleSize: 3,
+	CadidateScheduleSize: 3,
 	DelayEcho:            2,
 	AccountName:          "ftsystemdpos",
 	SystemName:           "ftsystemio",
@@ -48,21 +48,21 @@ var DefaultConfig = &Config{
 // Config dpos configures
 type Config struct {
 	// consensus fileds
-	MaxURLLen            uint64   // url length
-	UnitStake            *big.Int // state unit
-	ProducerMinQuantity  *big.Int // min quantity
-	VoterMinQuantity     *big.Int // min quantity
-	ActivatedMinQuantity *big.Int // min active quantity
-	BlockInterval        uint64
-	BlockFrequency       uint64
-	ProducerScheduleSize uint64
-	DelayEcho            uint64
-	AccountName          string
-	SystemName           string
-	SystemURL            string
-	ExtraBlockReward     *big.Int
-	BlockReward          *big.Int
-	Decimals             uint64
+	MaxURLLen            uint64   `json:"maxURLLen"`            // url length
+	UnitStake            *big.Int `json:"unitStake"`            // state unit
+	CadidateMinQuantity  *big.Int `json:"cadidateMinQuantity"`  // min quantity
+	VoterMinQuantity     *big.Int `json:"voterMinQuantity"`     // min quantity
+	ActivatedMinQuantity *big.Int `json:"activatedMinQuantity"` // min active quantity
+	BlockInterval        uint64   `json:"blockInterval"`
+	BlockFrequency       uint64   `json:"blockFrequency"`
+	CadidateScheduleSize uint64   `json:"cadidateScheduleSize"`
+	DelayEcho            uint64   `json:"delayEcho"`
+	AccountName          string   `json:"accountName"`
+	SystemName           string   `json:"systemName"`
+	SystemURL            string   `json:"systemURL"`
+	ExtraBlockReward     *big.Int `json:"extraBlockReward"`
+	BlockReward          *big.Int `json:"blockReward"`
+	Decimals             uint64   `json:"decimals"`
 
 	// cache files
 	decimal    atomic.Value
@@ -116,7 +116,7 @@ func (cfg *Config) epochInterval() uint64 {
 	if epochInter := cfg.epochInter.Load(); epochInter != nil {
 		return epochInter.(uint64)
 	}
-	epochInter := cfg.blockInterval() * cfg.BlockFrequency * cfg.ProducerScheduleSize
+	epochInter := cfg.blockInterval() * cfg.BlockFrequency * cfg.CadidateScheduleSize
 	cfg.epochInter.Store(epochInter)
 	return epochInter
 }
@@ -126,7 +126,7 @@ func (cfg *Config) consensusSize() uint64 {
 		return safeSize.(uint64)
 	}
 
-	safeSize := cfg.ProducerScheduleSize*2/3 + 1
+	safeSize := cfg.CadidateScheduleSize*2/3 + 1
 	cfg.safeSize.Store(safeSize)
 	return safeSize
 }
diff --git a/consensus/dpos/config_test.go b/consensus/dpos/config_test.go
index 55db5ddb..19f36263 100644
--- a/consensus/dpos/config_test.go
+++ b/consensus/dpos/config_test.go
@@ -51,7 +51,7 @@ func TestRLP(t *testing.T) {
 
 	DefaultConfig.BlockInterval = 500
 	DefaultConfig.blockInter.Store(DefaultConfig.BlockInterval * uint64(time.Millisecond))
-	DefaultConfig.epochInter.Store(DefaultConfig.blockInterval() * DefaultConfig.BlockFrequency * DefaultConfig.ProducerScheduleSize)
+	DefaultConfig.epochInter.Store(DefaultConfig.blockInterval() * DefaultConfig.BlockFrequency * DefaultConfig.CadidateScheduleSize)
 	now = uint64(time.Now().UnixNano())
 	slot = DefaultConfig.slot(now)
 	nslot = DefaultConfig.nextslot(now)
diff --git a/consensus/dpos/database.go b/consensus/dpos/database.go
index becd8ed2..f51e821a 100644
--- a/consensus/dpos/database.go
+++ b/consensus/dpos/database.go
@@ -29,11 +29,11 @@ var (
 
 // IDB dpos database
 type IDB interface {
-	SetProducer(*producerInfo) error
-	DelProducer(string) error
-	GetProducer(string) (*producerInfo, error)
-	Producers() ([]*producerInfo, error)
-	ProducersSize() (uint64, error)
+	SetCadidate(*cadidateInfo) error
+	DelCadidate(string) error
+	GetCadidate(string) (*cadidateInfo, error)
+	Cadidates() ([]*cadidateInfo, error)
+	CadidatesSize() (uint64, error)
 
 	SetVoter(*voterInfo) error
 	DelVoter(string, string) error
@@ -47,37 +47,42 @@ type IDB interface {
 	Delegate(string, *big.Int) error
 	Undelegate(string, *big.Int) error
 	IncAsset2Acct(string, string, *big.Int) error
+
+	GetDelegatedByTime(string, uint64) (*big.Int, *big.Int, uint64, error)
 }
 
-type producerInfo struct {
-	Name          string   // producer name
-	URL           string   // producer url
-	Quantity      *big.Int // producer stake quantity
-	TotalQuantity *big.Int // producer total stake quantity
-	Height        uint64   // timestamp
+type cadidateInfo struct {
+	Name          string   `json:"name"`          // cadidate name
+	URL           string   `json:"url"`           // cadidate url
+	Quantity      *big.Int `json:"quantity"`      // cadidate stake quantity
+	TotalQuantity *big.Int `json:"totalQuantity"` // cadidate total stake quantity
+	Height        uint64   `json:"height"`        // timestamp
+	Counter       uint64   `json:"counter"`
+	InBlackList   bool     `json:"inBlackList"`
 }
 
 type voterInfo struct {
-	Name     string   // voter name
-	Producer string   // producer approved by this voter
-	Quantity *big.Int // stake approved by this voter
-	Height   uint64   // timestamp
+	Name     string   `json:"name"`     // voter name
+	Cadidate string   `json:"cadidate"` // cadidate approved by this voter
+	Quantity *big.Int `json:"quantity"` // stake approved by this voter
+	Height   uint64   `json:"height"`   // timestamp
 }
 
 type globalState struct {
-	Height                          uint64   // block height
-	ActivatedProducerScheduleUpdate uint64   // update time
-	ActivatedProducerSchedule       []string // producers
-	ActivatedTotalQuantity          *big.Int // the sum of activate producer votes
-	TotalQuantity                   *big.Int // the sum of all producer votes
+	Height                          uint64   `json:"height"`                          // block height
+	ActivatedCadidateScheduleUpdate uint64   `json:"activatedCadidateScheduleUpdate"` // update time
+	ActivatedCadidateSchedule       []string `json:"activatedCadidateSchedule"`       // cadidates
+	ActivatedTotalQuantity          *big.Int `json:"activatedTotalQuantity"`          // the sum of activate cadidate votes
+	TotalQuantity                   *big.Int `json:"totalQuantity"`                   // the sum of all cadidate votes
+	TakeOver                        bool     `json:"takeOver"`                        // systemio take over dpos
 }
 
-type producerInfoArray []*producerInfo
+type cadidateInfoArray []*cadidateInfo
 
-func (prods producerInfoArray) Len() int {
+func (prods cadidateInfoArray) Len() int {
 	return len(prods)
 }
-func (prods producerInfoArray) Less(i, j int) bool {
+func (prods cadidateInfoArray) Less(i, j int) bool {
 	val := prods[i].TotalQuantity.Cmp(prods[j].TotalQuantity)
 	if val == 0 {
 		if prods[i].Height == prods[j].Height {
@@ -87,6 +92,6 @@ func (prods producerInfoArray) Less(i, j int) bool {
 	}
 	return val > 0
 }
-func (prods producerInfoArray) Swap(i, j int) {
+func (prods cadidateInfoArray) Swap(i, j int) {
 	prods[i], prods[j] = prods[j], prods[i]
 }
diff --git a/consensus/dpos/database_test.go b/consensus/dpos/database_test.go
index 9865408c..21fedc89 100644
--- a/consensus/dpos/database_test.go
+++ b/consensus/dpos/database_test.go
@@ -31,8 +31,8 @@ func TestDatabase(t *testing.T) {
 	// gstate
 	gstate := &globalState{
 		Height:                          10,
-		ActivatedProducerScheduleUpdate: uint64(time.Now().UnixNano()),
-		ActivatedProducerSchedule:       []string{},
+		ActivatedCadidateScheduleUpdate: uint64(time.Now().UnixNano()),
+		ActivatedCadidateSchedule:       []string{},
 		ActivatedTotalQuantity:          big.NewInt(1000),
 		TotalQuantity:                   big.NewInt(100000),
 	}
@@ -51,7 +51,7 @@ func TestDatabase(t *testing.T) {
 	// voter
 	vote := &voterInfo{
 		Name:     "fos",
-		Producer: "fos",
+		Cadidate: "fos",
 		Quantity: big.NewInt(1000),
 	}
 
@@ -68,8 +68,8 @@ func TestDatabase(t *testing.T) {
 	vjson, _ := json.Marshal(nvote)
 	t.Log("voter     ", string(vjson))
 
-	// producer
-	prod := &producerInfo{
+	// cadidate
+	prod := &cadidateInfo{
 		Name:          "fos",
 		URL:           "www.fractalproject.com",
 		Quantity:      big.NewInt(1000),
@@ -81,7 +81,7 @@ func TestDatabase(t *testing.T) {
 		panic(fmt.Sprintf("prod EncodeToBytes--%v", err))
 	}
 
-	nprod := &producerInfo{}
+	nprod := &cadidateInfo{}
 	if err := rlp.DecodeBytes(pval, nprod); err != nil {
 		panic(fmt.Sprintf("prod DecodeBytes--%v", err))
 	}
@@ -89,21 +89,21 @@ func TestDatabase(t *testing.T) {
 	pjson, _ := json.Marshal(nprod)
 	t.Log("prod     ", string(pjson))
 
-	prod1 := &producerInfo{
+	prod1 := &cadidateInfo{
 		Name:          "fos1",
 		URL:           "www.fractalproject.com",
 		Quantity:      big.NewInt(1000),
 		TotalQuantity: big.NewInt(2000),
 	}
 
-	prod2 := &producerInfo{
+	prod2 := &cadidateInfo{
 		Name:          "fos2",
 		URL:           "www.fractalproject.com",
 		Quantity:      big.NewInt(1000),
 		TotalQuantity: big.NewInt(1000),
 	}
 
-	prods := producerInfoArray{}
+	prods := cadidateInfoArray{}
 	prods = append(prods, prod)
 	prods = append(prods, prod1)
 	prods = append(prods, prod2)
diff --git a/consensus/dpos/dpos.go b/consensus/dpos/dpos.go
index d34c4a0f..20f8dff1 100644
--- a/consensus/dpos/dpos.go
+++ b/consensus/dpos/dpos.go
@@ -30,18 +30,19 @@ import (
 	"github.com/fractalplatform/fractal/crypto"
 	"github.com/fractalplatform/fractal/state"
 	"github.com/fractalplatform/fractal/types"
-	"github.com/fractalplatform/fractal/utils/rlp"
-	"golang.org/x/crypto/sha3"
+	lru "github.com/hashicorp/golang-lru"
 )
 
 var (
 	errMissingSignature           = errors.New("extra-data 65 byte suffix signature missing")
-	errMismatchSignerAndValidator = errors.New("mismatch block signer and producer")
+	errMismatchSignerAndValidator = errors.New("mismatch block signer and cadidate")
 	errInvalidMintBlockTime       = errors.New("invalid time to mint the block")
-	errInvalidBlockProducer       = errors.New("invalid block producer")
+	errInvalidBlockCadidate       = errors.New("invalid block cadidate")
 	errInvalidTimestamp           = errors.New("invalid timestamp")
-	ErrIllegalProducerName        = errors.New("illegal producer name")
-	ErrIllegalProducerPubKey      = errors.New("illegal producer pubkey")
+	ErrIllegalCadidateName        = errors.New("illegal cadidate name")
+	ErrIllegalCadidatePubKey      = errors.New("illegal cadidate pubkey")
+	ErrTooMuchRreversible         = errors.New("too much rreversible blocks")
+	ErrSystemTakeOver             = errors.New("system account take over")
 	errUnknownBlock               = errors.New("unknown block")
 	extraSeal                     = 65
 	timeOfGenesisBlock            int64
@@ -53,6 +54,10 @@ type stateDB struct {
 	state   *state.StateDB
 }
 
+func (s *stateDB) GetSnapshot(key string, timestamp uint64) ([]byte, error) {
+	return s.state.GetSnapshot(s.name, key, timestamp)
+}
+
 func (s *stateDB) Get(key string) ([]byte, error) {
 	return s.state.Get(s.name, key)
 }
@@ -65,11 +70,12 @@ func (s *stateDB) Delete(key string) error {
 	return nil
 }
 func (s *stateDB) Delegate(from string, amount *big.Int) error {
-	accountDB, err := accountmanager.NewAccountManager(s.state)
-	if err != nil {
-		return err
-	}
-	return accountDB.TransferAsset(common.StrToName(from), common.StrToName(s.name), s.assetid, amount)
+	return nil
+	// accountDB, err := accountmanager.NewAccountManager(s.state)
+	// if err != nil {
+	// 	return err
+	// }
+	// return accountDB.TransferAsset(common.StrToName(from), common.StrToName(s.name), s.assetid, amount)
 }
 func (s *stateDB) Undelegate(to string, amount *big.Int) error {
 	accountDB, err := accountmanager.NewAccountManager(s.state)
@@ -90,9 +96,10 @@ func (s *stateDB) IsValidSign(name string, pubkey []byte) bool {
 	if err != nil {
 		return false
 	}
-	return accountDB.IsValidSign(common.StrToName(name), types.ActionType(0), common.BytesToPubKey(pubkey)) == nil
+	return accountDB.IsValidSign(common.StrToName(name), common.BytesToPubKey(pubkey)) == nil
 }
 
+// Genesis dpos genesis store
 func Genesis(cfg *Config, state *state.StateDB, height uint64) error {
 	db := &LDB{
 		IDatabase: &stateDB{
@@ -100,7 +107,7 @@ func Genesis(cfg *Config, state *state.StateDB, height uint64) error {
 			state: state,
 		},
 	}
-	if err := db.SetProducer(&producerInfo{
+	if err := db.SetCadidate(&cadidateInfo{
 		Name:          cfg.SystemName,
 		URL:           cfg.SystemURL,
 		Quantity:      big.NewInt(0),
@@ -110,21 +117,21 @@ func Genesis(cfg *Config, state *state.StateDB, height uint64) error {
 		return err
 	}
 
-	activatedProducerSchedule := []string{}
-	for i := uint64(0); i < cfg.ProducerScheduleSize; i++ {
-		activatedProducerSchedule = append(activatedProducerSchedule, cfg.SystemName)
+	activatedCadidateSchedule := []string{}
+	for i := uint64(0); i < cfg.CadidateScheduleSize; i++ {
+		activatedCadidateSchedule = append(activatedCadidateSchedule, cfg.SystemName)
 	}
 	if err := db.SetState(&globalState{
 		Height:                    height,
 		ActivatedTotalQuantity:    big.NewInt(0),
-		ActivatedProducerSchedule: activatedProducerSchedule,
+		ActivatedCadidateSchedule: activatedCadidateSchedule,
 	}); err != nil {
 		return err
 	}
 	if err := db.SetState(&globalState{
 		Height:                    height + 1,
 		ActivatedTotalQuantity:    big.NewInt(0),
-		ActivatedProducerSchedule: activatedProducerSchedule,
+		ActivatedCadidateSchedule: activatedCadidateSchedule,
 	}); err != nil {
 		return err
 	}
@@ -143,11 +150,7 @@ type Dpos struct {
 	config *Config
 
 	// cache
-	proposedIrreversibleNum uint64
-	bftIrreversibleNum      uint64
-	producerIrreversibleNum map[string]uint64
-
-	firtEpcho uint64
+	bftIrreversibles *lru.Cache
 }
 
 // New creates a DPOS consensus engine
@@ -155,21 +158,10 @@ func New(config *Config, chain consensus.IChainReader) *Dpos {
 	dpos := &Dpos{
 		config: config,
 	}
-	if chain != nil {
-		dpos.init(chain)
-	}
+	dpos.bftIrreversibles, _ = lru.New(int(config.CadidateScheduleSize))
 	return dpos
 }
 
-func (dpos *Dpos) init(chain consensus.IChainReader) {
-	fheader := chain.GetHeaderByNumber(1)
-	if fheader == nil {
-		return
-	}
-	dpos.firtEpcho = dpos.config.epoch(fheader.Time.Uint64())
-	dpos.calcProposedIrreversible(chain)
-}
-
 // SetConfig set dpos config
 func (dpos *Dpos) SetConfig(config *Config) {
 	dpos.rw.Lock()
@@ -221,27 +213,40 @@ func (dpos *Dpos) Finalize(chain consensus.IChainReader, header *types.Header, t
 		},
 	}
 
-	if dpos.firtEpcho == 0 {
-		if fheader := chain.GetHeaderByNumber(1); fheader != nil {
-			dpos.firtEpcho = dpos.config.epoch(fheader.Time.Uint64())
-		}
-	}
-
 	counter := int64(0)
-	if dpos.IsFirst(header.Time.Uint64()) {
-		timestamp := header.Time.Uint64() - dpos.config.blockInterval()*dpos.config.BlockFrequency
+	parentEpoch := dpos.config.epoch(parent.Time.Uint64())
+	currentEpoch := dpos.config.epoch(header.Time.Uint64())
+	if parentEpoch != currentEpoch {
 		tparent := parent
-		for tparent.Number.Uint64() > 0 && tparent.Time.Uint64() >= timestamp {
+		for tparent.Number.Uint64() > 1 && dpos.config.epoch(tparent.Number.Uint64()) == dpos.config.epoch(parent.Time.Uint64()) {
 			counter++
 			tparent = chain.GetHeaderByHash(tparent.ParentHash)
 		}
+		// next epoch
+		sys.updateElectedCadidates(header.Time.Uint64())
+	}
+
+	if parent.Number.Uint64() > 0 && (dpos.CalcProposedIrreversible(chain, parent, true) == 0 || header.Time.Uint64()-parent.Time.Uint64() > 2*dpos.config.epochInterval()) {
+		if systemio := strings.Compare(header.Coinbase.String(), dpos.config.SystemName) == 0; systemio {
+			latest, err := sys.GetState(header.Number.Uint64())
+			if err != nil {
+				return nil, err
+			}
+			latest.TakeOver = true
+			if err := sys.SetState(latest); err != nil {
+				return nil, err
+			}
+		}
 	}
 
-	parent_epoch := dpos.config.epoch(parent.Time.Uint64())
-	current_epoch := dpos.config.epoch(header.Time.Uint64())
-	if parent_epoch != current_epoch {
-		// next epoch
-		sys.updateElectedProducers(header.Time.Uint64())
+	cadidate, err := sys.GetCadidate(header.Coinbase.String())
+	if err != nil {
+		return nil, err
+	} else if cadidate != nil {
+		cadidate.Counter++
+		if err := sys.SetCadidate(cadidate); err != nil {
+			return nil, err
+		}
 	}
 
 	extraReward := new(big.Int).Mul(dpos.config.extraBlockReward(), big.NewInt(counter))
@@ -260,7 +265,10 @@ func (dpos *Dpos) Finalize(chain consensus.IChainReader, header *types.Header, t
 
 	// update state root at the end
 	blk.Head.Root = state.IntermediateRoot()
-
+	if strings.Compare(header.Coinbase.String(), dpos.config.SystemName) == 0 {
+		dpos.bftIrreversibles.Purge()
+	}
+	dpos.bftIrreversibles.Add(header.Coinbase, header.ProposedIrreversible)
 	return blk, nil
 }
 
@@ -281,8 +289,8 @@ func (dpos *Dpos) Seal(chain consensus.IChainReader, block *types.Block, stop <-
 	if err != nil {
 		return nil, err
 	}
+
 	copy(header.Extra[len(header.Extra)-extraSeal:], sighash)
-	dpos.calcProposedIrreversible(chain)
 	return block.WithSeal(header), nil
 }
 
@@ -307,11 +315,11 @@ func (dpos *Dpos) VerifySeal(chain consensus.IChainReader, header *types.Header)
 		return err
 	}
 
-	if err := dpos.IsValidateProducer(chain, header.Number.Uint64()-1, header.Time.Uint64(), proudcer, [][]byte{pubkey}, state); err != nil {
+	if err := dpos.IsValidateCadidate(chain, parent, header.Time.Uint64(), proudcer, [][]byte{pubkey}, state, true); err != nil {
 		return err
 	}
 
-	return dpos.calcProposedIrreversible(chain)
+	return nil
 }
 
 // CalcDifficulty is the difficulty adjustment algorithm.
@@ -326,8 +334,8 @@ func (dpos *Dpos) CalcDifficulty(chain consensus.IChainReader, time uint64, pare
 	return big.NewInt((int64(time)-timeOfGenesisBlock)/int64(dpos.config.blockInterval()) + 1)
 }
 
-//IsValidateProducer current producer
-func (dpos *Dpos) IsValidateProducer(chain consensus.IChainReader, height uint64, timestamp uint64, producer string, pubkeys [][]byte, state *state.StateDB) error {
+//IsValidateCadidate current cadidate
+func (dpos *Dpos) IsValidateCadidate(chain consensus.IChainReader, parent *types.Header, timestamp uint64, cadidate string, pubkeys [][]byte, state *state.StateDB, force bool) error {
 	if timestamp%dpos.BlockInterval() != 0 {
 		return errInvalidMintBlockTime
 	}
@@ -337,38 +345,20 @@ func (dpos *Dpos) IsValidateProducer(chain consensus.IChainReader, height uint64
 		state: state,
 	}
 
-	if !common.IsValidName(producer) {
-		return ErrIllegalProducerName
+	if !common.IsValidAccountName(cadidate) {
+		return ErrIllegalCadidateName
 	}
 
 	has := false
 	for _, pubkey := range pubkeys {
-		if db.IsValidSign(producer, pubkey) {
+		if db.IsValidSign(cadidate, pubkey) {
 			has = true
 		}
 	}
 	if !has {
-		return ErrIllegalProducerPubKey
+		return ErrIllegalCadidatePubKey
 	}
 
-	target_ts := big.NewInt(int64(timestamp - dpos.config.DelayEcho*dpos.config.epochInterval()))
-	// find target block
-	var pheader *types.Header
-	for height > 0 {
-		pheader = chain.GetHeaderByNumber(height)
-		if pheader.Time.Cmp(target_ts) != 1 {
-			break
-		} else {
-			height -= 1
-		}
-	}
-
-	// if height > dpos.config.DelayEcho {
-	// 	height = height - dpos.config.DelayEcho
-	// } else {
-	// 	height = uint64(0)
-	// }
-
 	sys := &System{
 		config: dpos.config,
 		IDB: &LDB{
@@ -376,13 +366,41 @@ func (dpos *Dpos) IsValidateProducer(chain consensus.IChainReader, height uint64
 		},
 	}
 
-	gstate, err := sys.GetState(height)
+	latest, err := sys.GetState(parent.Number.Uint64())
+	if err != nil {
+		return err
+	}
+
+	systemio := strings.Compare(cadidate, dpos.config.SystemName) == 0
+	if latest.TakeOver {
+		if force && systemio {
+			return nil
+		}
+		return ErrSystemTakeOver
+	} else if parent.Number.Uint64() > 0 && (dpos.CalcProposedIrreversible(chain, parent, true) == 0 || timestamp-parent.Time.Uint64() > 2*dpos.config.epochInterval()) {
+		if force && systemio {
+			// first take over
+			return nil
+		}
+		return ErrTooMuchRreversible
+	}
+
+	targetTime := big.NewInt(int64(timestamp - dpos.config.DelayEcho*dpos.config.epochInterval()))
+	// find target block
+	for parent.Number.Uint64() > 0 {
+		if parent.Time.Cmp(targetTime) == -1 {
+			break
+		}
+		parent = chain.GetHeaderByHash(parent.ParentHash)
+	}
+
+	gstate, err := sys.GetState(parent.Number.Uint64() + 1)
 	if err != nil {
 		return err
 	}
 	offset := dpos.config.getoffset(timestamp)
-	if gstate == nil || offset >= uint64(len(gstate.ActivatedProducerSchedule)) || strings.Compare(gstate.ActivatedProducerSchedule[offset], producer) != 0 {
-		return fmt.Errorf("%v %v, except %v index %v (%v) ", errInvalidBlockProducer, producer, gstate.ActivatedProducerSchedule, offset, timestamp/dpos.config.epochInterval())
+	if gstate == nil || offset >= uint64(len(gstate.ActivatedCadidateSchedule)) || strings.Compare(gstate.ActivatedCadidateSchedule[offset], cadidate) != 0 {
+		return fmt.Errorf("%v %v, except %v index %v (%v) ", errInvalidBlockCadidate, cadidate, gstate.ActivatedCadidateSchedule, offset, timestamp/dpos.config.epochInterval())
 	}
 	return nil
 }
@@ -392,23 +410,41 @@ func (dpos *Dpos) BlockInterval() uint64 {
 	return dpos.config.blockInterval()
 }
 
+// Slot
 func (dpos *Dpos) Slot(timestamp uint64) uint64 {
 	return dpos.config.slot(timestamp)
 }
 
+// IsFirst the first of cadidate
 func (dpos *Dpos) IsFirst(timestamp uint64) bool {
 	return timestamp%dpos.config.epochInterval()%(dpos.config.blockInterval()*dpos.config.BlockFrequency) == 0
 }
 
+func (dpos *Dpos) GetDelegatedByTime(name string, timestamp uint64, state *state.StateDB) (*big.Int, *big.Int, uint64, error) {
+	sys := &System{
+		config: dpos.config,
+		IDB: &LDB{
+			IDatabase: &stateDB{
+				name:  dpos.config.AccountName,
+				state: state,
+			},
+		},
+	}
+	return sys.GetDelegatedByTime(name, timestamp)
+}
+
 // Engine an engine
 func (dpos *Dpos) Engine() consensus.IEngine {
 	return dpos
 }
 
-func (dpos *Dpos) calcLastIrreversible() uint64 {
+func (dpos *Dpos) CalcBFTIrreversible() uint64 {
 	irreversibles := UInt64Slice{}
-	for _, irreversible := range dpos.producerIrreversibleNum {
-		irreversibles = append(irreversibles, irreversible)
+	keys := dpos.bftIrreversibles.Keys()
+	for _, key := range keys {
+		if irreversible, ok := dpos.bftIrreversibles.Get(key); ok {
+			irreversibles = append(irreversibles, irreversible.(uint64))
+		}
 	}
 
 	if len(irreversibles) == 0 {
@@ -421,30 +457,27 @@ func (dpos *Dpos) calcLastIrreversible() uint64 {
 	return irreversibles[(len(irreversibles)-1)/3]
 }
 
-func (dpos *Dpos) calcProposedIrreversible(chain consensus.IChainReader) error {
+func (dpos *Dpos) CalcProposedIrreversible(chain consensus.IChainReader, parent *types.Header, strict bool) uint64 {
 	curHeader := chain.CurrentHeader()
-
-	producerMap := make(map[string]uint64)
-	for curHeader.Number.Uint64() > dpos.proposedIrreversibleNum {
-		if curHeader.Number.Uint64()-dpos.proposedIrreversibleNum+uint64(len(producerMap)) < dpos.config.consensusSize() {
-			return nil
+	if parent != nil {
+		curHeader = chain.GetHeaderByHash(parent.Hash())
+	}
+	cadidateMap := make(map[string]uint64)
+	timestamp := curHeader.Time.Uint64()
+	for curHeader.Number.Uint64() > 0 {
+		if strings.Compare(curHeader.Coinbase.String(), dpos.config.SystemName) == 0 {
+			return curHeader.Number.Uint64()
 		}
-		epoch := dpos.config.epoch(curHeader.Time.Uint64())
-		if e, ok := producerMap[curHeader.Coinbase.String()]; e != epoch && ok {
-			return nil
+		if strict && timestamp-curHeader.Time.Uint64() >= 2*dpos.config.epochInterval() {
+			break
 		}
-		producerMap[curHeader.Coinbase.String()] = epoch
-
-		if uint64(len(producerMap)) >= dpos.config.consensusSize() {
-			dpos.proposedIrreversibleNum = curHeader.Number.Uint64()
-			return nil
+		cadidateMap[curHeader.Coinbase.String()]++
+		if uint64(len(cadidateMap)) >= dpos.config.consensusSize() {
+			return curHeader.Number.Uint64()
 		}
 		curHeader = chain.GetHeaderByHash(curHeader.ParentHash)
-		if curHeader == nil {
-			return nil
-		}
 	}
-	return nil
+	return 0
 }
 
 func ecrecover(header *types.Header, extra []byte) ([]byte, error) {
@@ -461,24 +494,9 @@ func ecrecover(header *types.Header, extra []byte) ([]byte, error) {
 }
 
 func signHash(header *types.Header, extra []byte) (hash common.Hash) {
-	hasher := sha3.NewLegacyKeccak256()
-	rlp.Encode(hasher, []interface{}{
-		header.ParentHash,
-		header.Coinbase,
-		header.Root,
-		header.TxsRoot,
-		header.ReceiptsRoot,
-		header.Bloom,
-		header.Difficulty,
-		header.Number,
-		header.GasLimit,
-		header.GasUsed,
-		header.Time,
-		header.Extra[:len(header.Extra)-extraSeal],
-		extra,
-	})
-	hasher.Sum(hash[:0])
-	return hash
+	theader := types.CopyHeader(header)
+	theader.Extra = theader.Extra[:len(theader.Extra)-extraSeal]
+	return theader.Hash()
 }
 
 // UInt64Slice attaches the methods of sort.Interface to []uint64, sorting in increasing order.
diff --git a/consensus/dpos/ldb.go b/consensus/dpos/ldb.go
index 933f736f..79e03bab 100644
--- a/consensus/dpos/ldb.go
+++ b/consensus/dpos/ldb.go
@@ -35,26 +35,28 @@ type IDatabase interface {
 	Delegate(string, *big.Int) error
 	Undelegate(string, *big.Int) error
 	IncAsset2Acct(string, string, *big.Int) error
+
+	GetSnapshot(key string, timestamp uint64) ([]byte, error)
 }
 
 var (
-	// ProducerKeyPrefix producer name --> producerInfo
-	ProducerKeyPrefix = "prod"
+	// CadidateKeyPrefix cadidate name --> cadidateInfo
+	CadidateKeyPrefix = "prod"
 	// VoterKeyPrefix voter name ---> voterInfo
 	VoterKeyPrefix = "vote"
-	// // DelegatorKeyPrfix producer name ----> voter names
+	// // DelegatorKeyPrfix cadidate name ----> voter names
 	// DelegatorKeyPrfix = "dele"
-	// ProducersKeyPrefix produces ----> producer names
-	ProducersKeyPrefix = "prods"
+	// CadidatesKeyPrefix produces ----> cadidate names
+	CadidatesKeyPrefix = "prods"
 	// StateKeyPrefix height --> globalState
 	StateKeyPrefix = "state"
 	// Separator Split characters
 	Separator = "_"
 
-	// ProducersKey producers
-	ProducersKey = "prods"
-	// ProducersSizeKey producers size
-	ProducersSizeKey = "prodsize"
+	// CadidatesKey cadidates
+	CadidatesKey = "prods"
+	// CadidatesSizeKey cadidates size
+	CadidatesSizeKey = "prodsize"
 	// LastestStateKey lastest
 	LastestStateKey = "lastest"
 )
@@ -73,17 +75,17 @@ func NewLDB(db IDatabase) (*LDB, error) {
 	return ldb, nil
 }
 
-func (db *LDB) GetProducer(name string) (*producerInfo, error) {
-	key := strings.Join([]string{ProducerKeyPrefix, name}, Separator)
-	producerInfo := &producerInfo{}
+func (db *LDB) GetCadidate(name string) (*cadidateInfo, error) {
+	key := strings.Join([]string{CadidateKeyPrefix, name}, Separator)
+	cadidateInfo := &cadidateInfo{}
 	if val, err := db.Get(key); err != nil {
 		return nil, err
 	} else if val == nil {
 		return nil, nil
-	} else if err := rlp.DecodeBytes(val, producerInfo); err != nil {
+	} else if err := rlp.DecodeBytes(val, cadidateInfo); err != nil {
 		return nil, err
 	}
-	return producerInfo, nil
+	return cadidateInfo, nil
 }
 
 func (db *LDB) GetVoter(name string) (*voterInfo, error) {
@@ -99,8 +101,8 @@ func (db *LDB) GetVoter(name string) (*voterInfo, error) {
 	return voterInfo, nil
 }
 
-// func (db *LDB) GetDelegators(producer string) ([]string, error) {
-// 	key := strings.Join([]string{DelegatorKeyPrfix, producer}, Separator)
+// func (db *LDB) GetDelegators(cadidate string) ([]string, error) {
+// 	key := strings.Join([]string{DelegatorKeyPrfix, cadidate}, Separator)
 // 	delegators := []string{}
 // 	if val, err := db.Get(key); err != nil {
 // 		return nil, err
@@ -112,33 +114,33 @@ func (db *LDB) GetVoter(name string) (*voterInfo, error) {
 // 	return delegators, nil
 // }
 
-func (db *LDB) SetProducer(producer *producerInfo) error {
-	key := strings.Join([]string{ProducerKeyPrefix, producer.Name}, Separator)
-	if val, err := rlp.EncodeToBytes(producer); err != nil {
+func (db *LDB) SetCadidate(cadidate *cadidateInfo) error {
+	key := strings.Join([]string{CadidateKeyPrefix, cadidate.Name}, Separator)
+	if val, err := rlp.EncodeToBytes(cadidate); err != nil {
 		return err
 	} else if err := db.Put(key, val); err != nil {
 		return err
 	}
 
-	// producers
-	producers := []string{}
-	pkey := strings.Join([]string{ProducersKeyPrefix, ProducersKey}, Separator)
+	// cadidates
+	cadidates := []string{}
+	pkey := strings.Join([]string{CadidatesKeyPrefix, CadidatesKey}, Separator)
 	if pval, err := db.Get(pkey); err != nil {
 		return err
 	} else if pval == nil {
 
-	} else if err := rlp.DecodeBytes(pval, &producers); err != nil {
+	} else if err := rlp.DecodeBytes(pval, &cadidates); err != nil {
 		return err
 	}
 
-	for _, name := range producers {
-		if strings.Compare(name, producer.Name) == 0 {
+	for _, name := range cadidates {
+		if strings.Compare(name, cadidate.Name) == 0 {
 			return nil
 		}
 	}
 
-	producers = append(producers, producer.Name)
-	npval, err := rlp.EncodeToBytes(producers)
+	cadidates = append(cadidates, cadidate.Name)
+	npval, err := rlp.EncodeToBytes(cadidates)
 	if err != nil {
 		return err
 	}
@@ -146,8 +148,8 @@ func (db *LDB) SetProducer(producer *producerInfo) error {
 		return err
 	}
 
-	skey := strings.Join([]string{ProducersKeyPrefix, ProducersSizeKey}, Separator)
-	return db.Put(skey, uint64tobytes(uint64(len(producers))))
+	skey := strings.Join([]string{CadidatesKeyPrefix, CadidatesSizeKey}, Separator)
+	return db.Put(skey, uint64tobytes(uint64(len(cadidates))))
 }
 
 func (db *LDB) SetVoter(voter *voterInfo) error {
@@ -160,7 +162,7 @@ func (db *LDB) SetVoter(voter *voterInfo) error {
 
 	// 	// delegators
 	// 	delegators := []string{}
-	// 	dkey := strings.Join([]string{DelegatorKeyPrfix, voter.Producer}, Separator)
+	// 	dkey := strings.Join([]string{DelegatorKeyPrfix, voter.Cadidate}, Separator)
 
 	// 	if dval, err := db.Get(dkey); err != nil {
 	// 		return err
@@ -182,45 +184,45 @@ func (db *LDB) SetVoter(voter *voterInfo) error {
 	return nil
 }
 
-func (db *LDB) DelProducer(name string) error {
-	key := strings.Join([]string{ProducerKeyPrefix, name}, Separator)
+func (db *LDB) DelCadidate(name string) error {
+	key := strings.Join([]string{CadidateKeyPrefix, name}, Separator)
 	if err := db.Delete(key); err != nil {
 		return err
 	}
 
-	// producers
-	producers := []string{}
-	pkey := strings.Join([]string{ProducersKeyPrefix, ProducersKey}, Separator)
+	// cadidates
+	cadidates := []string{}
+	pkey := strings.Join([]string{CadidatesKeyPrefix, CadidatesKey}, Separator)
 	if pval, err := db.Get(pkey); err != nil {
 		return err
 	} else if pval == nil {
 
-	} else if err := rlp.DecodeBytes(pval, &producers); err != nil {
+	} else if err := rlp.DecodeBytes(pval, &cadidates); err != nil {
 		return err
 	}
-	for index, prod := range producers {
+	for index, prod := range cadidates {
 		if strings.Compare(prod, name) == 0 {
-			producers = append(producers[:index], producers[index+1:]...)
+			cadidates = append(cadidates[:index], cadidates[index+1:]...)
 			break
 		}
 	}
 
-	skey := strings.Join([]string{ProducersKeyPrefix, ProducersSizeKey}, Separator)
-	if err := db.Put(skey, uint64tobytes(uint64(len(producers)))); err != nil {
+	skey := strings.Join([]string{CadidatesKeyPrefix, CadidatesSizeKey}, Separator)
+	if err := db.Put(skey, uint64tobytes(uint64(len(cadidates)))); err != nil {
 		return err
 	}
 
-	if len(producers) == 0 {
+	if len(cadidates) == 0 {
 		return db.Delete(pkey)
 	}
-	npval, err := rlp.EncodeToBytes(producers)
+	npval, err := rlp.EncodeToBytes(cadidates)
 	if err != nil {
 		return err
 	}
 	return db.Put(pkey, npval)
 }
 
-func (db *LDB) DelVoter(name string, producer string) error {
+func (db *LDB) DelVoter(name string, cadidate string) error {
 	key := strings.Join([]string{VoterKeyPrefix, name}, Separator)
 	if err := db.Delete(key); err != nil {
 		return err
@@ -228,7 +230,7 @@ func (db *LDB) DelVoter(name string, producer string) error {
 
 	// delegators
 	// delegators := []string{}
-	// dkey := strings.Join([]string{DelegatorKeyPrfix, producer}, Separator)
+	// dkey := strings.Join([]string{DelegatorKeyPrfix, cadidate}, Separator)
 	// if dval, err := db.Get(dkey); err != nil {
 	// 	return err
 	// } else if dval == nil {
@@ -253,21 +255,21 @@ func (db *LDB) DelVoter(name string, producer string) error {
 	return nil
 }
 
-func (db *LDB) Producers() ([]*producerInfo, error) {
-	// producers
-	pkey := strings.Join([]string{ProducersKeyPrefix, ProducersKey}, Separator)
-	producers := []string{}
+func (db *LDB) Cadidates() ([]*cadidateInfo, error) {
+	// cadidates
+	pkey := strings.Join([]string{CadidatesKeyPrefix, CadidatesKey}, Separator)
+	cadidates := []string{}
 	if pval, err := db.Get(pkey); err != nil {
 		return nil, err
 	} else if pval == nil {
 		return nil, nil
-	} else if err := rlp.DecodeBytes(pval, &producers); err != nil {
+	} else if err := rlp.DecodeBytes(pval, &cadidates); err != nil {
 		return nil, err
 	}
 
-	prods := producerInfoArray{}
-	for _, producer := range producers {
-		prod, err := db.GetProducer(producer)
+	prods := cadidateInfoArray{}
+	for _, cadidate := range cadidates {
+		prod, err := db.GetCadidate(cadidate)
 		if err != nil {
 			return nil, err
 		}
@@ -277,9 +279,9 @@ func (db *LDB) Producers() ([]*producerInfo, error) {
 	return prods, nil
 }
 
-func (db *LDB) ProducersSize() (uint64, error) {
+func (db *LDB) CadidatesSize() (uint64, error) {
 	size := uint64(0)
-	skey := strings.Join([]string{ProducersKeyPrefix, ProducersSizeKey}, Separator)
+	skey := strings.Join([]string{CadidatesKeyPrefix, CadidatesSizeKey}, Separator)
 	if sval, err := db.Get(skey); err != nil {
 		return 0, err
 	} else if sval != nil {
@@ -340,6 +342,35 @@ func (db *LDB) DelState(height uint64) error {
 	return db.Delete(key)
 }
 
+func (db *LDB) GetDelegatedByTime(name string, timestamp uint64) (*big.Int, *big.Int, uint64, error) {
+	key := strings.Join([]string{CadidateKeyPrefix, name}, Separator)
+	val, err := db.GetSnapshot(key, timestamp)
+	if err != nil {
+		return big.NewInt(0), big.NewInt(0), 0, err
+	}
+	if val != nil {
+		cadidateInfo := &cadidateInfo{}
+		if err := rlp.DecodeBytes(val, cadidateInfo); err != nil {
+			return big.NewInt(0), big.NewInt(0), 0, err
+		}
+		return cadidateInfo.Quantity, cadidateInfo.TotalQuantity, cadidateInfo.Counter, nil
+	}
+
+	key = strings.Join([]string{VoterKeyPrefix, name}, Separator)
+	val, err = db.GetSnapshot(key, timestamp)
+	if err != nil {
+		return big.NewInt(0), big.NewInt(0), 0, err
+	}
+	if val != nil {
+		voterInfo := &voterInfo{}
+		if err := rlp.DecodeBytes(val, voterInfo); err != nil {
+			return big.NewInt(0), big.NewInt(0), 0, err
+		}
+		return voterInfo.Quantity, big.NewInt(0), 0, nil
+	}
+	return big.NewInt(0), big.NewInt(0), 0, nil
+}
+
 func (db *LDB) lastestHeight() (uint64, error) {
 	lkey := strings.Join([]string{StateKeyPrefix, LastestStateKey}, Separator)
 	if val, err := db.Get(lkey); err != nil {
diff --git a/consensus/dpos/ldb_test.go b/consensus/dpos/ldb_test.go
index 5e7bd082..9a7a1604 100644
--- a/consensus/dpos/ldb_test.go
+++ b/consensus/dpos/ldb_test.go
@@ -63,7 +63,9 @@ func (ldb *levelDB) Undelegate(string, *big.Int) error {
 func (ldb *levelDB) IncAsset2Acct(string, string, *big.Int) error {
 	return nil
 }
-
+func (ldb *levelDB) GetSnapshot(string, uint64) ([]byte, error) {
+	return nil, nil
+}
 func newTestLDB() (*levelDB, func()) {
 	dirname, err := ioutil.TempDir(os.TempDir(), "dpos_test_")
 	if err != nil {
@@ -89,7 +91,7 @@ func TestLDBVoter(t *testing.T) {
 	defer function()
 	voter := &voterInfo{
 		Name:     "vos",
-		Producer: "fos",
+		Cadidate: "fos",
 		Quantity: big.NewInt(1000),
 		Height:   uint64(time.Now().UnixNano()),
 	}
@@ -104,17 +106,17 @@ func TestLDBVoter(t *testing.T) {
 		panic(fmt.Errorf("getvoter --- not nil"))
 	}
 
-	// if delegators, err := db.GetDelegators(nvoter.Producer); err != nil {
+	// if delegators, err := db.GetDelegators(nvoter.Cadidate); err != nil {
 	// 	panic(fmt.Errorf("getdelegators --- %v", err))
 	// } else if len(delegators) != 1 {
 	// 	panic(fmt.Errorf("getdelegators --- not mismatch"))
 	// }
 
-	if err := db.DelVoter(nvoter.Name, nvoter.Producer); err != nil {
+	if err := db.DelVoter(nvoter.Name, nvoter.Cadidate); err != nil {
 		panic(fmt.Errorf("delvoter --- %v", err))
 	}
 
-	// if delegators, err := db.GetDelegators(nvoter.Producer); err != nil {
+	// if delegators, err := db.GetDelegators(nvoter.Cadidate); err != nil {
 	// 	panic(fmt.Errorf("getdelegators after del --- %v", err))
 	// } else if len(delegators) != 0 {
 	// 	t.Log(len(delegators))
@@ -128,50 +130,50 @@ func TestLDBVoter(t *testing.T) {
 	}
 }
 
-func TestLDBProducer(t *testing.T) {
-	// SetProducer(*producerInfo) error
-	// DelProducer(string) error
-	// GetProducer(string) (*producerInfo, error)
-	// Producers() ([]*producerInfo, error)
-	// ProducersSize() (uint64, error)
+func TestLDBCadidate(t *testing.T) {
+	// SetCadidate(*cadidateInfo) error
+	// DelCadidate(string) error
+	// GetCadidate(string) (*cadidateInfo, error)
+	// Cadidates() ([]*cadidateInfo, error)
+	// CadidatesSize() (uint64, error)
 	ldb, function := newTestLDB()
 	db, _ := NewLDB(ldb)
 	defer function()
-	prod := &producerInfo{
+	prod := &cadidateInfo{
 		Name:          "fos",
 		URL:           "www.fractalproject.com",
 		Quantity:      big.NewInt(1000),
 		TotalQuantity: big.NewInt(1000),
 		Height:        uint64(time.Now().UnixNano()),
 	}
-	if err := db.SetProducer(prod); err != nil {
+	if err := db.SetCadidate(prod); err != nil {
 		panic(fmt.Errorf("setprod --- %v", err))
 	}
 
-	nprod, err := db.GetProducer(prod.Name)
+	nprod, err := db.GetCadidate(prod.Name)
 	if err != nil {
 		panic(fmt.Errorf("getprod --- %v", err))
 	} else if nprod == nil {
 		panic(fmt.Errorf("getprod --- not nil"))
 	}
 
-	if size, err := db.ProducersSize(); err != nil {
+	if size, err := db.CadidatesSize(); err != nil {
 		panic(fmt.Errorf("prodsize --- %v", err))
 	} else if size != 1 {
 		panic(fmt.Errorf("prodsize --- mismatch"))
 	}
 
-	if err := db.DelProducer(nprod.Name); err != nil {
+	if err := db.DelCadidate(nprod.Name); err != nil {
 		panic(fmt.Errorf("delprod --- %v", err))
 	}
 
-	if size, err := db.ProducersSize(); err != nil {
+	if size, err := db.CadidatesSize(); err != nil {
 		panic(fmt.Errorf("prodsize --- %v", err))
 	} else if size != 0 {
 		panic(fmt.Errorf("prodsize --- mismatch"))
 	}
 
-	if nprod, err := db.GetProducer(nprod.Name); err != nil {
+	if nprod, err := db.GetCadidate(nprod.Name); err != nil {
 		panic(fmt.Errorf("getprod --- %v", err))
 	} else if nprod != nil {
 		panic(fmt.Errorf("getprod --- should nil"))
@@ -187,8 +189,8 @@ func TestLDBState(t *testing.T) {
 	defer function()
 	gstate := &globalState{
 		Height:                          10,
-		ActivatedProducerScheduleUpdate: uint64(time.Now().UnixNano()),
-		ActivatedProducerSchedule:       []string{},
+		ActivatedCadidateScheduleUpdate: uint64(time.Now().UnixNano()),
+		ActivatedCadidateSchedule:       []string{},
 		ActivatedTotalQuantity:          big.NewInt(1000),
 		TotalQuantity:                   big.NewInt(100000),
 	}
diff --git a/consensus/dpos/processor.go b/consensus/dpos/processor.go
index 70ef2566..8c1da0ff 100644
--- a/consensus/dpos/processor.go
+++ b/consensus/dpos/processor.go
@@ -17,9 +17,12 @@
 package dpos
 
 import (
+	"fmt"
 	"math/big"
+	"strings"
 
 	"github.com/fractalplatform/fractal/accountmanager"
+	"github.com/fractalplatform/fractal/common"
 	"github.com/fractalplatform/fractal/utils/rlp"
 
 	"github.com/fractalplatform/fractal/params"
@@ -27,39 +30,41 @@ import (
 	"github.com/fractalplatform/fractal/types"
 )
 
-type RegisterProducer struct {
-	Url   string
-	Stake *big.Int
+type RegisterCadidate struct {
+	Url string
 }
 
-type UpdateProducer struct {
+type UpdateCadidate struct {
 	Url   string
 	Stake *big.Int
 }
 
-type VoteProducer struct {
-	Producer string
-	Stake    *big.Int
+type VoteCadidate struct {
+	Cadidate string
 }
 
-type ChangeProducer struct {
-	Producer string
+type ChangeCadidate struct {
+	Cadidate string
 }
 
 type RemoveVoter struct {
-	Voter string
+	Voters []string
+}
+
+type KickedCadidate struct {
+	Cadidates []string
 }
 
-func (dpos *Dpos) ProcessAction(chainCfg *params.ChainConfig, state *state.StateDB, action *types.Action) error {
+func (dpos *Dpos) ProcessAction(chainCfg *params.ChainConfig, state *state.StateDB, action *types.Action) ([]*types.InternalAction, error) {
 	snap := state.Snapshot()
-	err := dpos.processAction(chainCfg, state, action)
+	internalLogs, err := dpos.processAction(chainCfg, state, action)
 	if err != nil {
 		state.RevertToSnapshot(snap)
 	}
-	return err
+	return internalLogs, err
 }
 
-func (dpos *Dpos) processAction(chainCfg *params.ChainConfig, state *state.StateDB, action *types.Action) error {
+func (dpos *Dpos) processAction(chainCfg *params.ChainConfig, state *state.StateDB, action *types.Action) ([]*types.InternalAction, error) {
 	sys := &System{
 		config: dpos.config,
 		IDB: &LDB{
@@ -70,64 +75,120 @@ func (dpos *Dpos) processAction(chainCfg *params.ChainConfig, state *state.State
 			},
 		},
 	}
+
+	var internalActions []*types.InternalAction
+
+	if !action.CheckValue() {
+		return nil, accountmanager.ErrAmountValueInvalid
+	}
+
+	if action.AssetID() != chainCfg.SysTokenID {
+		return nil, accountmanager.ErrAssetIDInvalid
+	}
+
+	if strings.Compare(action.Recipient().String(), dpos.config.AccountName) != 0 {
+		return nil, accountmanager.ErrInvalidReceiptAsset
+	}
+
+	if action.Value().Cmp(big.NewInt(0)) > 0 {
+		accountDB, err := accountmanager.NewAccountManager(state)
+		if err != nil {
+			return nil, err
+		}
+		if err := accountDB.TransferAsset(action.Sender(), action.Recipient(), action.AssetID(), action.Value()); err != nil {
+			return nil, err
+		}
+	}
+
 	switch action.Type() {
-	case types.RegProducer:
-		arg := &RegisterProducer{}
+	case types.RegCadidate:
+		arg := &RegisterCadidate{}
 		if err := rlp.DecodeBytes(action.Data(), &arg); err != nil {
-			return err
+			return nil, err
 		}
-		if err := sys.RegProducer(action.Sender().String(), arg.Url, arg.Stake); err != nil {
-			return err
+		if err := sys.RegCadidate(action.Sender().String(), arg.Url, action.Value()); err != nil {
+			return nil, err
 		}
-	case types.UpdateProducer:
-		arg := &UpdateProducer{}
+	case types.UpdateCadidate:
+		arg := &UpdateCadidate{}
 		if err := rlp.DecodeBytes(action.Data(), &arg); err != nil {
-			return err
+			return nil, err
+		}
+		if arg.Stake.Sign() == 1 {
+			return nil, fmt.Errorf("stake cannot be greater zero")
 		}
-		if err := sys.UpdateProducer(action.Sender().String(), arg.Url, arg.Stake); err != nil {
-			return err
+		if action.Value().Sign() == 1 && arg.Stake.Sign() == -1 {
+			return nil, fmt.Errorf("value & stake cannot allowed at the same time")
 		}
-	case types.UnregProducer:
-		if err := sys.UnregProducer(action.Sender().String()); err != nil {
-			return err
+		if err := sys.UpdateCadidate(action.Sender().String(), arg.Url, new(big.Int).Add(action.Value(), arg.Stake)); err != nil {
+			return nil, err
 		}
+	case types.UnregCadidate:
+		stake, err := sys.UnregCadidate(action.Sender().String())
+		if err != nil {
+			return nil, err
+		}
+		actionX := types.NewAction(action.Type(), action.Recipient(), action.Sender(), 0, 0, action.AssetID(), stake, nil)
+		internalAction := &types.InternalAction{Action: actionX.NewRPCAction(0), ActionType: "", GasUsed: 0, GasLimit: 0, Depth: 0, Error: ""}
+		internalActions = append(internalActions, internalAction)
 	case types.RemoveVoter:
 		arg := &RemoveVoter{}
 		if err := rlp.DecodeBytes(action.Data(), &arg); err != nil {
-			return err
+			return nil, err
+		}
+		for _, voter := range arg.Voters {
+			stake, err := sys.UnvoteVoter(action.Sender().String(), voter)
+			if err != nil {
+				return nil, err
+			}
+			actionX := types.NewAction(action.Type(), action.Recipient(), common.Name(voter), 0, 0, action.AssetID(), stake, nil)
+			internalAction := &types.InternalAction{Action: actionX.NewRPCAction(0), ActionType: "", GasUsed: 0, GasLimit: 0, Depth: 0, Error: ""}
+			internalActions = append(internalActions, internalAction)
+		}
+	case types.VoteCadidate:
+		arg := &VoteCadidate{}
+		if err := rlp.DecodeBytes(action.Data(), &arg); err != nil {
+			return nil, err
 		}
-		if err := sys.UnvoteVoter(action.Sender().String(), arg.Voter); err != nil {
-			return err
+		if err := sys.VoteCadidate(action.Sender().String(), arg.Cadidate, action.Value()); err != nil {
+			return nil, err
 		}
-	case types.VoteProducer:
-		arg := &VoteProducer{}
+	case types.ChangeCadidate:
+		arg := &ChangeCadidate{}
 		if err := rlp.DecodeBytes(action.Data(), &arg); err != nil {
-			return err
+			return nil, err
+		}
+		if err := sys.ChangeCadidate(action.Sender().String(), arg.Cadidate); err != nil {
+			return nil, err
 		}
-		if err := sys.VoteProducer(action.Sender().String(), arg.Producer, arg.Stake); err != nil {
-			return err
+	case types.UnvoteCadidate:
+		stake, err := sys.UnvoteCadidate(action.Sender().String())
+		if err != nil {
+			return nil, err
 		}
-	case types.ChangeProducer:
-		arg := &ChangeProducer{}
+		actionX := types.NewAction(action.Type(), action.Recipient(), action.Sender(), 0, 0, action.AssetID(), stake, nil)
+		internalAction := &types.InternalAction{Action: actionX.NewRPCAction(0), ActionType: "", GasUsed: 0, GasLimit: 0, Depth: 0, Error: ""}
+		internalActions = append(internalActions, internalAction)
+	case types.KickedCadidate:
+		if strings.Compare(action.Sender().String(), dpos.config.SystemName) != 0 {
+			return nil, fmt.Errorf("no permission for kicking cadidates")
+		}
+		arg := &KickedCadidate{}
 		if err := rlp.DecodeBytes(action.Data(), &arg); err != nil {
-			return err
+			return nil, err
 		}
-		if err := sys.ChangeProducer(action.Sender().String(), arg.Producer); err != nil {
-			return err
+		for _, cadicate := range arg.Cadidates {
+			if err := sys.KickedCadidate(cadicate); err != nil {
+				return nil, err
+			}
 		}
-	case types.UnvoteProducer:
-		if err := sys.UnvoteProducer(action.Sender().String()); err != nil {
-			return err
+	case types.ExitTakeOver:
+		if strings.Compare(action.Sender().String(), dpos.config.SystemName) != 0 {
+			return nil, fmt.Errorf("no permission for exit take over")
 		}
+		sys.ExitTakeOver()
 	default:
-		return accountmanager.ErrUnkownTxType
-	}
-	accountDB, err := accountmanager.NewAccountManager(state)
-	if err != nil {
-		return err
-	}
-	if action.Value().Cmp(big.NewInt(0)) > 0 {
-		accountDB.TransferAsset(action.Sender(), action.Recipient(), action.AssetID(), action.Value())
+		return nil, accountmanager.ErrUnkownTxType
 	}
-	return nil
+	return internalActions, nil
 }
diff --git a/consensus/dpos/vote.go b/consensus/dpos/vote.go
index eac7a4fd..9af1858d 100644
--- a/consensus/dpos/vote.go
+++ b/consensus/dpos/vote.go
@@ -21,6 +21,8 @@ import (
 	"math/big"
 	"math/rand"
 	"strings"
+
+	"github.com/fractalplatform/fractal/state"
 )
 
 type System struct {
@@ -28,8 +30,20 @@ type System struct {
 	IDB
 }
 
-// RegProducer  register a producer
-func (sys *System) RegProducer(producer string, url string, stake *big.Int) error {
+func NewSystem(state *state.StateDB, config *Config) *System {
+	return &System{
+		config: config,
+		IDB: &LDB{
+			IDatabase: &stateDB{
+				name:  config.AccountName,
+				state: state,
+			},
+		},
+	}
+}
+
+// RegCadidate  register a cadidate
+func (sys *System) RegCadidate(cadidate string, url string, stake *big.Int) error {
 	// parameter validity
 	if uint64(len(url)) > sys.config.MaxURLLen {
 		return fmt.Errorf("invalid url %v(too long, max %v)", url, sys.config.MaxURLLen)
@@ -39,24 +53,24 @@ func (sys *System) RegProducer(producer string, url string, stake *big.Int) erro
 	if m.Sign() != 0 {
 		return fmt.Errorf("invalid stake %v(non divisibility, unit %v)", stake, sys.config.unitStake())
 	}
-	if q.Cmp(sys.config.ProducerMinQuantity) < 0 {
-		return fmt.Errorf("invalid stake %v(insufficient, producer min %v)", stake, new(big.Int).Mul(sys.config.ProducerMinQuantity, sys.config.unitStake()))
+	if q.Cmp(sys.config.CadidateMinQuantity) < 0 {
+		return fmt.Errorf("invalid stake %v(insufficient, cadidate min %v)", stake, new(big.Int).Mul(sys.config.CadidateMinQuantity, sys.config.unitStake()))
 	}
 
-	if voter, err := sys.GetVoter(producer); err != nil {
+	if voter, err := sys.GetVoter(cadidate); err != nil {
 		return err
 	} else if voter != nil {
-		return fmt.Errorf("invalid producer %v(alreay vote to %v)", producer, voter.Producer)
+		return fmt.Errorf("invalid cadidate %v(alreay vote to %v)", cadidate, voter.Cadidate)
 	}
-	prod, err := sys.GetProducer(producer)
+	prod, err := sys.GetCadidate(cadidate)
 	if err != nil {
 		return err
 	}
 	if prod != nil {
-		return fmt.Errorf("invalid producer %v(already exist)", producer)
+		return fmt.Errorf("invalid cadidate %v(already exist)", cadidate)
 	}
-	prod = &producerInfo{
-		Name:          producer,
+	prod = &cadidateInfo{
+		Name:          cadidate,
 		Quantity:      big.NewInt(0),
 		TotalQuantity: big.NewInt(0),
 	}
@@ -66,7 +80,7 @@ func (sys *System) RegProducer(producer string, url string, stake *big.Int) erro
 	}
 	gstate.TotalQuantity = new(big.Int).Add(gstate.TotalQuantity, q)
 
-	if err := sys.Delegate(producer, stake); err != nil {
+	if err := sys.Delegate(cadidate, stake); err != nil {
 		return fmt.Errorf("delegate (%v) failed(%v)", stake, err)
 	}
 
@@ -74,7 +88,7 @@ func (sys *System) RegProducer(producer string, url string, stake *big.Int) erro
 	prod.Quantity = new(big.Int).Add(prod.Quantity, q)
 	prod.TotalQuantity = new(big.Int).Add(prod.TotalQuantity, q)
 	prod.Height = gstate.Height
-	if err := sys.SetProducer(prod); err != nil {
+	if err := sys.SetCadidate(prod); err != nil {
 		return err
 	}
 	if err := sys.SetState(gstate); err != nil {
@@ -83,8 +97,8 @@ func (sys *System) RegProducer(producer string, url string, stake *big.Int) erro
 	return nil
 }
 
-// UpdateProducer  update a producer
-func (sys *System) UpdateProducer(producer string, url string, stake *big.Int) error {
+// UpdateCadidate  update a cadidate
+func (sys *System) UpdateCadidate(cadidate string, url string, stake *big.Int) error {
 	// parameter validity
 	if uint64(len(url)) > sys.config.MaxURLLen {
 		return fmt.Errorf("invalid url %v(too long, max %v)", url, sys.config.MaxURLLen)
@@ -94,16 +108,16 @@ func (sys *System) UpdateProducer(producer string, url string, stake *big.Int) e
 	if m.Sign() != 0 {
 		return fmt.Errorf("invalid stake %v(non divisibility, unit %v)", stake, sys.config.unitStake())
 	}
-	if q.Cmp(sys.config.ProducerMinQuantity) < 0 {
-		return fmt.Errorf("invalid stake %v(insufficient, producer min %v)", stake, new(big.Int).Mul(sys.config.ProducerMinQuantity, sys.config.unitStake()))
+	if q.Cmp(sys.config.CadidateMinQuantity) < 0 {
+		return fmt.Errorf("invalid stake %v(insufficient, cadidate min %v)", stake, new(big.Int).Mul(sys.config.CadidateMinQuantity, sys.config.unitStake()))
 	}
 
-	prod, err := sys.GetProducer(producer)
+	prod, err := sys.GetCadidate(cadidate)
 	if err != nil {
 		return err
 	}
 	if prod == nil {
-		return fmt.Errorf("invalid producer %v(not exist)", producer)
+		return fmt.Errorf("invalid cadidate %v(not exist)", cadidate)
 	}
 
 	q = new(big.Int).Sub(q, prod.Quantity)
@@ -112,7 +126,7 @@ func (sys *System) UpdateProducer(producer string, url string, stake *big.Int) e
 	if err != nil {
 		return err
 	}
-	if sys.isdpos() && new(big.Int).Add(gstate.TotalQuantity, q).Cmp(sys.config.ActivatedMinQuantity) < 0 {
+	if sys.isdpos(gstate) && new(big.Int).Add(gstate.TotalQuantity, q).Cmp(sys.config.ActivatedMinQuantity) < 0 {
 		return fmt.Errorf("insufficient actived stake")
 	}
 	gstate.TotalQuantity = new(big.Int).Add(gstate.TotalQuantity, q)
@@ -120,11 +134,11 @@ func (sys *System) UpdateProducer(producer string, url string, stake *big.Int) e
 	tstake := new(big.Int).Mul(q, sys.config.unitStake())
 	if q.Sign() < 0 {
 		tstake = new(big.Int).Abs(tstake)
-		if err := sys.Undelegate(producer, tstake); err != nil {
+		if err := sys.Undelegate(cadidate, tstake); err != nil {
 			return fmt.Errorf("undelegate %v failed(%v)", q, err)
 		}
 	} else {
-		if err := sys.Delegate(producer, tstake); err != nil {
+		if err := sys.Delegate(cadidate, tstake); err != nil {
 			return fmt.Errorf("delegate (%v) failed(%v)", q, err)
 		}
 	}
@@ -134,7 +148,7 @@ func (sys *System) UpdateProducer(producer string, url string, stake *big.Int) e
 	}
 	prod.Quantity = new(big.Int).Add(prod.Quantity, q)
 	prod.TotalQuantity = new(big.Int).Add(prod.TotalQuantity, q)
-	if err := sys.SetProducer(prod); err != nil {
+	if err := sys.SetCadidate(prod); err != nil {
 		return err
 	}
 	if err := sys.SetState(gstate); err != nil {
@@ -143,64 +157,72 @@ func (sys *System) UpdateProducer(producer string, url string, stake *big.Int) e
 	return nil
 }
 
-// UnregProducer  unregister a producer
-func (sys *System) UnregProducer(producer string) error {
+// UnregCadidate  unregister a cadidate
+func (sys *System) UnregCadidate(cadidate string) (*big.Int, error) {
 	// parameter validity
 	// modify or update
-	prod, err := sys.GetProducer(producer)
+	var stake *big.Int
+	prod, err := sys.GetCadidate(cadidate)
 	if err != nil {
-		return err
+		return nil, err
 	}
 	if prod != nil {
 
 		gstate, err := sys.GetState(LastBlockHeight)
 		if err != nil {
-			return err
+			return nil, err
 		}
-		if sys.isdpos() {
-			if cnt, err := sys.ProducersSize(); err != nil {
-				return err
+		if sys.isdpos(gstate) {
+			if cnt, err := sys.CadidatesSize(); err != nil {
+				return nil, err
 			} else if uint64(cnt) <= sys.config.consensusSize() {
-				return fmt.Errorf("insufficient actived producers")
+				return nil, fmt.Errorf("insufficient actived cadidates")
 			}
 			if new(big.Int).Sub(gstate.TotalQuantity, prod.TotalQuantity).Cmp(sys.config.ActivatedMinQuantity) < 0 {
-				return fmt.Errorf("insufficient actived stake")
+				return nil, fmt.Errorf("insufficient actived stake")
 			}
 		}
 
-		// voters, err := sys.GetDelegators(producer)
+		// voters, err := sys.GetDelegators(cadidate)
 		// if err != nil {
 		// 	return err
 		// }
 		// for _, voter := range voters {
-		// 	if err := sys.unvoteProducer(voter); err != nil {
+		// 	if err := sys.unvoteCadidate(voter); err != nil {
 		// 		return err
 		// 	}
 		// }
 
 		if prod.TotalQuantity.Cmp(prod.Quantity) > 0 {
-			return fmt.Errorf("already has voter")
+			return nil, fmt.Errorf("already has voter")
 		}
 
-		stake := new(big.Int).Mul(prod.Quantity, sys.config.unitStake())
-		if err := sys.Undelegate(producer, stake); err != nil {
-			return fmt.Errorf("undelegate %v failed(%v)", stake, err)
+		stake = new(big.Int).Mul(prod.Quantity, sys.config.unitStake())
+		if err := sys.Undelegate(cadidate, stake); err != nil {
+			return nil, fmt.Errorf("undelegate %v failed(%v)", stake, err)
 		}
-		if err := sys.DelProducer(prod.Name); err != nil {
-			return err
+		if prod.InBlackList {
+			if err := sys.SetCadidate(prod); err != nil {
+				return nil, err
+			}
+		} else {
+			if err := sys.DelCadidate(prod.Name); err != nil {
+				return nil, err
+			}
 		}
+
 		gstate.TotalQuantity = new(big.Int).Sub(gstate.TotalQuantity, prod.Quantity)
 		if err := sys.SetState(gstate); err != nil {
-			return err
+			return nil, err
 		}
 	} else {
-		return fmt.Errorf("invalide producer %v", producer)
+		return nil, fmt.Errorf("invalide cadidate %v", cadidate)
 	}
-	return nil
+	return stake, nil
 }
 
-// VoteProducer vote a producer
-func (sys *System) VoteProducer(voter string, producer string, stake *big.Int) error {
+// VoteCadidate vote a cadidate
+func (sys *System) VoteCadidate(voter string, cadidate string, stake *big.Int) error {
 	// parameter validity
 	m := big.NewInt(0)
 	q, _ := new(big.Int).DivMod(stake, sys.config.unitStake(), m)
@@ -211,22 +233,22 @@ func (sys *System) VoteProducer(voter string, producer string, stake *big.Int) e
 		return fmt.Errorf("invalid stake %v(insufficient, voter min %v)", stake, new(big.Int).Mul(sys.config.VoterMinQuantity, sys.config.unitStake()))
 	}
 
-	if prod, err := sys.GetProducer(voter); err != nil {
+	if prod, err := sys.GetCadidate(voter); err != nil {
 		return err
 	} else if prod != nil {
-		return fmt.Errorf("invalid vote(alreay is producer)")
+		return fmt.Errorf("invalid vote(alreay is cadidate)")
 	}
 	if vote, err := sys.GetVoter(voter); err != nil {
 		return err
 	} else if vote != nil {
-		return fmt.Errorf("invalid vote(already voted to producer %v)", vote.Producer)
+		return fmt.Errorf("invalid vote(already voted to cadidate %v)", vote.Cadidate)
 	}
-	prod, err := sys.GetProducer(producer)
+	prod, err := sys.GetCadidate(cadidate)
 	if err != nil {
 		return err
 	}
 	if prod == nil {
-		return fmt.Errorf("invalid vote(invalid producers %v)", producer)
+		return fmt.Errorf("invalid vote(invalid cadidates %v)", cadidate)
 	}
 
 	// modify or update
@@ -242,14 +264,14 @@ func (sys *System) VoteProducer(voter string, producer string, stake *big.Int) e
 	prod.TotalQuantity = new(big.Int).Add(prod.TotalQuantity, q)
 	vote := &voterInfo{
 		Name:     voter,
-		Producer: producer,
+		Cadidate: cadidate,
 		Quantity: q,
 		Height:   gstate.Height,
 	}
 	if err := sys.SetVoter(vote); err != nil {
 		return err
 	}
-	if err := sys.SetProducer(prod); err != nil {
+	if err := sys.SetCadidate(prod); err != nil {
 		return err
 	}
 	if err := sys.SetState(gstate); err != nil {
@@ -258,8 +280,8 @@ func (sys *System) VoteProducer(voter string, producer string, stake *big.Int) e
 	return nil
 }
 
-// ChangeProducer change a producer
-func (sys *System) ChangeProducer(voter string, producer string) error {
+// ChangeCadidate change a cadidate
+func (sys *System) ChangeCadidate(voter string, cadidate string) error {
 	// parameter validity
 	vote, err := sys.GetVoter(voter)
 	if err != nil {
@@ -268,99 +290,139 @@ func (sys *System) ChangeProducer(voter string, producer string) error {
 	if vote == nil {
 		return fmt.Errorf("invalid voter %v", voter)
 	}
-	if strings.Compare(vote.Producer, producer) == 0 {
-		return fmt.Errorf("same producer")
+	if strings.Compare(vote.Cadidate, cadidate) == 0 {
+		return fmt.Errorf("same cadidate")
 	}
-	prod, err := sys.GetProducer(producer)
+	prod, err := sys.GetCadidate(cadidate)
 	if err != nil {
 		return err
 	}
 	if prod == nil {
-		return fmt.Errorf("invalid producer %v", producer)
+		return fmt.Errorf("invalid cadidate %v", cadidate)
 	}
 
 	// modify or update
-	oprod, err := sys.GetProducer(vote.Producer)
+	oprod, err := sys.GetCadidate(vote.Cadidate)
 	if err != nil {
 		return err
 	}
 	oprod.TotalQuantity = new(big.Int).Sub(oprod.TotalQuantity, vote.Quantity)
-	if err := sys.SetProducer(oprod); err != nil {
+	if err := sys.SetCadidate(oprod); err != nil {
 		return err
 	}
-	if err := sys.DelVoter(vote.Name, vote.Producer); err != nil {
+	if err := sys.DelVoter(vote.Name, vote.Cadidate); err != nil {
 		return err
 	}
 
-	vote.Producer = prod.Name
+	vote.Cadidate = prod.Name
 	prod.TotalQuantity = new(big.Int).Add(prod.TotalQuantity, vote.Quantity)
 	if err := sys.SetVoter(vote); err != nil {
 		return err
 	}
-	if err := sys.SetProducer(prod); err != nil {
+	if err := sys.SetCadidate(prod); err != nil {
 		return err
 	}
 	return nil
 }
 
-// UnvoteProducer cancel vote
-func (sys *System) UnvoteProducer(voter string) error {
+// UnvoteCadidate cancel vote
+func (sys *System) UnvoteCadidate(voter string) (*big.Int, error) {
 	// parameter validity
-	return sys.unvoteProducer(voter)
+	return sys.unvoteCadidate(voter)
 }
 
 // UnvoteVoter cancel voter
-func (sys *System) UnvoteVoter(producer string, voter string) error {
+func (sys *System) UnvoteVoter(cadidate string, voter string) (*big.Int, error) {
 	// parameter validity
 	vote, err := sys.GetVoter(voter)
 	if err != nil {
-		return err
+		return nil, err
 	}
 	if vote == nil {
-		return fmt.Errorf("invalid voter %v", voter)
+		return nil, fmt.Errorf("invalid voter %v", voter)
+	}
+	if strings.Compare(cadidate, vote.Cadidate) != 0 {
+		return nil, fmt.Errorf("invalid cadidate %v", cadidate)
+	}
+	return sys.unvoteCadidate(voter)
+}
+
+func (sys *System) GetDelegatedByTime(name string, timestamp uint64) (*big.Int, *big.Int, uint64, error) {
+	q, tq, c, err := sys.IDB.GetDelegatedByTime(name, timestamp)
+	if err != nil {
+		return big.NewInt(0), big.NewInt(0), 0, err
+	}
+	return new(big.Int).Mul(q, sys.config.unitStake()), new(big.Int).Mul(tq, sys.config.unitStake()), c, nil
+}
+
+func (sys *System) KickedCadidate(cadidate string) error {
+	prod, err := sys.GetCadidate(cadidate)
+	if prod != nil {
+		if err := sys.Undelegate(sys.config.SystemName, new(big.Int).Mul(prod.Quantity, sys.config.unitStake())); err != nil {
+			return err
+		}
+		state, err := sys.GetState(LastBlockHeight)
+		if err != nil {
+			return err
+		}
+		state.TotalQuantity = new(big.Int).Sub(state.TotalQuantity, prod.Quantity)
+		prod.TotalQuantity = new(big.Int).Sub(prod.TotalQuantity, prod.Quantity)
+		prod.Quantity = big.NewInt(0)
+		prod.InBlackList = true
+		if err := sys.SetState(state); err != nil {
+			return err
+		}
+		return sys.SetCadidate(prod)
 	}
-	if strings.Compare(producer, vote.Producer) != 0 {
-		return fmt.Errorf("invalid producer %v", producer)
+	return err
+}
+
+func (sys *System) ExitTakeOver() error {
+	latest, err := sys.GetState(LastBlockHeight)
+	if latest != nil {
+		latest.TakeOver = false
+		return sys.SetState(latest)
 	}
-	return sys.unvoteProducer(voter)
+	return err
 }
 
-func (sys *System) unvoteProducer(voter string) error {
+func (sys *System) unvoteCadidate(voter string) (*big.Int, error) {
 	// modify or update
+	var stake *big.Int
 	vote, err := sys.GetVoter(voter)
 	if err != nil {
-		return err
+		return nil, err
 	}
 	if vote == nil {
-		return fmt.Errorf("invalid voter %v", voter)
+		return nil, fmt.Errorf("invalid voter %v", voter)
 	}
 	gstate, err := sys.GetState(LastBlockHeight)
 	if err != nil {
-		return err
+		return nil, err
 	}
-	if sys.isdpos() && new(big.Int).Sub(gstate.TotalQuantity, vote.Quantity).Cmp(sys.config.ActivatedMinQuantity) < 0 {
-		return fmt.Errorf("insufficient actived stake")
+	if sys.isdpos(gstate) && new(big.Int).Sub(gstate.TotalQuantity, vote.Quantity).Cmp(sys.config.ActivatedMinQuantity) < 0 {
+		return nil, fmt.Errorf("insufficient actived stake")
 	}
-	stake := new(big.Int).Mul(vote.Quantity, sys.config.unitStake())
+	stake = new(big.Int).Mul(vote.Quantity, sys.config.unitStake())
 	if err := sys.Undelegate(voter, stake); err != nil {
-		return fmt.Errorf("undelegate %v failed(%v)", stake, err)
+		return nil, fmt.Errorf("undelegate %v failed(%v)", stake, err)
 	}
 	gstate.TotalQuantity = new(big.Int).Sub(gstate.TotalQuantity, vote.Quantity)
-	prod, err := sys.GetProducer(vote.Producer)
+	prod, err := sys.GetCadidate(vote.Cadidate)
 	if err != nil {
-		return err
+		return nil, err
 	}
 	prod.TotalQuantity = new(big.Int).Sub(prod.TotalQuantity, vote.Quantity)
-	if err := sys.SetProducer(prod); err != nil {
-		return err
+	if err := sys.SetCadidate(prod); err != nil {
+		return nil, err
 	}
-	if err := sys.DelVoter(vote.Name, vote.Producer); err != nil {
-		return err
+	if err := sys.DelVoter(vote.Name, vote.Cadidate); err != nil {
+		return nil, err
 	}
 	if err := sys.SetState(gstate); err != nil {
-		return err
+		return nil, err
 	}
-	return nil
+	return stake, nil
 }
 
 func (sys *System) onblock(height uint64) error {
@@ -370,70 +432,72 @@ func (sys *System) onblock(height uint64) error {
 	}
 	ngstate := &globalState{
 		Height:                          height + 1,
-		ActivatedProducerSchedule:       gstate.ActivatedProducerSchedule,
-		ActivatedProducerScheduleUpdate: gstate.ActivatedProducerScheduleUpdate,
+		ActivatedCadidateSchedule:       gstate.ActivatedCadidateSchedule,
+		ActivatedCadidateScheduleUpdate: gstate.ActivatedCadidateScheduleUpdate,
 		ActivatedTotalQuantity:          gstate.ActivatedTotalQuantity,
 		TotalQuantity:                   new(big.Int).SetBytes(gstate.TotalQuantity.Bytes()),
+		TakeOver:                        gstate.TakeOver,
 	}
 	sys.SetState(ngstate)
 	return nil
 }
 
-func (sys *System) updateElectedProducers(timestamp uint64) error {
+func (sys *System) updateElectedCadidates(timestamp uint64) error {
 	gstate, err := sys.GetState(LastBlockHeight)
 	if err != nil {
 		return err
 	}
 
-	size, _ := sys.ProducersSize()
+	size, _ := sys.CadidatesSize()
 	if gstate.TotalQuantity.Cmp(sys.config.ActivatedMinQuantity) < 0 || uint64(size) < sys.config.consensusSize() {
-		activatedProducerSchedule := []string{}
+		activatedCadidateSchedule := []string{}
 		activeTotalQuantity := big.NewInt(0)
-		producer, _ := sys.GetProducer(sys.config.SystemName)
-		for i := uint64(0); i < sys.config.ProducerScheduleSize; i++ {
-			activatedProducerSchedule = append(activatedProducerSchedule, sys.config.SystemName)
-			activeTotalQuantity = new(big.Int).Add(activeTotalQuantity, producer.TotalQuantity)
+		cadidate, _ := sys.GetCadidate(sys.config.SystemName)
+		for i := uint64(0); i < sys.config.CadidateScheduleSize; i++ {
+			activatedCadidateSchedule = append(activatedCadidateSchedule, sys.config.SystemName)
+			activeTotalQuantity = new(big.Int).Add(activeTotalQuantity, cadidate.TotalQuantity)
 		}
-		gstate.ActivatedProducerSchedule = activatedProducerSchedule
-		gstate.ActivatedProducerScheduleUpdate = timestamp
+		gstate.ActivatedCadidateSchedule = activatedCadidateSchedule
+		gstate.ActivatedCadidateScheduleUpdate = timestamp
 		gstate.ActivatedTotalQuantity = activeTotalQuantity
 		return sys.SetState(gstate)
 	}
 
-	producers, err := sys.Producers()
+	cadidates, err := sys.Cadidates()
 	if err != nil {
 		return err
 	}
-	activatedProducerSchedule := []string{}
+	activatedCadidateSchedule := []string{}
 	activeTotalQuantity := big.NewInt(0)
-	for index, producer := range producers {
-		if uint64(index) >= sys.config.ProducerScheduleSize {
+	for _, cadidate := range cadidates {
+		if cadidate.InBlackList || strings.Compare(cadidate.Name, sys.config.SystemName) == 0 {
+			continue
+		}
+		activatedCadidateSchedule = append(activatedCadidateSchedule, cadidate.Name)
+		activeTotalQuantity = new(big.Int).Add(activeTotalQuantity, cadidate.TotalQuantity)
+		if uint64(len(activatedCadidateSchedule)) == sys.config.CadidateScheduleSize {
 			break
 		}
-		activatedProducerSchedule = append(activatedProducerSchedule, producer.Name)
-		activeTotalQuantity = new(big.Int).Add(activeTotalQuantity, producer.TotalQuantity)
 	}
 
 	seed := int64(timestamp)
 	r := rand.New(rand.NewSource(seed))
-	for i := len(activatedProducerSchedule) - 1; i > 0; i-- {
+	for i := len(activatedCadidateSchedule) - 1; i > 0; i-- {
 		j := int(r.Int31n(int32(i + 1)))
-		activatedProducerSchedule[i], activatedProducerSchedule[j] = activatedProducerSchedule[j], activatedProducerSchedule[i]
+		activatedCadidateSchedule[i], activatedCadidateSchedule[j] = activatedCadidateSchedule[j], activatedCadidateSchedule[i]
 	}
 
-	gstate.ActivatedProducerSchedule = activatedProducerSchedule
-	gstate.ActivatedProducerScheduleUpdate = timestamp
+	gstate.ActivatedCadidateSchedule = activatedCadidateSchedule
+	gstate.ActivatedCadidateScheduleUpdate = timestamp
 	gstate.ActivatedTotalQuantity = activeTotalQuantity
 	return sys.SetState(gstate)
 }
 
-func (sys *System) isdpos() bool {
-	if size, _ := sys.ProducersSize(); uint64(size) < sys.config.consensusSize() {
-		return false
-	}
-	gstate, _ := sys.GetState(LastBlockHeight)
-	if gstate.TotalQuantity.Cmp(sys.config.ActivatedMinQuantity) < 0 {
-		return false
+func (sys *System) isdpos(gstate *globalState) bool {
+	for _, cadidate := range gstate.ActivatedCadidateSchedule {
+		if strings.Compare(cadidate, sys.config.SystemName) != 0 {
+			return true
+		}
 	}
-	return true
+	return false
 }
diff --git a/consensus/dpos/vote_test.go b/consensus/dpos/vote_test.go
index 4312eb8d..cad3bd78 100644
--- a/consensus/dpos/vote_test.go
+++ b/consensus/dpos/vote_test.go
@@ -22,7 +22,7 @@ import (
 )
 
 var (
-	minproducerstake = big.NewInt(0).Mul(DefaultConfig.unitStake(), DefaultConfig.ProducerMinQuantity)
+	mincadidatestake = big.NewInt(0).Mul(DefaultConfig.unitStake(), DefaultConfig.CadidateMinQuantity)
 	minvoterstake    = big.NewInt(0).Mul(DefaultConfig.unitStake(), DefaultConfig.VoterMinQuantity)
 	big1             = big.NewInt(1)
 )
@@ -43,157 +43,157 @@ func TestVote(t *testing.T) {
 		ActivatedTotalQuantity: big.NewInt(0),
 	})
 
-	// RegProducer
-	producer := "testproducer"
+	// RegCadidate
+	cadidate := "testcadidate"
 	url := "testurl"
-	stake := big.NewInt(0).Sub(minproducerstake, big1)
+	stake := big.NewInt(0).Sub(mincadidatestake, big1)
 
-	if err := dpos.UnregProducer(producer); err == nil {
-		t.Errorf("UnregProducer should failed --- %v", err)
+	if _, err := dpos.UnregCadidate(cadidate); err == nil {
+		t.Errorf("UnregCadidate should failed --- %v", err)
 	}
 
-	err = dpos.RegProducer(producer, url, stake)
+	err = dpos.RegCadidate(cadidate, url, stake)
 	if err == nil {
-		t.Errorf("RegProducer should failed --- %v", err)
+		t.Errorf("RegCadidate should failed --- %v", err)
 	}
 
-	if err := dpos.UnregProducer(producer); err == nil {
-		t.Errorf("UnregProducer should failed --- %v", err)
+	if _, err := dpos.UnregCadidate(cadidate); err == nil {
+		t.Errorf("UnregCadidate should failed --- %v", err)
 	}
 
-	err = dpos.RegProducer(producer, url, minproducerstake)
+	err = dpos.RegCadidate(cadidate, url, mincadidatestake)
 	if nil != err {
-		t.Errorf("RegProducer failed --- %v", err)
+		t.Errorf("RegCadidate failed --- %v", err)
 	}
 
-	if gstate, err := dpos.GetState(LastBlockHeight); err != nil || gstate.TotalQuantity.Cmp(DefaultConfig.ProducerMinQuantity) != 0 {
-		t.Errorf("gstate totalQuantity mismatch --- %v(%v, %v)", err, gstate.TotalQuantity, DefaultConfig.ProducerMinQuantity)
+	if gstate, err := dpos.GetState(LastBlockHeight); err != nil || gstate.TotalQuantity.Cmp(DefaultConfig.CadidateMinQuantity) != 0 {
+		t.Errorf("gstate totalQuantity mismatch --- %v(%v, %v)", err, gstate.TotalQuantity, DefaultConfig.CadidateMinQuantity)
 	}
 
-	// GetProducer
-	if prod, err := dpos.GetProducer(producer); err != nil {
-		t.Errorf("GetProducer failed --- %v", err)
-	} else if prod.Name != producer || prod.URL != url || prod.Quantity.Cmp(DefaultConfig.ProducerMinQuantity) != 0 || prod.Quantity.Cmp(prod.TotalQuantity) != 0 {
-		t.Errorf("producer info not match")
+	// GetCadidate
+	if prod, err := dpos.GetCadidate(cadidate); err != nil {
+		t.Errorf("GetCadidate failed --- %v", err)
+	} else if prod.Name != cadidate || prod.URL != url || prod.Quantity.Cmp(DefaultConfig.CadidateMinQuantity) != 0 || prod.Quantity.Cmp(prod.TotalQuantity) != 0 {
+		t.Errorf("cadidate info not match")
 	}
 
-	// Producers
-	if prods, err := dpos.Producers(); err != nil || len(prods) != 1 {
-		t.Errorf("producers mismatch")
+	// Cadidates
+	if prods, err := dpos.Cadidates(); err != nil || len(prods) != 1 {
+		t.Errorf("cadidates mismatch")
 	}
 
-	// ProducersSize
-	if size, err := dpos.ProducersSize(); err != nil || size != 1 {
-		t.Errorf("producers mismatch")
+	// CadidatesSize
+	if size, err := dpos.CadidatesSize(); err != nil || size != 1 {
+		t.Errorf("cadidates mismatch")
 	}
 
-	// VoteProducer
+	// VoteCadidate
 	voter := "testvoter"
 	vstake := big.NewInt(0).Sub(minvoterstake, big1)
-	err = dpos.VoteProducer(voter, producer, vstake)
+	err = dpos.VoteCadidate(voter, cadidate, vstake)
 	if err == nil {
-		t.Errorf("VoteProducer should failed --- %v", err)
+		t.Errorf("VoteCadidate should failed --- %v", err)
 	}
 
-	err = dpos.VoteProducer(voter, producer, minvoterstake)
+	err = dpos.VoteCadidate(voter, cadidate, minvoterstake)
 	if nil != err {
-		t.Errorf("VoterProducer failed --- %v", err)
+		t.Errorf("VoterCadidate failed --- %v", err)
 	}
 
-	prod, _ := dpos.GetProducer(producer)
+	prod, _ := dpos.GetCadidate(cadidate)
 	gstate, _ := dpos.GetState(LastBlockHeight)
 	if prod.TotalQuantity.Cmp(gstate.TotalQuantity) != 0 {
 		t.Errorf("gstate totalQuantity mismatch --- %v(%v, %v)", err, gstate.TotalQuantity, prod.TotalQuantity)
 	} else if new(big.Int).Sub(prod.TotalQuantity, prod.Quantity).Cmp(DefaultConfig.VoterMinQuantity) != 0 {
-		t.Errorf("producer totalQuantity mismatch --- %v(%v, %v)", err, prod.TotalQuantity, prod.Quantity)
+		t.Errorf("cadidate totalQuantity mismatch --- %v(%v, %v)", err, prod.TotalQuantity, prod.Quantity)
 	}
 
 	// GetVoter
 	if vote, err := dpos.GetVoter(voter); err != nil {
 		t.Errorf("GetVoter failed --- %v", err)
-	} else if vote.Name != voter || vote.Producer != producer || vote.Quantity.Cmp(DefaultConfig.VoterMinQuantity) != 0 {
+	} else if vote.Name != voter || vote.Cadidate != cadidate || vote.Quantity.Cmp(DefaultConfig.VoterMinQuantity) != 0 {
 		t.Errorf("voter info not match --- %v", err)
 	}
 
-	// voter cant reg producer
-	err = dpos.RegProducer(voter, url, minproducerstake)
-	if err.Error() != "invalid producer testvoter(alreay vote to testproducer)" {
+	// voter cant reg cadidate
+	err = dpos.RegCadidate(voter, url, mincadidatestake)
+	if err.Error() != "invalid cadidate testvoter(alreay vote to testcadidate)" {
 		t.Errorf("wrong err type --- %v", err)
 	}
 
 	// test change
-	producer2 := "testproducer2"
+	cadidate2 := "testcadidate2"
 	url2 := "testurl2"
-	dpos.RegProducer(producer2, url2, minproducerstake)
-	// Producers
-	if prods, err := dpos.Producers(); err != nil || len(prods) != 2 {
-		t.Errorf("producers mismatch")
+	dpos.RegCadidate(cadidate2, url2, mincadidatestake)
+	// Cadidates
+	if prods, err := dpos.Cadidates(); err != nil || len(prods) != 2 {
+		t.Errorf("cadidates mismatch")
 	}
 
-	if err := dpos.ChangeProducer(voter, producer2); err != nil {
-		t.Errorf("ChangeProducer failed --- %v", err)
+	if err := dpos.ChangeCadidate(voter, cadidate2); err != nil {
+		t.Errorf("ChangeCadidate failed --- %v", err)
 	}
 
 	vote, _ := dpos.GetVoter(voter)
-	prod, _ = dpos.GetProducer(producer)
-	prod2, _ := dpos.GetProducer(producer2)
+	prod, _ = dpos.GetCadidate(cadidate)
+	prod2, _ := dpos.GetCadidate(cadidate2)
 	gstate, _ = dpos.GetState(LastBlockHeight)
 
-	if vote.Producer != prod2.Name || vote.Quantity.Cmp(DefaultConfig.VoterMinQuantity) != 0 ||
+	if vote.Cadidate != prod2.Name || vote.Quantity.Cmp(DefaultConfig.VoterMinQuantity) != 0 ||
 		prod.Quantity.Cmp(prod.TotalQuantity) != 0 || new(big.Int).Add(prod.TotalQuantity, prod2.TotalQuantity).Cmp(gstate.TotalQuantity) != 0 {
 		t.Log(prod2.TotalQuantity, gstate.TotalQuantity)
 		t.Error("Change stake not work")
 	}
 
-	if err := dpos.UnvoteProducer(voter); err != nil {
-		t.Errorf("UnvoteProducer failed --- %v", err)
+	if _, err := dpos.UnvoteCadidate(voter); err != nil {
+		t.Errorf("UnvoteCadidate failed --- %v", err)
 	} else if vote, err := dpos.GetVoter(voter); err != nil || vote != nil {
-		t.Errorf("UnvoteProducer failed --- %v", err)
+		t.Errorf("UnvoteCadidate failed --- %v", err)
 	}
-	prod2, _ = dpos.GetProducer(producer2)
+	prod2, _ = dpos.GetCadidate(cadidate2)
 	gstate, _ = dpos.GetState(LastBlockHeight)
 	if prod.Quantity.Cmp(prod.TotalQuantity) != 0 ||
 		prod2.Quantity.Cmp(prod2.TotalQuantity) != 0 || new(big.Int).Add(prod.TotalQuantity, prod2.TotalQuantity).Cmp(gstate.TotalQuantity) != 0 {
-		t.Errorf("UnvoteProducer failed")
+		t.Errorf("UnvoteCadidate failed")
 	}
 
-	if err := dpos.UnregProducer(producer); err != nil {
-		t.Errorf("UnregProducer failed --- %v", err)
-	} else if prod, err := dpos.GetProducer(producer); err != nil || prod != nil {
-		t.Errorf("UnregProducer failed --- %v", err)
+	if _, err := dpos.UnregCadidate(cadidate); err != nil {
+		t.Errorf("UnregCadidate failed --- %v", err)
+	} else if prod, err := dpos.GetCadidate(cadidate); err != nil || prod != nil {
+		t.Errorf("UnregCadidate failed --- %v", err)
 	} else if gstate, _ = dpos.GetState(LastBlockHeight); prod2.TotalQuantity.Cmp(gstate.TotalQuantity) != 0 {
-		t.Errorf("UnvoteProducer failed mismatch %v %v", prod2.TotalQuantity, gstate.TotalQuantity)
+		t.Errorf("UnvoteCadidate failed mismatch %v %v", prod2.TotalQuantity, gstate.TotalQuantity)
 	}
 
 	// activate dpos state
 	DefaultConfig.safeSize.Store(uint64(2))
-	pmq2 := big.NewInt(0).Mul(DefaultConfig.ProducerMinQuantity, big.NewInt(2))
+	pmq2 := big.NewInt(0).Mul(DefaultConfig.CadidateMinQuantity, big.NewInt(2))
 	DefaultConfig.ActivatedMinQuantity = big.NewInt(0).Add(pmq2, big1)
 
-	err = dpos.RegProducer(producer, url, minproducerstake)
+	err = dpos.RegCadidate(cadidate, url, mincadidatestake)
 	if err != nil {
-		t.Errorf("RegProducer err %v", err)
+		t.Errorf("RegCadidate err %v", err)
 	}
 
 	// register again
-	err = dpos.RegProducer(producer, url, minproducerstake)
-	if err.Error() != "invalid producer testproducer(already exist)" {
+	err = dpos.RegCadidate(cadidate, url, mincadidatestake)
+	if err.Error() != "invalid cadidate testcadidate(already exist)" {
 		t.Errorf("wrong err: %v", err)
 	}
 
-	err = dpos.VoteProducer(voter, producer, minvoterstake)
+	err = dpos.VoteCadidate(voter, cadidate, minvoterstake)
 	if nil != err {
-		t.Errorf("VoterProducer failed --- %v", err)
+		t.Errorf("VoterCadidate failed --- %v", err)
 	}
 
 	//t.Log(dpos.isdpos())
-	err = dpos.UnregProducer(producer)
-	if err == nil || err.Error() != "insufficient actived producers" {
+	_, err = dpos.UnregCadidate(cadidate)
+	if err.Error() != "already has voter" {
 		t.Errorf("wrong err: %v", err)
 	}
 
-	err = dpos.UnvoteProducer(voter)
-	if err == nil || err.Error() != "insufficient actived stake" {
+	_, err = dpos.UnvoteCadidate(voter)
+	if err != nil {
 		t.Errorf("wrong err: %v", err)
 	}
 }
diff --git a/consensus/miner/api.go b/consensus/miner/api.go
index 98ae4831..59ce7fc6 100644
--- a/consensus/miner/api.go
+++ b/consensus/miner/api.go
@@ -28,13 +28,15 @@ type API struct {
 }
 
 func (api *API) Start() bool {
-	api.miner.Start()
-	return true
+	return api.miner.Start(false)
+}
+
+func (api *API) Force() bool {
+	return api.miner.Start(true)
 }
 
 func (api *API) Stop() bool {
-	api.miner.Stop()
-	return true
+	return api.miner.Stop()
 }
 
 func (api *API) Mining() bool {
diff --git a/consensus/miner/miner.go b/consensus/miner/miner.go
index c819c1e5..a9f2c2a3 100644
--- a/consensus/miner/miner.go
+++ b/consensus/miner/miner.go
@@ -85,29 +85,31 @@ func (miner *Miner) update() {
 }
 
 // Start start worker
-func (miner *Miner) Start() {
+func (miner *Miner) Start(force bool) bool {
 	atomic.StoreInt32(&miner.shouldStart, 1)
 	if atomic.LoadInt32(&miner.canStart) == 0 {
 		log.Error("Network syncing, will start miner afterwards")
-		return
+		return false
 	}
 	if !atomic.CompareAndSwapInt32(&miner.mining, 0, 1) {
 		log.Error("miner already started")
-		return
+		return false
 	}
 	log.Info("Starting mining operation")
-	miner.worker.start()
+	miner.worker.start(force)
+	return true
 }
 
 // Stop stop worker
-func (miner *Miner) Stop() {
+func (miner *Miner) Stop() bool {
 	if !atomic.CompareAndSwapInt32(&miner.mining, 1, 0) {
 		log.Error("miner already stopped")
-		return
+		return false
 	}
 	log.Info("Stopping mining operation")
 	atomic.StoreInt32(&miner.shouldStart, 0)
 	miner.worker.stop()
+	return true
 }
 
 // Mining wroker is wroking
@@ -135,7 +137,7 @@ func (miner *Miner) SetCoinbase(name string, privKeys []string) error {
 		privs = append(privs, priv)
 	}
 
-	if !common.IsValidName(name) {
+	if !common.IsValidAccountName(name) {
 		return fmt.Errorf("invalid name %v", name)
 	}
 
@@ -146,7 +148,7 @@ func (miner *Miner) SetCoinbase(name string, privKeys []string) error {
 // SetExtra extra data
 func (miner *Miner) SetExtra(extra []byte) error {
 	if uint64(len(extra)) > params.MaximumExtraDataSize-65 {
-		err := fmt.Errorf("Extra exceeds max length. %d > %v", len(extra), params.MaximumExtraDataSize)
+		err := fmt.Errorf("Extra exceeds max length. %d > %v", len(extra), params.MaximumExtraDataSize-65)
 		log.Warn("SetExtra", "error", err)
 		return err
 	}
diff --git a/consensus/miner/worker.go b/consensus/miner/worker.go
index 4095712f..f08d65d8 100644
--- a/consensus/miner/worker.go
+++ b/consensus/miner/worker.go
@@ -62,10 +62,12 @@ type Worker struct {
 
 	currentWork *Work
 
+	wg         sync.WaitGroup
 	mining     int32
 	quitWork   chan struct{}
 	quitWorkRW sync.RWMutex
 	quit       chan struct{}
+	force      bool
 }
 
 func newWorker(consensus consensus.IConsensus) *Worker {
@@ -106,6 +108,7 @@ out:
 		case ev := <-txsCh:
 			// Apply transactions to the pending state if we're not mining.
 			if atomic.LoadInt32(&worker.mining) == 0 {
+				worker.wg.Wait()
 				txs := make(map[common.Name][]*types.Transaction)
 				for _, tx := range ev.Data.([]*types.Transaction) {
 					action := tx.GetActions()[0]
@@ -123,15 +126,18 @@ out:
 	}
 }
 
-func (worker *Worker) start() {
+func (worker *Worker) start(force bool) {
 	if !atomic.CompareAndSwapInt32(&worker.mining, 0, 1) {
 		log.Warn("worker already started")
 		return
 	}
+	worker.force = force
 	go worker.mintLoop()
 }
 
 func (worker *Worker) mintLoop() {
+	worker.wg.Add(1)
+	defer worker.wg.Done()
 	dpos, ok := worker.Engine().(*dpos.Dpos)
 	if !ok {
 		panic("only support dpos engine")
@@ -142,7 +148,7 @@ func (worker *Worker) mintLoop() {
 			return nil, err
 		}
 		for index, privKey := range worker.privKeys {
-			if err := accountDB.IsValidSign(common.StrToName(worker.coinbase), types.ActionType(0), common.BytesToPubKey(worker.pubKeys[index])); err == nil {
+			if err := accountDB.IsValidSign(common.StrToName(worker.coinbase), common.BytesToPubKey(worker.pubKeys[index])); err == nil {
 				return crypto.Sign(content, privKey)
 			}
 		}
@@ -187,17 +193,22 @@ func (worker *Worker) mintBlock(timestamp int64, quit chan struct{}) {
 		log.Error("failed to mint block", "timestamp", timestamp, "err", err)
 		return
 	}
-	if err := cdpos.IsValidateProducer(worker, header.Number.Uint64(), uint64(timestamp), worker.coinbase, worker.pubKeys, state); err != nil {
+	if err := cdpos.IsValidateCadidate(worker, header, uint64(timestamp), worker.coinbase, worker.pubKeys, state, worker.force); err != nil {
 		switch err {
-		case dpos.ErrIllegalProducerName:
+		case dpos.ErrSystemTakeOver:
 			fallthrough
-		case dpos.ErrIllegalProducerPubKey:
+		case dpos.ErrTooMuchRreversible:
+			fallthrough
+		case dpos.ErrIllegalCadidateName:
+			fallthrough
+		case dpos.ErrIllegalCadidatePubKey:
 			log.Error("failed to mint the block", "timestamp", timestamp, "err", err)
 		default:
 			log.Debug("failed to mint the block", "timestamp", timestamp, "err", err)
 		}
 		return
 	}
+
 	bstart := time.Now()
 outer:
 
@@ -209,7 +220,7 @@ outer:
 		}
 		block, err := worker.commitNewWork(timestamp, quit)
 		if err == nil {
-			log.Info("Mined new block", "producer", block.Coinbase(), "number", block.Number(), "hash", block.Hash().String(), "time", block.Time().Int64(), "txs", len(block.Txs), "gas", block.GasUsed(), "diff", block.Difficulty(), "elapsed", common.PrettyDuration(time.Since(bstart)))
+			log.Info("Mined new block", "cadidate", block.Coinbase(), "number", block.Number(), "hash", block.Hash().String(), "time", block.Time().Int64(), "txs", len(block.Txs), "gas", block.GasUsed(), "diff", block.Difficulty(), "elapsed", common.PrettyDuration(time.Since(bstart)))
 			break outer
 		}
 		if strings.Contains(err.Error(), "mint") {
@@ -282,8 +293,9 @@ func (worker *Worker) commitNewWork(timestamp int64, quit chan struct{}) (*types
 		Time:       big.NewInt(timestamp),
 		Difficulty: worker.CalcDifficulty(worker.IConsensus, uint64(timestamp), parent),
 	}
-	if common.IsValidName(worker.coinbase) {
+	if common.IsValidAccountName(worker.coinbase) {
 		header.Coinbase = common.StrToName(worker.coinbase)
+		header.ProposedIrreversible = dpos.CalcProposedIrreversible(worker, parent, false)
 	}
 	state, err := worker.StateAt(parent.Root)
 	if err != nil {
@@ -348,7 +360,7 @@ func (worker *Worker) commitNewWork(timestamp int64, quit chan struct{}) (*types
 		if bytes.Compare(block.ParentHash().Bytes(), worker.CurrentHeader().Hash().Bytes()) != 0 {
 			return nil, fmt.Errorf("old parent hash")
 		}
-		if err := worker.WriteBlockWithState(block, work.currentReceipts, work.currentState); err != nil {
+		if _, err := worker.WriteBlockWithState(block, work.currentReceipts, work.currentState); err != nil {
 			return nil, fmt.Errorf("writing block to chain, err: %v", err)
 		}
 
@@ -390,6 +402,16 @@ func (worker *Worker) commitTransactions(work *Work, txs *types.TransactionsByPr
 
 		action := tx.GetActions()[0]
 
+		if strings.Compare(work.currentHeader.Coinbase.String(), worker.Config().SysName) != 0 {
+			switch action.Type() {
+			case types.KickedCadidate:
+				fallthrough
+			case types.ExitTakeOver:
+				continue
+			default:
+			}
+		}
+
 		from := action.Sender()
 		// Start executing the transaction
 		work.currentState.Prepare(tx.Hash(), common.Hash{}, work.currentCnt)
@@ -432,7 +454,7 @@ func (worker *Worker) commitTransactions(work *Work, txs *types.TransactionsByPr
 func (worker *Worker) commitTransaction(work *Work, tx *types.Transaction) ([]*types.Log, error) {
 	snap := work.currentState.Snapshot()
 	var name *common.Name
-	if common.IsValidName(work.currentHeader.Coinbase.String()) {
+	if common.IsValidAccountName(work.currentHeader.Coinbase.String()) {
 		name = new(common.Name)
 		*name = common.StrToName(work.currentHeader.Coinbase.String())
 	}
diff --git a/crypto/signature_nocgo.go b/crypto/signature_nocgo.go
index f90485fd..ec9567c2 100644
--- a/crypto/signature_nocgo.go
+++ b/crypto/signature_nocgo.go
@@ -68,7 +68,6 @@ func Sign(hash []byte, prv *ecdsa.PrivateKey) ([]byte, error) {
 	if err != nil {
 		return nil, err
 	}
-	// Convert to Ethereum signature format with 'recovery id' v at the end.
 	v := sig[0] - 27
 	copy(sig, sig[1:])
 	sig[64] = v
diff --git a/ftservice/apibackend.go b/ftservice/apibackend.go
index 1f10cef1..b22a8294 100644
--- a/ftservice/apibackend.go
+++ b/ftservice/apibackend.go
@@ -34,7 +34,6 @@ import (
 	"github.com/fractalplatform/fractal/state"
 	"github.com/fractalplatform/fractal/types"
 	"github.com/fractalplatform/fractal/utils/fdb"
-	"github.com/fractalplatform/fractal/wallet"
 )
 
 // APIBackend implements ftserviceapi.Backend for full nodes
@@ -114,6 +113,98 @@ func (b *APIBackend) GetReceipts(ctx context.Context, hash common.Hash) ([]*type
 	return nil, nil
 }
 
+func (b *APIBackend) GetDetailTxsLog(ctx context.Context, hash common.Hash) ([]*types.DetailTx, error) {
+	if number := rawdb.ReadHeaderNumber(b.ftservice.chainDb, hash); number != nil {
+		return rawdb.ReadDetailTxs(b.ftservice.chainDb, hash, *number), nil
+	}
+	return nil, nil
+}
+
+func (b *APIBackend) GetBlockDetailLog(ctx context.Context, blockNr rpc.BlockNumber) *types.BlockAndResult {
+	hash := rawdb.ReadCanonicalHash(b.ftservice.chainDb, uint64(blockNr))
+	if hash == (common.Hash{}) {
+		return nil
+	}
+	receipts := rawdb.ReadReceipts(b.ftservice.chainDb, hash, uint64(blockNr))
+	txDetails := rawdb.ReadDetailTxs(b.ftservice.chainDb, hash, uint64(blockNr))
+	return &types.BlockAndResult{
+		Receipts:  receipts,
+		DetailTxs: txDetails,
+	}
+}
+
+func (b *APIBackend) GetTxsByFilter(ctx context.Context, filterFn func(common.Name) bool, blockNr rpc.BlockNumber, lookbackNum uint64) []common.Hash {
+	lastnum := uint64(blockNr) - lookbackNum
+
+	txHashs := make([]common.Hash, 0)
+
+	for ublocknum := uint64(blockNr); ublocknum > lastnum; ublocknum-- {
+
+		hash := rawdb.ReadCanonicalHash(b.ftservice.chainDb, ublocknum)
+		if hash == (common.Hash{}) {
+			continue
+		}
+
+		blockBody := rawdb.ReadBody(b.ftservice.chainDb, hash, ublocknum)
+		if blockBody == nil {
+			continue
+		}
+		batch_txs := blockBody.Transactions
+
+		for _, tx := range batch_txs {
+			for _, act := range tx.GetActions() {
+				if filterFn(act.Sender()) || filterFn(act.Recipient()) {
+					txHashs = append(txHashs, tx.Hash())
+					break
+				}
+			}
+		}
+	}
+
+	return txHashs
+}
+
+func (b *APIBackend) GetDetailTxByFilter(ctx context.Context, filterFn func(common.Name) bool, blockNr rpc.BlockNumber, lookbackNum uint64) []*types.DetailTx {
+	lastnum := uint64(blockNr) - lookbackNum
+
+	txdetails := make([]*types.DetailTx, 0)
+
+	for ublocknum := uint64(blockNr); ublocknum > lastnum; ublocknum-- {
+
+		hash := rawdb.ReadCanonicalHash(b.ftservice.chainDb, ublocknum)
+		if hash == (common.Hash{}) {
+			continue
+		}
+
+		batch_txdetails := rawdb.ReadDetailTxs(b.ftservice.chainDb, hash, ublocknum)
+		for _, txd := range batch_txdetails {
+
+			new_intxs := make([]*types.DetailAction, 0)
+			for _, intx := range txd.Actions {
+				new_inactions := make([]*types.InternalAction, 0)
+				for _, inlog := range intx.InternalActions {
+					if filterFn(inlog.Action.From) || filterFn(inlog.Action.To) {
+						new_inactions = append(new_inactions, inlog)
+					}
+				}
+				if len(new_inactions) > 0 {
+					new_intxs = append(new_intxs, &types.DetailAction{InternalActions: new_inactions})
+				}
+			}
+
+			if len(new_intxs) > 0 {
+				txdetails = append(txdetails, &types.DetailTx{TxHash: txd.TxHash, Actions: new_intxs})
+			}
+		}
+	}
+
+	return txdetails
+}
+
+func (b *APIBackend) GetBadBlocks(ctx context.Context) ([]*types.Block, error) {
+	return b.ftservice.blockchain.BadBlocks(), nil
+}
+
 func (b *APIBackend) GetTd(blockHash common.Hash) *big.Int {
 	return b.ftservice.blockchain.GetTdByHash(blockHash)
 }
@@ -173,8 +264,7 @@ func (b *APIBackend) GetEVM(ctx context.Context, account *accountmanager.Account
 		EgnineContext: b.ftservice.Engine(),
 	}
 
-	fromPubkey := common.PubKey{}
-	context := processor.NewEVMContext(from, fromPubkey, assetID, gasPrice, header, evmcontext, nil)
+	context := processor.NewEVMContext(from, assetID, gasPrice, header, evmcontext, nil)
 	return vm.NewEVM(context, account, state, b.ChainConfig(), vmCfg), vmError, nil
 }
 
@@ -183,10 +273,6 @@ func (b *APIBackend) SetGasPrice(gasPrice *big.Int) bool {
 	return true
 }
 
-func (b *APIBackend) Wallet() *wallet.Wallet {
-	return b.ftservice.Wallet()
-}
-
 func (b *APIBackend) GetAccountManager() (*accountmanager.AccountManager, error) {
 	sdb, err := b.ftservice.blockchain.State()
 	if err != nil {
diff --git a/ftservice/config.go b/ftservice/config.go
index 2bc958c8..f35b23c8 100644
--- a/ftservice/config.go
+++ b/ftservice/config.go
@@ -18,7 +18,6 @@ package ftservice
 
 import (
 	"github.com/fractalplatform/fractal/blockchain"
-	"github.com/fractalplatform/fractal/common"
 	"github.com/fractalplatform/fractal/ftservice/gasprice"
 	"github.com/fractalplatform/fractal/metrics"
 	"github.com/fractalplatform/fractal/txpool"
@@ -31,30 +30,29 @@ type Config struct {
 	Genesis *blockchain.Genesis `toml:",omitempty"`
 
 	// Database options
-	SkipBcVersionCheck bool `mapstructure:"ftservice-skipvcversioncheck"`
-	DatabaseHandles    int  `mapstructure:"ftservice-databasehandles"`
-	DatabaseCache      int  `mapstructure:"ftservice-databasecache"`
+	DatabaseHandles int
+	DatabaseCache   int `mapstructure:"databasecache"`
 
 	// Transaction pool options
-	TxPool *txpool.Config
+	TxPool *txpool.Config `mapstructure:"txpool"`
 
 	// Gas Price Oracle options
-	GasPrice gasprice.Config
+	GasPrice gasprice.Config `mapstructure:"gpo"`
 
 	// miner
-	Miner *MinerConfig
+	Miner *MinerConfig `mapstructure:"miner"`
 
-	CoinBase    common.Address
-	MetricsConf *metrics.Config
+	MetricsConf *metrics.Config `mapstructure:"metrics"`
 
 	// snapshot
-	Snapshot bool
+	Snapshot        bool
+	ContractLogFlag bool `mapstructure:"contractlog"`
 }
 
 // MinerConfig miner config
 type MinerConfig struct {
-	Start       bool     `mapstructure:"miner-start"`
-	Name        string   `mapstructure:"miner-name"`
-	PrivateKeys []string `mapstructure:"miner-private"`
-	ExtraData   string   `mapstructure:"miner-extra"`
+	Start       bool     `mapstructure:"start"`
+	Name        string   `mapstructure:"name"`
+	PrivateKeys []string `mapstructure:"private"`
+	ExtraData   string   `mapstructure:"extra"`
 }
diff --git a/ftservice/ftservice.go b/ftservice/ftservice.go
index 43aecdd6..fee280d0 100644
--- a/ftservice/ftservice.go
+++ b/ftservice/ftservice.go
@@ -17,30 +17,26 @@
 package ftservice
 
 import (
-	"fmt"
 	"math/big"
 	"sync"
 
 	"github.com/ethereum/go-ethereum/log"
-	am "github.com/fractalplatform/fractal/accountmanager"
 	"github.com/fractalplatform/fractal/blockchain"
 	"github.com/fractalplatform/fractal/consensus"
 	"github.com/fractalplatform/fractal/consensus/dpos"
 	"github.com/fractalplatform/fractal/consensus/miner"
 	"github.com/fractalplatform/fractal/ftservice/gasprice"
-	"github.com/fractalplatform/fractal/internal/api"
 	"github.com/fractalplatform/fractal/node"
 	"github.com/fractalplatform/fractal/p2p"
 	adaptor "github.com/fractalplatform/fractal/p2p/protoadaptor"
 	"github.com/fractalplatform/fractal/params"
 	"github.com/fractalplatform/fractal/processor"
 	"github.com/fractalplatform/fractal/processor/vm"
-	"github.com/fractalplatform/fractal/rawdb"
 	"github.com/fractalplatform/fractal/rpc"
+	"github.com/fractalplatform/fractal/rpcapi"
 	"github.com/fractalplatform/fractal/state"
 	"github.com/fractalplatform/fractal/txpool"
 	"github.com/fractalplatform/fractal/utils/fdb"
-	"github.com/fractalplatform/fractal/wallet"
 )
 
 // FtService implements the fractal service.
@@ -51,13 +47,13 @@ type FtService struct {
 	blockchain   *blockchain.BlockChain
 	txPool       *txpool.TxPool
 	chainDb      fdb.Database // Block chain database
-	wallet       *wallet.Wallet
 	engine       consensus.IEngine
 	miner        *miner.Miner
 	p2pServer    *adaptor.ProtoAdaptor
 	gasPrice     *big.Int
 	lock         sync.RWMutex // Protects the variadic fields (e.g. gas price)
 	APIBackend   *APIBackend
+	snapshot     *state.SnapshotSt
 }
 
 // New creates a new ftservice object (including the initialisation of the common ftservice object)
@@ -78,47 +74,23 @@ func New(ctx *node.ServiceContext, config *Config) (*FtService, error) {
 		config:       config,
 		chainDb:      chainDb,
 		chainConfig:  chainCfg,
-		wallet:       ctx.Wallet,
 		p2pServer:    ctx.P2P,
 		shutdownChan: make(chan bool),
 	}
 
-	if !config.SkipBcVersionCheck {
-		bcVersion := rawdb.ReadDatabaseVersion(chainDb)
-		if bcVersion != blockchain.BlockChainVersion && bcVersion != 0 {
-			return nil, fmt.Errorf("Blockchain DB version mismatch (%d / %d)", bcVersion, blockchain.BlockChainVersion)
-		}
-		rawdb.WriteDatabaseVersion(chainDb, blockchain.BlockChainVersion)
-	}
-
 	//blockchain
-	ftservice.blockchain, err = blockchain.NewBlockChain(chainDb, vm.Config{}, ftservice.chainConfig, txpool.SenderCacher)
-	if err != nil {
-		return nil, err
+	vmconfig := vm.Config{
+		ContractLogFlag: config.ContractLogFlag,
 	}
-	ftservice.wallet.SetBlockChain(ftservice.blockchain)
-	if config.Snapshot {
-		go state.SnapShotblk(chainDb, 300, 3600)
-	}
-
-	statedb, err := ftservice.blockchain.State()
+	ftservice.blockchain, err = blockchain.NewBlockChain(chainDb, vmconfig, ftservice.chainConfig, txpool.SenderCacher)
 	if err != nil {
-		panic(fmt.Sprintf("state db err %v", err))
-	}
-	accountManager, err := am.NewAccountManager(statedb)
-	if err != nil {
-		panic(fmt.Sprintf("genesis accountManager new err: %v", err))
-	}
-	if ok, err := accountManager.AccountIsExist(chainCfg.SysName); !ok {
-		panic(fmt.Sprintf("system account is not exist %v", err))
+		return nil, err
 	}
 
-	assetInfo, err := accountManager.GetAssetInfoByName(chainCfg.SysToken)
-	if err != nil {
-		panic(fmt.Sprintf("genesis system asset err %v", err))
+	ftservice.snapshot = state.NewSnapshot(chainDb, 3600)
+	if config.Snapshot {
+		ftservice.snapshot.Start()
 	}
-	chainCfg.SysTokenID = assetInfo.AssetId
-	chainCfg.SysTokenDecimals = assetInfo.Decimals
 
 	// txpool
 	if config.TxPool.Journal != "" {
@@ -155,7 +127,7 @@ func New(ctx *node.ServiceContext, config *Config) (*FtService, error) {
 	ftservice.miner.SetCoinbase(config.Miner.Name, config.Miner.PrivateKeys)
 	ftservice.miner.SetExtra([]byte(config.Miner.ExtraData))
 	if config.Miner.Start {
-		ftservice.miner.Start()
+		ftservice.miner.Start(false)
 	}
 
 	ftservice.APIBackend = &APIBackend{ftservice: ftservice}
@@ -167,8 +139,7 @@ func New(ctx *node.ServiceContext, config *Config) (*FtService, error) {
 
 // APIs return the collection of RPC services the ftservice package offers.
 func (fs *FtService) APIs() []rpc.API {
-	apis := api.GetAPIs(fs.APIBackend)
-	return apis
+	return rpcapi.GetAPIs(fs.APIBackend)
 }
 
 // Start implements node.Service, starting all internal goroutines.
@@ -179,6 +150,7 @@ func (fs *FtService) Start() error {
 
 // Stop implements node.Service, terminating all internal goroutine
 func (fs *FtService) Stop() error {
+	fs.snapshot.Stop()
 	fs.blockchain.Stop()
 	fs.txPool.Stop()
 	fs.chainDb.Close()
@@ -212,5 +184,4 @@ func (s *FtService) BlockChain() *blockchain.BlockChain { return s.blockchain }
 func (s *FtService) TxPool() *txpool.TxPool             { return s.txPool }
 func (s *FtService) Engine() consensus.IEngine          { return s.engine }
 func (s *FtService) ChainDb() fdb.Database              { return s.chainDb }
-func (s *FtService) Wallet() *wallet.Wallet             { return s.wallet }
 func (s *FtService) Protocols() []p2p.Protocol          { return nil }
diff --git a/ftservice/gasprice/gasprice.go b/ftservice/gasprice/gasprice.go
index 0c2d5927..35946842 100644
--- a/ftservice/gasprice/gasprice.go
+++ b/ftservice/gasprice/gasprice.go
@@ -23,23 +23,23 @@ import (
 	"sync"
 
 	"github.com/fractalplatform/fractal/common"
-	"github.com/fractalplatform/fractal/internal/api"
 	"github.com/fractalplatform/fractal/rpc"
+	"github.com/fractalplatform/fractal/rpcapi"
 	"github.com/fractalplatform/fractal/types"
 )
 
 var maxPrice = big.NewInt(500 * 1e9)
 
 type Config struct {
-	Blocks     int `mapstructure:"gpo-blocks"`
-	Percentile int `mapstructure:"gpo-percentile"`
+	Blocks     int `mapstructure:"blocks"`
+	Percentile int `mapstructure:"percentile"`
 	Default    *big.Int
 }
 
 // Oracle recommends gas prices based on the content of recent
 // blocks. Suitable for both light and full clients.
 type Oracle struct {
-	backend   api.Backend
+	backend   rpcapi.Backend
 	lastHead  common.Hash
 	lastPrice *big.Int
 	cacheLock sync.RWMutex
@@ -50,7 +50,7 @@ type Oracle struct {
 }
 
 // NewOracle returns a new oracle.
-func NewOracle(backend api.Backend, params Config) *Oracle {
+func NewOracle(backend rpcapi.Backend, params Config) *Oracle {
 	blocks := params.Blocks
 	if blocks < 1 {
 		blocks = 1
diff --git a/internal/api/keystore.go b/internal/api/keystore.go
deleted file mode 100644
index e5f97d42..00000000
--- a/internal/api/keystore.go
+++ /dev/null
@@ -1,174 +0,0 @@
-// Copyright 2018 The Fractal Team Authors
-// This file is part of the fractal project.
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-package api
-
-import (
-	"context"
-
-	"github.com/ethereum/go-ethereum/common/hexutil"
-	am "github.com/fractalplatform/fractal/accountmanager"
-	"github.com/fractalplatform/fractal/common"
-	"github.com/fractalplatform/fractal/crypto"
-	"github.com/fractalplatform/fractal/types"
-	"github.com/fractalplatform/fractal/utils/rlp"
-)
-
-type PrivateKeyStoreAPI struct {
-	b Backend
-}
-
-func NewPrivateKeyStoreAPI(b Backend) *PrivateKeyStoreAPI {
-	return &PrivateKeyStoreAPI{b}
-}
-
-// NewAccount generates a new key and stores it into the key directory.
-func (api *PrivateKeyStoreAPI) NewAccount(ctx context.Context, passphrase string) (map[string]interface{}, error) {
-	a, err := api.b.Wallet().NewAccount(passphrase)
-	if err != nil {
-		return nil, err
-	}
-
-	key, err := api.b.Wallet().GetPrivateKey(a, passphrase)
-	if err != nil {
-		return nil, err
-	}
-
-	return map[string]interface{}{
-		"address":   a.Addr,
-		"path":      a.Path,
-		"publicKey": hexutil.Bytes(crypto.FromECDSAPub(&key.PrivateKey.PublicKey)).String(),
-	}, nil
-}
-
-// Delete deletes a account by passsphrase.
-func (api *PrivateKeyStoreAPI) Delete(ctx context.Context, addr common.Address, passphrase string) error {
-	a, err := api.b.Wallet().Find(addr)
-	if err != nil {
-		return err
-	}
-	return api.b.Wallet().Delete(a, passphrase)
-}
-
-// Update changes the passphrase of an existing account.
-func (api *PrivateKeyStoreAPI) Update(ctx context.Context, addr common.Address, passphrase, newPassphrase string) error {
-	a, err := api.b.Wallet().Find(addr)
-	if err != nil {
-		return err
-	}
-	return api.b.Wallet().Update(a, passphrase, newPassphrase)
-}
-
-// ImportRawKey stores the given key into the key directory, encrypting it with the passphrase.
-func (api *PrivateKeyStoreAPI) ImportRawKey(ctx context.Context, privkey string, passphrase string) (map[string]interface{}, error) {
-	key, err := crypto.HexToECDSA(privkey)
-	if err != nil {
-		return nil, err
-	}
-	a, err := api.b.Wallet().ImportECDSA(key, passphrase)
-	if err != nil {
-		return nil, err
-	}
-	return map[string]interface{}{
-		"address":   a.Addr,
-		"path":      a.Path,
-		"publicKey": hexutil.Bytes(crypto.FromECDSAPub(&key.PublicKey)),
-	}, nil
-}
-
-// ExportRawKey export account private key .
-func (api *PrivateKeyStoreAPI) ExportRawKey(ctx context.Context, addr common.Address, passphrase string) (hexutil.Bytes, error) {
-	a, err := api.b.Wallet().Find(addr)
-	if err != nil {
-		return nil, err
-	}
-	key, err := api.b.Wallet().GetPrivateKey(a, passphrase)
-	if err != nil {
-		return nil, err
-	}
-	return hexutil.Bytes(crypto.FromECDSA(key.PrivateKey)), nil
-}
-
-// ListAccount returns all key files
-func (api *PrivateKeyStoreAPI) ListAccount(ctx context.Context) ([]map[string]interface{}, error) {
-	accounts := api.b.Wallet().Accounts()
-	ret := make([]map[string]interface{}, 0)
-	for _, account := range accounts {
-		tmpa := map[string]interface{}{
-			"address":   account.Addr,
-			"path":      account.Path,
-			"publicKey": account.PublicKey,
-		}
-		ret = append(ret, tmpa)
-	}
-	return ret, nil
-}
-
-// SignTransaction sign transaction and return raw hex .
-func (api *PrivateKeyStoreAPI) SignTransaction(ctx context.Context, addr common.Address, passphrase string, tx *types.Transaction) (hexutil.Bytes, error) {
-	a, err := api.b.Wallet().Find(addr)
-	if err != nil {
-		return nil, err
-	}
-	signed, err := api.b.Wallet().SignTxWithPassphrase(a, passphrase, tx, tx.GetActions()[0], api.b.ChainConfig().ChainID)
-	if err != nil {
-		return nil, err
-	}
-	rawtx, err := rlp.EncodeToBytes(signed)
-	if err != nil {
-		return nil, err
-	}
-	return hexutil.Bytes(rawtx), nil
-}
-
-// SignData sign data and return raw hex
-func (api *PrivateKeyStoreAPI) SignData(ctx context.Context, addr common.Address, passphrase string, data hexutil.Bytes) (hexutil.Bytes, error) {
-	a, err := api.b.Wallet().NewAccount(passphrase)
-	if err != nil {
-		return nil, err
-	}
-	key, err := api.b.Wallet().GetPrivateKey(a, passphrase)
-	if err != nil {
-		return nil, err
-	}
-
-	sig, err := crypto.Sign(data[:], key.PrivateKey)
-	if err != nil {
-		return nil, err
-	}
-
-	return hexutil.Bytes(sig), nil
-}
-
-func (api *PrivateKeyStoreAPI) BindAccountAndPublicKey(ctx context.Context, accountName string) error {
-	return api.b.Wallet().BindAccountAndPublicKey(accountName)
-}
-
-func (api *PrivateKeyStoreAPI) DeleteBound(ctx context.Context, accountName string) error {
-	return api.b.Wallet().DeleteBound(accountName)
-}
-
-func (api *PrivateKeyStoreAPI) UpdateBindingInfo(ctx context.Context, accountName string) error {
-	return api.b.Wallet().BindAccountAndPublicKey(accountName)
-}
-
-func (api *PrivateKeyStoreAPI) GetAccountsByPublicKeys(ctx context.Context) ([]am.Account, error) {
-	accounts, err := api.b.Wallet().GetAllAccounts()
-	if err != nil {
-		return nil, err
-	}
-	return accounts, nil
-}
diff --git a/metrics/config.go b/metrics/config.go
index 3cb09c9f..ca3237bb 100644
--- a/metrics/config.go
+++ b/metrics/config.go
@@ -1,11 +1,11 @@
 package metrics
 
 type Config struct {
-	MetricsFlag  bool   `mapstructure:"test-metricsflag"`
-	InfluxDBFlag bool   `mapstructure:"test-influxdbflag"`
-	Url          string `mapstructure:"test-influxdburl"`
-	DataBase     string `mapstructure:"test-influxdbname"`
-	UserName     string `mapstructure:"test-influxdbuser"`
-	PassWd       string `mapstructure:"test-influxdbpasswd"`
-	NameSpace    string `mapstructure:"test-influxdbnamespace"`
+	MetricsFlag  bool   `mapstructure:"metrics"`
+	InfluxDBFlag bool   `mapstructure:"influxdb"`
+	URL          string `mapstructure:"influxdburl"`
+	DataBase     string `mapstructure:"influxdbname"`
+	UserName     string `mapstructure:"influxdbuser"`
+	PassWd       string `mapstructure:"influxdbpasswd"`
+	NameSpace    string `mapstructure:"influxdbnamespace"`
 }
diff --git a/node/config.go b/node/config.go
index 8dd996dd..7a0516ba 100644
--- a/node/config.go
+++ b/node/config.go
@@ -30,45 +30,40 @@ import (
 	"github.com/fractalplatform/fractal/crypto"
 	"github.com/fractalplatform/fractal/p2p"
 	"github.com/fractalplatform/fractal/p2p/enode"
-	"github.com/fractalplatform/fractal/wallet/keystore"
 )
 
 const (
-	datadirPrivateKey      = "nodekey"      // Path within the datadir to the node's private key
-	datadirDefaultKeyStore = "keystore"     // Path within the datadir to the keystore
-	datadirBootNodes       = "bootnodes"    // Path within the datadir to the boot node list
-	datadirStaticNodes     = "staticnodes"  // Path within the datadir to the static node list
-	datadirTrustedNodes    = "trustednodes" // Path within the datadir to the trusted node list
+	datadirPrivateKey   = "nodekey"      // Path within the datadir to the node's private key
+	datadirBootNodes    = "bootnodes"    // Path within the datadir to the boot node list
+	datadirStaticNodes  = "staticnodes"  // Path within the datadir to the static node list
+	datadirTrustedNodes = "trustednodes" // Path within the datadir to the trusted node list
 )
 
 // Config represents a small collection of configuration values to fine tune the
 // P2P network layer of a protocol stack.
 type Config struct {
-	Name    string `mapstructure:"node-name"`
-	DataDir string `mapstructure:"node-datadir"`
-
-	KeyStoreDir       string `mapstructure:"node-keystore"`
-	UseLightweightKDF bool   `mapstructure:"node-lightkdf"`
-
-	IPCPath string `mapstructure:"node-ipcpath"`
-
-	HTTPHost         string   `mapstructure:"node-httphost"`
-	HTTPPort         int      `mapstructure:"node-httpport"`
-	HTTPModules      []string `mapstructure:"node-httpmodules"`
-	HTTPCors         []string `mapstructure:"node-httpcors"`
-	HTTPVirtualHosts []string `mapstructure:"node-httpvirtualhosts"`
-
-	WSHost      string   `mapstructure:"node-wshost"`
-	WSPort      int      `mapstructure:"node-wsport"`
-	WSModules   []string `mapstructure:"node-wsmodules"`
-	WSOrigins   []string `mapstructure:"node-wsorigins"`
-	WSExposeAll bool     `mapstructure:"node-wsexposall"`
+	Name              string
+	DataDir           string `mapstructure:"datadir"`
+	UseLightweightKDF bool   `mapstructure:"lightkdf"`
+	IPCPath           string `mapstructure:"ipcpath"`
+
+	HTTPHost         string   `mapstructure:"httphost"`
+	HTTPPort         int      `mapstructure:"httpport"`
+	HTTPModules      []string `mapstructure:"httpmodules"`
+	HTTPCors         []string `mapstructure:"httpcors"`
+	HTTPVirtualHosts []string `mapstructure:"httpvirtualhosts"`
+
+	WSHost      string   `mapstructure:"wshost"`
+	WSPort      int      `mapstructure:"wsport"`
+	WSModules   []string `mapstructure:"wsmodules"`
+	WSOrigins   []string `mapstructure:"wsorigins"`
+	WSExposeAll bool     `mapstructure:"wsexposall"`
 
 	// p2p
-	P2PBootNodes   string
-	P2PStaticNodes string
-	P2PTrustNodes  string
-	P2PConfig      *p2p.Config
+	P2PBootNodes   string      `mapstructure:"bootnodes"`
+	P2PStaticNodes string      `mapstructure:"staticnodes"`
+	P2PTrustNodes  string      `mapstructure:"trustnodes"`
+	P2PConfig      *p2p.Config `mapstructure:"p2p"`
 
 	// Logger is a custom logger to use with the p2p.Server.
 	Logger log.Logger `toml:",omitempty"`
@@ -134,18 +129,6 @@ func (c *Config) resolvePath(path string) string {
 	return filepath.Join(filepath.Join(c.DataDir, c.Name), path)
 }
 
-// walletConfig determines the settings for scrypt and keydirectory
-func (c *Config) walletConfig() (int, int, string) {
-	scryptN := keystore.StandardScryptN
-	scryptP := keystore.StandardScryptP
-	if c.UseLightweightKDF {
-		scryptN = keystore.LightScryptN
-		scryptP = keystore.LightScryptP
-	}
-
-	return scryptN, scryptP, filepath.Join(c.DataDir, datadirDefaultKeyStore)
-}
-
 func (c *Config) NodeKey() *ecdsa.PrivateKey {
 	// Use any specifically configured key.
 	if c.P2PConfig.PrivateKey != nil {
diff --git a/node/node.go b/node/node.go
index df059050..74282fe8 100644
--- a/node/node.go
+++ b/node/node.go
@@ -18,7 +18,6 @@ package node
 
 import (
 	"fmt"
-	"io/ioutil"
 	"os"
 	"path/filepath"
 	"reflect"
@@ -31,13 +30,11 @@ import (
 	adaptor "github.com/fractalplatform/fractal/p2p/protoadaptor"
 	"github.com/fractalplatform/fractal/rpc"
 	"github.com/fractalplatform/fractal/utils/filelock"
-	"github.com/fractalplatform/fractal/wallet"
 )
 
 // Node is a container on which services can be registered.
 type Node struct {
 	config          *Config
-	wallet          *wallet.Wallet
 	running         bool
 	instanceDirLock filelock.Releaser        // prevents concurrent use of instance directory
 	serviceFuncs    []ServiceConstructor     // Service constructors (in dependency order)
@@ -70,14 +67,9 @@ func New(conf *Config) (*Node, error) {
 	if conf.Logger == nil {
 		conf.Logger = log.New()
 	}
-	w, err := makeWallet(conf)
-	if err != nil {
-		return nil, err
-	}
 
 	return &Node{
 		config:       conf,
-		wallet:       w,
 		running:      false,
 		serviceFuncs: []ServiceConstructor{},
 		services:     make(map[reflect.Type]Service),
@@ -88,23 +80,6 @@ func New(conf *Config) (*Node, error) {
 	}, nil
 }
 
-func makeWallet(conf *Config) (*wallet.Wallet, error) {
-	n, p, dir := conf.walletConfig()
-	if dir == "" {
-		var err error
-		// There is no datadir.
-		dir, err = ioutil.TempDir("", "tmpkeystore")
-		if err != nil {
-			return nil, err
-		}
-	}
-
-	if err := os.MkdirAll(dir, 0700); err != nil {
-		return nil, err
-	}
-	return wallet.NewWallet(dir, n, p), nil
-}
-
 // Register injects a new service into the node's stack. The service created by
 // the passed constructor must be unique in its type with regard to sibling ones.
 func (n *Node) Register(constructor ServiceConstructor) error {
@@ -147,7 +122,6 @@ func (n *Node) Start() error {
 		ctx := &ServiceContext{
 			config:   n.config,
 			services: make(map[reflect.Type]Service),
-			Wallet:   n.wallet,
 			P2P:      n.p2pServer,
 		}
 		for kind, s := range services { // copy needed for threaded access
@@ -430,3 +404,12 @@ func (n *Node) stopWS() {
 		n.wsHandler = nil
 	}
 }
+
+func (n *Node) GetNodeConfig() *ServiceContext {
+	ctx := &ServiceContext{
+		config:   n.config,
+		services: make(map[reflect.Type]Service),
+		P2P:      n.p2pServer,
+	}
+	return ctx
+}
diff --git a/node/service.go b/node/service.go
index fab37acf..a0789b01 100644
--- a/node/service.go
+++ b/node/service.go
@@ -26,7 +26,6 @@ import (
 	"github.com/fractalplatform/fractal/utils/fdb"
 	ldb "github.com/fractalplatform/fractal/utils/fdb/leveldb"
 	mdb "github.com/fractalplatform/fractal/utils/fdb/memdb"
-	"github.com/fractalplatform/fractal/wallet"
 )
 
 // ServiceContext is a collection of service independent options inherited from
@@ -35,7 +34,6 @@ import (
 type ServiceContext struct {
 	config   *Config
 	services map[reflect.Type]Service // Index of the already constructed services
-	Wallet   *wallet.Wallet
 	P2P      *adaptor.ProtoAdaptor
 }
 
diff --git a/p2p/discover/udp_test.go b/p2p/discover/udp_test.go
index baf3c0c5..8b637f85 100644
--- a/p2p/discover/udp_test.go
+++ b/p2p/discover/udp_test.go
@@ -301,10 +301,10 @@ func TestUDP_findnodeMultiReply(t *testing.T) {
 
 	// send the reply as two packets.
 	list := []*node{
-		wrapNode(enode.MustParseV4("enode://ba85011c70bcc5c04d8607d3a0ed29aa6179c092cbdda10d5d32684fb33ed01bd94f588ca8f91ac48318087dcb02eaf36773a7a453f0eedd6742af668097b29c@10.0.1.16:30303?discport=30304")),
-		wrapNode(enode.MustParseV4("enode://81fa361d25f157cd421c60dcc28d8dac5ef6a89476633339c5df30287474520caca09627da18543d9079b5b288698b542d56167aa5c09111e55acdbbdf2ef799@10.0.1.16:30303")),
-		wrapNode(enode.MustParseV4("enode://9bffefd833d53fac8e652415f4973bee289e8b1a5c6c4cbe70abf817ce8a64cee11b823b66a987f51aaa9fba0d6a91b3e6bf0d5a5d1042de8e9eeea057b217f8@10.0.1.36:30301?discport=17")),
-		wrapNode(enode.MustParseV4("enode://1b5b4aa662d7cb44a7221bfba67302590b643028197a7d5214790f3bac7aaa4a3241be9e83c09cf1f6c69d007c634faae3dc1b1221793e8446c0b3a09de65960@10.0.1.16:30303")),
+		wrapNode(enode.MustParseV4("fnode://ba85011c70bcc5c04d8607d3a0ed29aa6179c092cbdda10d5d32684fb33ed01bd94f588ca8f91ac48318087dcb02eaf36773a7a453f0eedd6742af668097b29c@10.0.1.16:30303?discport=30304")),
+		wrapNode(enode.MustParseV4("fnode://81fa361d25f157cd421c60dcc28d8dac5ef6a89476633339c5df30287474520caca09627da18543d9079b5b288698b542d56167aa5c09111e55acdbbdf2ef799@10.0.1.16:30303")),
+		wrapNode(enode.MustParseV4("fnode://9bffefd833d53fac8e652415f4973bee289e8b1a5c6c4cbe70abf817ce8a64cee11b823b66a987f51aaa9fba0d6a91b3e6bf0d5a5d1042de8e9eeea057b217f8@10.0.1.36:30301?discport=17")),
+		wrapNode(enode.MustParseV4("fnode://1b5b4aa662d7cb44a7221bfba67302590b643028197a7d5214790f3bac7aaa4a3241be9e83c09cf1f6c69d007c634faae3dc1b1221793e8446c0b3a09de65960@10.0.1.16:30303")),
 	}
 	rpclist := make([]rpcNode, len(list))
 	for i := range list {
diff --git a/p2p/enode/node.go b/p2p/enode/node.go
index ff24c1b7..a9505f42 100644
--- a/p2p/enode/node.go
+++ b/p2p/enode/node.go
@@ -155,7 +155,7 @@ func (n ID) String() string {
 
 // The Go syntax representation of a ID is a call to HexID.
 func (n ID) GoString() string {
-	return fmt.Sprintf("enode.HexID(\"%x\")", n[:])
+	return fmt.Sprintf("fnode.HexID(\"%x\")", n[:])
 }
 
 // TerminalString returns a shortened hex string for terminal logging.
diff --git a/p2p/enode/nodedb.go b/p2p/enode/nodedb.go
index da1db133..442b72bc 100644
--- a/p2p/enode/nodedb.go
+++ b/p2p/enode/nodedb.go
@@ -175,7 +175,7 @@ func (db *DB) Node(id ID) *Node {
 func mustDecodeNode(id, data []byte) *Node {
 	node := new(Node)
 	if err := rlp.DecodeBytes(data, &node.r); err != nil {
-		panic(fmt.Errorf("p2p/enode: can't decode node %x in DB: %v", id, err))
+		panic(fmt.Errorf("p2p/fnode: can't decode node %x in DB: %v", id, err))
 	}
 	// Restore node id cache.
 	copy(node.id[:], id)
diff --git a/p2p/enode/urlv4.go b/p2p/enode/urlv4.go
index d56ad772..8898e589 100644
--- a/p2p/enode/urlv4.go
+++ b/p2p/enode/urlv4.go
@@ -31,7 +31,7 @@ import (
 	"github.com/fractalplatform/fractal/p2p/enr"
 )
 
-var incompleteNodeURL = regexp.MustCompile("(?i)^(?:enode://)?([0-9a-f]+)$")
+var incompleteNodeURL = regexp.MustCompile("(?i)^(?:fnode://)?([0-9a-f]+)$")
 
 // MustParseV4 parses a node URL. It panics if the URL is not valid.
 func MustParseV4(rawurl string) *Node {
@@ -108,8 +108,8 @@ func parseComplete(rawurl string) (*Node, error) {
 	if err != nil {
 		return nil, err
 	}
-	if u.Scheme != "enode" {
-		return nil, errors.New("invalid URL scheme, want \"enode\"")
+	if u.Scheme != "fnode" {
+		return nil, errors.New("invalid URL scheme, want \"fnode\"")
 	}
 	// Parse the Node ID from the user portion.
 	if u.User == nil {
@@ -171,7 +171,7 @@ func (n *Node) v4URL() string {
 	default:
 		nodeid = fmt.Sprintf("%s.%x", scheme, n.id[:])
 	}
-	u := url.URL{Scheme: "enode"}
+	u := url.URL{Scheme: "fnode"}
 	if n.Incomplete() {
 		u.Host = nodeid
 	} else {
diff --git a/p2p/enode/urlv4_test.go b/p2p/enode/urlv4_test.go
index 3680ab6b..5ee27dea 100644
--- a/p2p/enode/urlv4_test.go
+++ b/p2p/enode/urlv4_test.go
@@ -34,27 +34,27 @@ var parseNodeTests = []struct {
 }{
 	{
 		rawurl:    "http://foobar",
-		wantError: `invalid URL scheme, want "enode"`,
+		wantError: `invalid URL scheme, want "fnode"`,
 	},
 	{
-		rawurl:    "enode://01010101@123.124.125.126:3",
+		rawurl:    "fnode://01010101@123.124.125.126:3",
 		wantError: `invalid node ID (wrong length, want 128 hex chars)`,
 	},
 	// Complete nodes with IP address.
 	{
-		rawurl:    "enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@hostname:3",
+		rawurl:    "fnode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@hostname:3",
 		wantError: `invalid IP address`,
 	},
 	{
-		rawurl:    "enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@127.0.0.1:foo",
+		rawurl:    "fnode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@127.0.0.1:foo",
 		wantError: `invalid port`,
 	},
 	{
-		rawurl:    "enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@127.0.0.1:3?discport=foo",
+		rawurl:    "fnode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@127.0.0.1:3?discport=foo",
 		wantError: `invalid discport in query`,
 	},
 	{
-		rawurl: "enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@127.0.0.1:52150",
+		rawurl: "fnode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@127.0.0.1:52150",
 		wantResult: NewV4(
 			hexPubkey("1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"),
 			net.IP{0x7f, 0x0, 0x0, 0x1},
@@ -63,7 +63,7 @@ var parseNodeTests = []struct {
 		),
 	},
 	{
-		rawurl: "enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@[::]:52150",
+		rawurl: "fnode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@[::]:52150",
 		wantResult: NewV4(
 			hexPubkey("1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"),
 			net.ParseIP("::"),
@@ -72,7 +72,7 @@ var parseNodeTests = []struct {
 		),
 	},
 	{
-		rawurl: "enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@[2001:db8:3c4d:15::abcd:ef12]:52150",
+		rawurl: "fnode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@[2001:db8:3c4d:15::abcd:ef12]:52150",
 		wantResult: NewV4(
 			hexPubkey("1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"),
 			net.ParseIP("2001:db8:3c4d:15::abcd:ef12"),
@@ -81,7 +81,7 @@ var parseNodeTests = []struct {
 		),
 	},
 	{
-		rawurl: "enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@127.0.0.1:52150?discport=22334",
+		rawurl: "fnode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@127.0.0.1:52150?discport=22334",
 		wantResult: NewV4(
 			hexPubkey("1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"),
 			net.IP{0x7f, 0x0, 0x0, 0x1},
@@ -98,7 +98,7 @@ var parseNodeTests = []struct {
 		),
 	},
 	{
-		rawurl: "enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439",
+		rawurl: "fnode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439",
 		wantResult: NewV4(
 			hexPubkey("1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"),
 			nil, 0, 0,
@@ -110,7 +110,7 @@ var parseNodeTests = []struct {
 		wantError: `invalid node ID (wrong length, want 128 hex chars)`,
 	},
 	{
-		rawurl:    "enode://01010101",
+		rawurl:    "fnode://01010101",
 		wantError: `invalid node ID (wrong length, want 128 hex chars)`,
 	},
 	{
@@ -153,7 +153,7 @@ func TestParseNode(t *testing.T) {
 
 func TestNodeString(t *testing.T) {
 	for i, test := range parseNodeTests {
-		if test.wantError == "" && strings.HasPrefix(test.rawurl, "enode://") {
+		if test.wantError == "" && strings.HasPrefix(test.rawurl, "fnode://") {
 			str := test.wantResult.String()
 			if str != test.rawurl {
 				t.Errorf("test %d: Node.String() mismatch:\ngot:  %s\nwant: %s", i, str, test.rawurl)
diff --git a/p2p/server.go b/p2p/server.go
index 400c9e67..f904a758 100644
--- a/p2p/server.go
+++ b/p2p/server.go
@@ -62,29 +62,28 @@ type Config struct {
 	PrivateKey *ecdsa.PrivateKey
 
 	// NetworkID is ID of network
-	NetworkID uint `mapstructure:"p2p-networkdID"`
+	NetworkID uint `mapstructure:"networkid"`
 
 	// MaxPeers is the maximum number of peers that can be
 	// connected. It must be greater than zero.
-	MaxPeers int `mapstructure:"p2p-maxpeers"`
+	MaxPeers int `mapstructure:"maxpeers"`
 
 	// MaxPendingPeers is the maximum number of peers that can be pending in the
 	// handshake phase, counted separately for inbound and outbound connections.
 	// Zero defaults to preset values.
-	MaxPendingPeers int `mapstructure:"p2p-maxpendpeers"`
+	MaxPendingPeers int `mapstructure:"maxpendpeers"`
 
 	// DialRatio controls the ratio of inbound to dialed connections.
 	// Example: a DialRatio of 2 allows 1/2 of connections to be dialed.
 	// Setting DialRatio to zero defaults it to 3.
-	DialRatio int `mapstructure:"p2p-dialratio"`
+	DialRatio int `mapstructure:"dialratio"`
 
 	// NoDiscovery can be used to disable the peer discovery mechanism.
 	// Disabling is useful for protocol debugging (manual topology).
-	NoDiscovery bool `mapstructure:"p2p-nodiscover"`
+	NoDiscovery bool `mapstructure:"nodiscover"`
 
 	// Name sets the node name of this server.
-	// Use common.MakeName to create a name that follows existing conventions.
-	Name string `mapstructure:"p2p-nodename"`
+	Name string `mapstructure:"name"`
 
 	// BootstrapNodes are used to establish connectivity
 	// with the rest of the network.
@@ -101,11 +100,11 @@ type Config struct {
 	// Connectivity can be restricted to certain IP networks.
 	// If this option is set to a non-nil value, only hosts which match one of the
 	// IP networks contained in the list are considered.
-	NetRestrict *netutil.Netlist `mapstructure:"p2p-badIP"`
+	NetRestrict *netutil.Netlist
 
 	// NodeDatabase is the path to the database containing the previously seen
 	// live nodes in the network.
-	NodeDatabase string `mapstructure:"p2p-nodedb"`
+	NodeDatabase string `mapstructure:"nodedb"`
 
 	// Protocols should contain the protocols supported
 	// by the server. Matching protocols are launched for
@@ -118,7 +117,7 @@ type Config struct {
 	// If the port is zero, the operating system will pick a port. The
 	// ListenAddr field will be updated with the actual address when
 	// the server is started.
-	ListenAddr string `mapstructure:"p2p-listenaddr"`
+	ListenAddr string `mapstructure:"listenaddr"`
 
 	// If set to a non-nil value, the given NAT port mapper
 	// is used to make the listening port available to the
@@ -130,7 +129,7 @@ type Config struct {
 	Dialer NodeDialer
 
 	// If NoDial is true, the server will not dial any peers.
-	NoDial bool `mapstructure:"p2p-nodial"`
+	NoDial bool `mapstructure:"nodial"`
 
 	// If EnableMsgEvents is set then the server will emit PeerEvents
 	// whenever a message is sent to or received from a peer
diff --git a/params/chainconfig.go b/params/chainconfig.go
index 492f4f71..f84cfda7 100644
--- a/params/chainconfig.go
+++ b/params/chainconfig.go
@@ -17,38 +17,109 @@
 package params
 
 import (
+	"encoding/json"
 	"math/big"
-
-	"github.com/fractalplatform/fractal/common"
 )
 
-const DefaultPubkeyHex = "047db227d7094ce215c3a0f57e1bcc732551fe351f94249471934567e0f5dc1bf795962b8cccb87a2eb56b29fbe37d614e2f4c3c45b789ae4f1f51f4cb21972ffd"
-
 // ChainConfig is the core config which determines the blockchain settings.
-// ChainConfig is stored in the database on a per block basis.
 type ChainConfig struct {
-	ChainID             *big.Int    `json:"chainId"`   // chainId identifies the current chain and is used for replay protection
-	BootNodes           []string    `json:"bootnodes"` // enode URLs of the P2P bootstrap nodes
-	SysName             common.Name `json:"sysName"`   // system name
-	SysToken            string      `json:"sysToken"`  // system token
-	AssetChargeRatio    uint64      `json:"assetChargeRatio"`
-	ContractChargeRatio uint64      `json:"contractChargeRatio"`
-	SysTokenID          uint64      `json:"-"`
-	SysTokenDecimals    uint64      `json:"-"`
-	UpperLimit          *big.Int    `json:"upperlimit"`
+	BootNodes        []string      `json:"bootnodes,omitempty"` // enode URLs of the P2P bootstrap nodes
+	ChainID          *big.Int      `json:"chainId,omitempty"`   // chainId identifies the current chain and is used for replay protection
+	ChainName        string        `json:"chainName,omitempty"` // chain name
+	ChainURL         string        `json:"chainUrl,omitempty"`  // chain url
+	AccountNameCfg   *NameConfig   `json:"accountParams,omitempty"`
+	AssetNameCfg     *NameConfig   `json:"assetParams,omitempty"`
+	ChargeCfg        *ChargeConfig `json:"chargeParams,omitempty"`
+	ForkedCfg        *FrokedConfig `json:"upgradeParams,omitempty"`
+	DposCfg          *DposConfig   `json:"dposParams,omitempty"`
+	SysName          string        `json:"systemName,omitempty"`  // system name
+	AccountName      string        `json:"accountName,omitempty"` // system name
+	DposName         string        `json:"dposName,omitempty"`    // system name
+	SysToken         string        `json:"systemToken,omitempty"` // system token
+	SysTokenID       uint64        `json:"sysTokenID,omitempty"`
+	SysTokenDecimals uint64        `json:"sysTokenDecimal,omitempty"`
+}
+
+type ChargeConfig struct {
+	AssetRatio    uint64 `json:"assetRatio,omitempty"`
+	ContractRatio uint64 `json:"contractRatio,omitempty"`
+}
+
+type NameConfig struct {
+	Level     uint64 `json:"level,omitempty"`
+	Length    uint64 `json:"length,omitempty"`
+	SubLength uint64 `json:"subLength,omitempty"`
+}
+
+type FrokedConfig struct {
+	ForkBlockNum   uint64 `json:"blockCnt,omitempty"`
+	Forkpercentage uint64 `json:"upgradeRatio,omitempty"`
+}
+
+type DposConfig struct {
+	MaxURLLen            uint64   `json:"maxURLLen,omitempty"`            // url length
+	UnitStake            *big.Int `json:"unitStake,omitempty"`            // state unit
+	CadidateMinQuantity  *big.Int `json:"cadidateMinQuantity,omitempty"`  // min quantity
+	VoterMinQuantity     *big.Int `json:"voterMinQuantity,omitempty"`     // min quantity
+	ActivatedMinQuantity *big.Int `json:"activatedMinQuantity,omitempty"` // min active quantity
+	BlockInterval        uint64   `json:"blockInterval,omitempty"`
+	BlockFrequency       uint64   `json:"blockFrequency,omitempty"`
+	CadidateScheduleSize uint64   `json:"cadidateScheduleSize,omitempty"`
+	DelayEcho            uint64   `json:"delayEcho,omitempty"`
+	ExtraBlockReward     *big.Int `json:"extraBlockReward,omitempty"`
+	BlockReward          *big.Int `json:"blockReward,omitempty"`
 }
 
 var DefaultChainconfig = &ChainConfig{
-	ChainID:             big.NewInt(1),
-	SysName:             "ftsystemio",
-	SysToken:            "ftoken",
-	AssetChargeRatio:    80,
-	ContractChargeRatio: 80,
+	BootNodes: []string{},
+	ChainID:   big.NewInt(1),
+	ChainName: "fractal",
+	ChainURL:  "https://fractalproject.com",
+	AccountNameCfg: &NameConfig{
+		Level:     1,
+		Length:    16,
+		SubLength: 8,
+	},
+	AssetNameCfg: &NameConfig{
+		Level:     1,
+		Length:    16,
+		SubLength: 8,
+	},
+	ChargeCfg: &ChargeConfig{
+		AssetRatio:    80,
+		ContractRatio: 80,
+	},
+	ForkedCfg: &FrokedConfig{
+		ForkBlockNum:   10000,
+		Forkpercentage: 80,
+	},
+	DposCfg: &DposConfig{
+		MaxURLLen:            512,
+		UnitStake:            big.NewInt(1000),
+		CadidateMinQuantity:  big.NewInt(10),
+		VoterMinQuantity:     big.NewInt(1),
+		ActivatedMinQuantity: big.NewInt(100),
+		BlockInterval:        3000,
+		BlockFrequency:       6,
+		CadidateScheduleSize: 3,
+		DelayEcho:            2,
+		ExtraBlockReward:     big.NewInt(1),
+		BlockReward:          big.NewInt(5),
+	},
+	SysName:     "fractal.admin",
+	AccountName: "fractal.account",
+	DposName:    "fractal.dpos",
+	SysToken:    "ftoken",
+}
+
+func (cfg *ChainConfig) Copy() *ChainConfig {
+	bts, _ := json.Marshal(cfg)
+	c := &ChainConfig{}
+	json.Unmarshal(bts, c)
+	return c
 }
 
 const (
-	// TheForkNum this hard forking for add fork controller function.
-	TheForkNum uint64 = 422500
 	// NextForkID is the id of next fork
 	NextForkID uint64 = 0
 )
diff --git a/params/gas_table.go b/params/gas_table.go
index d1ecfb83..21af3453 100644
--- a/params/gas_table.go
+++ b/params/gas_table.go
@@ -20,7 +20,7 @@ import (
 	"github.com/fractalplatform/fractal/types"
 )
 
-// GasTable organizes gas prices for different ethereum phases.
+// GasTable organizes gas prices for different phases.
 type GasTable struct {
 	ExtcodeSize uint64
 	ExtcodeCopy uint64
@@ -38,14 +38,21 @@ type GasTable struct {
 	// not charged.
 	CreateBySuicide uint64
 	SetOwner        uint64
+	GetAccountTime  uint64
 	GetSnapshotTime uint64
 	GetAssetAmount  uint64
 	SnapBalance     uint64
+	IssueAsset      uint64
+	DestroyAsset    uint64
+	AddAsset        uint64
+	GetAccountID    uint64
+	GetDelegate     uint64
+	CryptoCalc      uint64
+	CryptoByte      uint64
 }
 
-// Variables containing gas prices for different ethereum phases.
+// Variables containing gas prices for different phases.
 var (
-
 	// GasTable contain the gas re-prices
 	GasTableInstanse = GasTable{
 		ExtcodeSize: 700,
@@ -58,9 +65,17 @@ var (
 
 		CreateBySuicide: 25000,
 		SetOwner:        200,
+		GetAccountTime:  200,
 		GetSnapshotTime: 200,
 		GetAssetAmount:  200,
 		SnapBalance:     200,
+		IssueAsset:      200,
+		DestroyAsset:    200,
+		AddAsset:        200,
+		GetAccountID:    200,
+		GetDelegate:     200,
+		CryptoCalc:      20000,
+		CryptoByte:      1000,
 	}
 )
 
diff --git a/params/params.go b/params/params.go
index 956081c4..de885972 100644
--- a/params/params.go
+++ b/params/params.go
@@ -38,34 +38,25 @@ const (
 
 	//VM const
 
-	ExpByteGas           uint64 = 10    // Times ceil(log256(exponent)) for the EXP instruction.
-	SloadGas             uint64 = 50    // Multiplied by the number of 32-byte words that are copied (round up) for any *COPY operation and added.
 	CallValueTransferGas uint64 = 9000  // Paid for CALL when the value transfer is non-zero.
-	CallNewAccountGas    uint64 = 25000 // Paid for CALL when the destination address didn't exist prior.
 	QuadCoeffDiv         uint64 = 512   // Divisor for the quadratic particle of the memory cost equation.
 	SstoreSetGas         uint64 = 20000 // Once per SLOAD operation.
 	LogDataGas           uint64 = 8     // Per byte in a LOG* operation's data.
 	CallStipend          uint64 = 2300  // Free gas given at beginning of call.
 
-	Sha3Gas          uint64 = 30    // Once per SHA3 operation.
-	Sha3WordGas      uint64 = 6     // Once per word of the SHA3 operation's data.
-	SstoreResetGas   uint64 = 5000  // Once per SSTORE operation if the zeroness changes from zero.
-	SstoreClearGas   uint64 = 5000  // Once per SSTORE operation if the zeroness doesn't change.
-	SstoreRefundGas  uint64 = 15000 // Once per SSTORE operation if the zeroness changes to zero.
-	JumpdestGas      uint64 = 1     // Refunded gas, once per SSTORE operation if the zeroness changes to zero.
-	EpochDuration    uint64 = 30000 // Duration between proof-of-work epochs.
-	CallGas          uint64 = 40    // Once per CALL operation & message call transaction.
-	CreateDataGas    uint64 = 200   //
-	CallCreateDepth  uint64 = 1024  // Maximum depth of call/create stack.
-	ExpGas           uint64 = 10    // Once per EXP instruction
-	LogGas           uint64 = 375   // Per LOG* operation.
-	CopyGas          uint64 = 3     //
-	StackLimit       uint64 = 1024  // Maximum size of VM stack allowed.
-	TierStepGas      uint64 = 0     // Once per operation, for a selection of them.
-	LogTopicGas      uint64 = 375   // Multiplied by the * of the LOG*, per LOG transaction. e.g. LOG0 incurs 0 * c_txLogTopicGas, LOG4 incurs 4 * c_txLogTopicGas.
-	CreateGas        uint64 = 32000 // Once per CREATE operation & contract-creation transaction.
-	SuicideRefundGas uint64 = 24000 // Refunded following a suicide operation.
-	MemoryGas        uint64 = 3     // Times the address of the (highest referenced byte in memory + 1). NOTE: referencing happens on read, write and in instructions such as RETURN and CALL.
+	Sha3Gas         uint64 = 30    // Once per SHA3 operation.
+	Sha3WordGas     uint64 = 6     // Once per word of the SHA3 operation's data.
+	SstoreResetGas  uint64 = 5000  // Once per SSTORE operation if the zeroness changes from zero.
+	JumpdestGas     uint64 = 1     // Refunded gas, once per SSTORE operation if the zeroness changes to zero.
+	EpochDuration   uint64 = 30000 // Duration between proof-of-work epochs.
+	CreateDataGas   uint64 = 200   //
+	CallCreateDepth uint64 = 1024  // Maximum depth of call/create stack.
+	LogGas          uint64 = 375   // Per LOG* operation.
+	CopyGas         uint64 = 3     //
+	StackLimit      uint64 = 1024  // Maximum size of VM stack allowed.
+	LogTopicGas     uint64 = 375   // Multiplied by the * of the LOG*, per LOG transaction. e.g. LOG0 incurs 0 * c_txLogTopicGas, LOG4 incurs 4 * c_txLogTopicGas.
+	CreateGas       uint64 = 32000 // Once per CREATE operation & contract-creation transaction.
+	MemoryGas       uint64 = 3     // Times the address of the (highest referenced byte in memory + 1). NOTE: referencing happens on read, write and in instructions such as RETURN and CALL.
 
 	MaxCodeSize = 24576 // Maximum bytecode to permit for a contract
 
@@ -83,10 +74,6 @@ const (
 	Bn256ScalarMulGas       uint64 = 40000  // Gas needed for an elliptic curve scalar multiplication
 	Bn256PairingBaseGas     uint64 = 100000 // Base price for an elliptic curve pairing check
 	Bn256PairingPerPointGas uint64 = 80000  // Per-point price for an elliptic curve pairing check
-
-	Wei   = 1
-	GWei  = 1e9
-	Ether = 1e18
 )
 
 var (
@@ -95,3 +82,8 @@ var (
 	MinimumDifficulty      = big.NewInt(131072) // The minimum that the difficulty may ever be.
 	DurationLimit          = big.NewInt(13)     // The decision boundary on the blocktime duration used to determine whether difficulty should go up or not.
 )
+
+var (
+	MaxSignDepth  = uint64(10)
+	MaxSignLength = uint64(50)
+)
diff --git a/processor/error.go b/processor/error.go
index ee544df5..d73a1e87 100644
--- a/processor/error.go
+++ b/processor/error.go
@@ -52,6 +52,10 @@ var (
 	ErrNonceTooLow = errors.New("nonce too low")
 
 	errZeroBlockTime = errors.New("timestamp equals parent's")
+
+	errParentBlock = errors.New("parent block not exist")
+	//
+	ErrActionInvalidValue = errors.New("action value invalid")
 )
 
 // GenesisMismatchError is raised when trying to overwrite an existing
diff --git a/processor/evm.go b/processor/evm.go
index 65f2ad39..ddba6d8a 100644
--- a/processor/evm.go
+++ b/processor/evm.go
@@ -60,7 +60,7 @@ type ChainContext interface {
 	StateAt(hash common.Hash) (*state.StateDB, error)
 
 	// WriteBlockWithState writes the block and all associated state to the database.
-	WriteBlockWithState(block *types.Block, receipts []*types.Receipt, state *state.StateDB) error
+	WriteBlockWithState(block *types.Block, receipts []*types.Receipt, state *state.StateDB) (bool, error)
 
 	// CheckForkID checks the validity of forkID
 	CheckForkID(header *types.Header) error
@@ -73,12 +73,14 @@ type ChainContext interface {
 }
 
 type EgnineContext interface {
-	// Author retrieves the Ethereum address of the account that minted the given
+	// Author retrieves the address of the account that minted the given
 	// block, which may be different from the header's coinbase if a consensus
 	// engine is based on signatures.
 	Author(header *types.Header) (common.Name, error)
 
-	ProcessAction(chainCfg *params.ChainConfig, state *state.StateDB, action *types.Action) error
+	ProcessAction(chainCfg *params.ChainConfig, state *state.StateDB, action *types.Action) ([]*types.InternalAction, error)
+
+	GetDelegatedByTime(name string, timestamp uint64, state *state.StateDB) (*big.Int, *big.Int, uint64, error)
 }
 
 type EvmContext struct {
@@ -87,7 +89,7 @@ type EvmContext struct {
 }
 
 // NewEVMContext creates a new context for use in the EVM.
-func NewEVMContext(sender common.Name, fromPubkey common.PubKey, assetID uint64, gasPrice *big.Int, header *types.Header, chain *EvmContext, author *common.Name) vm.Context {
+func NewEVMContext(sender common.Name, assetID uint64, gasPrice *big.Int, header *types.Header, chain *EvmContext, author *common.Name) vm.Context {
 	// If we don't have an explicit author (i.e. not mining), extract from the header
 	var beneficiary common.Name
 	if author == nil {
@@ -96,16 +98,17 @@ func NewEVMContext(sender common.Name, fromPubkey common.PubKey, assetID uint64,
 		beneficiary = *author
 	}
 	return vm.Context{
-		GetHash:     GetHashFn(header, chain),
-		Origin:      sender,
-		FromPubkey:  fromPubkey,
-		AssetID:     assetID,
-		Coinbase:    beneficiary,
-		BlockNumber: new(big.Int).Set(header.Number),
-		Time:        new(big.Int).Set(header.Time),
-		Difficulty:  new(big.Int).Set(header.Difficulty),
-		GasLimit:    header.GasLimit,
-		GasPrice:    new(big.Int).Set(gasPrice),
+		GetHash:            GetHashFn(header, chain),
+		GetDelegatedByTime: chain.GetDelegatedByTime,
+		GetHeaderByNumber:  chain.GetHeaderByNumber,
+		Origin:             sender,
+		AssetID:            assetID,
+		Coinbase:           beneficiary,
+		BlockNumber:        new(big.Int).Set(header.Number),
+		Time:               new(big.Int).Set(header.Time),
+		Difficulty:         new(big.Int).Set(header.Difficulty),
+		GasLimit:           header.GasLimit,
+		GasPrice:           new(big.Int).Set(gasPrice),
 	}
 }
 
diff --git a/processor/processor.go b/processor/processor.go
index c0e78a9c..36bf2518 100644
--- a/processor/processor.go
+++ b/processor/processor.go
@@ -17,6 +17,7 @@
 package processor
 
 import (
+	"github.com/ethereum/go-ethereum/log"
 	"github.com/fractalplatform/fractal/accountmanager"
 	"github.com/fractalplatform/fractal/common"
 	"github.com/fractalplatform/fractal/consensus"
@@ -42,7 +43,7 @@ func NewStateProcessor(bc ChainContext, engine consensus.IEngine) *StateProcesso
 	}
 }
 
-// Process processes the state changes according to the Ethereum rules by running
+// Process processes the state changes according to the rules by running
 // the transaction messages using the statedb and applying any rewards to both
 // the processor (coinbase) and any included uncles.
 //
@@ -92,14 +93,13 @@ func (p *StateProcessor) ApplyTransaction(author *common.Name, gp *common.GasPoo
 
 	var totalGas uint64
 	var ios []*types.ActionResult
+	detailTx := &types.DetailTx{}
+	var detailActions []*types.DetailAction
 	for i, action := range tx.GetActions() {
-		fromPubkey, err := types.Recover(types.NewSigner(config.ChainID), action, tx)
-		if err != nil {
-			return nil, 0, err
-		}
-
-		if err := accountDB.IsValidSign(action.Sender(), action.Type(), fromPubkey); err != nil {
-			return nil, 0, err
+		if needCheckSign(accountDB, action) {
+			if err := accountDB.RecoverTx(types.NewSigner(config.ChainID), tx); err != nil {
+				return nil, 0, err
+			}
 		}
 
 		nonce, err := accountDB.GetNonce(action.Sender())
@@ -116,7 +116,7 @@ func (p *StateProcessor) ApplyTransaction(author *common.Name, gp *common.GasPoo
 			ChainContext:  p.bc,
 			EgnineContext: p.engine,
 		}
-		context := NewEVMContext(action.Sender(), fromPubkey, assetID, tx.GasPrice(), header, evmcontext, author)
+		context := NewEVMContext(action.Sender(), assetID, tx.GasPrice(), header, evmcontext, author)
 		vmenv := vm.NewEVM(context, accountDB, statedb, config, cfg)
 
 		_, gas, failed, err, vmerr := ApplyMessage(accountDB, vmenv, action, gp, gasPrice, assetID, config, p.engine)
@@ -137,9 +137,14 @@ func (p *StateProcessor) ApplyTransaction(author *common.Name, gp *common.GasPoo
 		vmerrstr := ""
 		if vmerr != nil {
 			vmerrstr = vmerr.Error()
+			log.Debug("processer apply transaction ", "hash", tx.Hash(), "err", vmerrstr)
 		}
-		ios = append(ios, &types.ActionResult{Status: status, Index: uint64(i), GasUsed: gas, Error: vmerrstr})
-
+		var gasAllot []*types.GasDistribution
+		for account, gas := range vmenv.FounderGasMap {
+			gasAllot = append(gasAllot, &types.GasDistribution{Account: account.String(), Gas: uint64(gas.Value), TypeID: gas.TypeID})
+		}
+		ios = append(ios, &types.ActionResult{Status: status, Index: uint64(i), GasUsed: gas, GasAllot: gasAllot, Error: vmerrstr})
+		detailActions = append(detailActions, &types.DetailAction{InternalActions: vmenv.InternalTxs})
 	}
 	root := statedb.ReceiptRoot()
 	receipt := types.NewReceipt(root[:], *usedGas, totalGas)
@@ -149,5 +154,21 @@ func (p *StateProcessor) ApplyTransaction(author *common.Name, gp *common.GasPoo
 	receipt.Logs = statedb.GetLogs(tx.Hash())
 	receipt.Bloom = types.CreateBloom([]*types.Receipt{receipt})
 
+	detailTx.TxHash = receipt.TxHash
+	detailTx.Actions = detailActions
+	receipt.SetInternalTxsLog(detailTx)
 	return receipt, totalGas, nil
 }
+
+func needCheckSign(accountDB *accountmanager.AccountManager, action *types.Action) bool {
+	authorVersion := types.GetAuthorCache(action)
+	if len(authorVersion) == 0 {
+		return true
+	}
+	for name, version := range authorVersion {
+		if tmpVersion, err := accountDB.GetAuthorVersion(name); err != nil || version != tmpVersion {
+			return true
+		}
+	}
+	return false
+}
diff --git a/processor/transition.go b/processor/transition.go
index 359756ec..c637f57f 100644
--- a/processor/transition.go
+++ b/processor/transition.go
@@ -82,10 +82,10 @@ func (st *StateTransition) preCheck() error {
 
 func (st *StateTransition) buyGas() error {
 	mgval := new(big.Int).Mul(new(big.Int).SetUint64(st.action.Gas()), st.gasPrice)
-	balance, err := st.account.GetAccountBalanceByID(st.from, st.assetID)
+	balance, err := st.account.GetAccountBalanceByID(st.from, st.assetID, 0)
 	//balance, err := st.account.GetAccountBalanceByID(st.from, st.assetID)
 	if err != nil {
-		return errInsufficientBalanceForGas
+		return err
 	}
 	if balance.Cmp(mgval) < 0 {
 		return errInsufficientBalanceForGas
@@ -131,24 +131,35 @@ func (st *StateTransition) TransitionDb() (ret []byte, usedGas uint64, failed bo
 	switch {
 	case actionType == types.CreateContract:
 		ret, st.gas, vmerr = evm.Create(sender, st.action, st.gas)
-	case actionType == types.Transfer:
+	case actionType == types.CallContract:
 		ret, st.gas, vmerr = evm.Call(sender, st.action, st.gas)
-	case actionType == types.RegProducer:
+	case actionType == types.RegCadidate:
 		fallthrough
-	case actionType == types.UpdateProducer:
+	case actionType == types.UpdateCadidate:
 		fallthrough
-	case actionType == types.UnregProducer:
+	case actionType == types.UnregCadidate:
 		fallthrough
 	case actionType == types.RemoveVoter:
 		fallthrough
-	case actionType == types.VoteProducer:
+	case actionType == types.VoteCadidate:
+		fallthrough
+	case actionType == types.ChangeCadidate:
 		fallthrough
-	case actionType == types.ChangeProducer:
+	case actionType == types.KickedCadidate:
 		fallthrough
-	case actionType == types.UnvoteProducer:
-		vmerr = st.engine.ProcessAction(st.evm.ChainConfig(), st.evm.StateDB, st.action)
+	case actionType == types.ExitTakeOver:
+		fallthrough
+	case actionType == types.UnvoteCadidate:
+		internalLogs, err := st.engine.ProcessAction(st.evm.ChainConfig(), st.evm.StateDB, st.action)
+		vmerr = err
+		evm.InternalTxs = append(evm.InternalTxs, internalLogs...)
 	default:
-		vmerr = st.account.Process(st.action)
+		internalLogs, err := st.account.Process(&types.AccountManagerContext{
+			Action: st.action,
+			Number: st.evm.Context.BlockNumber.Uint64(),
+		})
+		vmerr = err
+		evm.InternalTxs = append(evm.InternalTxs, internalLogs...)
 	}
 	if vmerr != nil {
 		log.Debug("VM returned with error", "err", vmerr)
@@ -170,13 +181,23 @@ func (st *StateTransition) TransitionDb() (ret []byte, usedGas uint64, failed bo
 	st.refundGas()
 
 	if st.action.Value().Sign() != 0 {
-		assetFounder, _ := st.account.GetAssetFounder(st.action.AssetID())
-		assetFounderRatio := st.chainConfig.AssetChargeRatio
-		if len(assetFounder.String()) > 0 {
-			if _, ok := evm.FounderGasMap[assetFounder]; !ok {
-				evm.FounderGasMap[assetFounder] = int64(params.ActionGas * assetFounderRatio / 100)
+
+		assetInfo, _ := evm.AccountDB.GetAssetInfoByID(st.action.AssetID())
+		assetName := common.Name(assetInfo.GetAssetName())
+
+		assetFounderRatio := st.chainConfig.ChargeCfg.AssetRatio
+		if len(assetName.String()) > 0 {
+			if _, ok := evm.FounderGasMap[assetName]; !ok {
+				dGas := vm.DistributeGas{
+					Value:  int64(params.ActionGas * assetFounderRatio / 100),
+					TypeID: vm.AssetGas}
+				evm.FounderGasMap[assetName] = dGas
 			} else {
-				evm.FounderGasMap[assetFounder] += int64(params.ActionGas * assetFounderRatio / 100)
+				dGas := vm.DistributeGas{
+					Value:  int64(params.ActionGas * assetFounderRatio / 100),
+					TypeID: vm.AssetGas}
+				dGas.Value = evm.FounderGasMap[assetName].Value + dGas.Value
+				evm.FounderGasMap[assetName] = dGas
 			}
 		}
 	}
@@ -188,13 +209,36 @@ func (st *StateTransition) TransitionDb() (ret []byte, usedGas uint64, failed bo
 
 func (st *StateTransition) distributeGas() error {
 	var totalGas int64
-	for founder, gas := range st.evm.FounderGasMap {
-		st.account.AddAccountBalanceByID(founder, st.assetID, new(big.Int).Mul(st.gasPrice, big.NewInt(gas)))
-		totalGas += gas
+	for name, gas := range st.evm.FounderGasMap {
+		var founder common.Name
+		if vm.AssetGas == gas.TypeID {
+			assetInfo, _ := st.account.GetAssetInfoByName(name.String())
+			if assetInfo != nil {
+				founder = assetInfo.GetAssetFounder()
+			}
+		} else if vm.ContractGas == gas.TypeID {
+			founder, _ = st.account.GetFounder(name)
+		} else if vm.CoinbaseGas == gas.TypeID {
+			founder = name
+		}
+
+		st.account.AddAccountBalanceByID(founder, st.assetID, new(big.Int).Mul(st.gasPrice, big.NewInt(gas.Value)))
+		totalGas += gas.Value
 	}
 	if totalGas > int64(st.gasUsed()) {
 		return fmt.Errorf("calc wrong gas used")
 	}
+	if _, ok := st.evm.FounderGasMap[st.evm.Coinbase]; !ok {
+		st.evm.FounderGasMap[st.evm.Coinbase] = vm.DistributeGas{
+			Value:  int64(st.gasUsed()) - totalGas,
+			TypeID: vm.CoinbaseGas}
+	} else {
+		dGas := vm.DistributeGas{
+			Value:  int64(st.gasUsed()) - totalGas,
+			TypeID: vm.CoinbaseGas}
+		dGas.Value = st.evm.FounderGasMap[st.evm.Coinbase].Value + dGas.Value
+		st.evm.FounderGasMap[st.evm.Coinbase] = dGas
+	}
 	st.account.AddAccountBalanceByID(st.evm.Coinbase, st.assetID, new(big.Int).Mul(st.gasPrice, new(big.Int).SetUint64(st.gasUsed()-uint64(totalGas))))
 	return nil
 }
diff --git a/processor/validator.go b/processor/validator.go
index c521daf4..071fa545 100644
--- a/processor/validator.go
+++ b/processor/validator.go
@@ -50,13 +50,18 @@ func NewBlockValidator(blockchain ChainContext, engine consensus.IEngine) *Block
 // ValidateHeader checks whether a header conforms to the consensus rules of the
 // stock engine.
 func (v *BlockValidator) ValidateHeader(header *types.Header, seal bool) error {
+
 	// Short circuit if the header is known, or it's parent not
 	if v.bc.HasBlockAndState(header.Hash(), header.Number.Uint64()) {
 		return ErrKnownBlock
 	}
 
 	number := header.Number.Uint64()
+
 	parent := v.bc.GetHeader(header.ParentHash, number-1)
+	if parent == nil {
+		return errParentBlock
+	}
 
 	// Ensure that the header's extra-data section is of a reasonable size
 	if uint64(len(header.Extra)) > params.MaximumExtraDataSize {
diff --git a/processor/vm/contract.go b/processor/vm/contract.go
index a3b33803..08ec6141 100644
--- a/processor/vm/contract.go
+++ b/processor/vm/contract.go
@@ -39,7 +39,7 @@ type AccountRef common.Name
 // Name casts AccountRef to a Name
 func (ar AccountRef) Name() common.Name { return (common.Name)(ar) }
 
-// Contract represents an ethereum contract in the state database. It contains
+// Contract represents an contract in the state database. It contains
 // the the contract code, calling arguments. Contract implements ContractRef
 type Contract struct {
 	// CallerName is the result of the caller which initialised this
diff --git a/processor/vm/contracts.go b/processor/vm/contracts.go
index 481487e5..1c8dc0b9 100644
--- a/processor/vm/contracts.go
+++ b/processor/vm/contracts.go
@@ -37,7 +37,7 @@ type PrecompiledContract interface {
 	Run(input []byte) ([]byte, error) // Run runs the precompiled contract
 }
 
-// PrecompiledContractsHomestead contains the default set of pre-compiled Ethereum
+// PrecompiledContractsHomestead contains the default set of pre-compiled
 // contracts used in the Frontier and Homestead releases.
 var PrecompiledContractsHomestead = map[common.Address]PrecompiledContract{
 	common.BytesToAddress([]byte{1}): &ecrecover{},
@@ -46,7 +46,7 @@ var PrecompiledContractsHomestead = map[common.Address]PrecompiledContract{
 	common.BytesToAddress([]byte{4}): &dataCopy{},
 }
 
-// PrecompiledContractsByzantium contains the default set of pre-compiled Ethereum
+// PrecompiledContractsByzantium contains the default set of pre-compiled
 // contracts used in the Byzantium release.
 var PrecompiledContractsByzantium = map[common.Address]PrecompiledContract{
 	common.BytesToAddress([]byte{1}): &ecrecover{},
diff --git a/processor/vm/errors.go b/processor/vm/errors.go
index 39ccb493..a5abb493 100644
--- a/processor/vm/errors.go
+++ b/processor/vm/errors.go
@@ -25,4 +25,6 @@ var (
 	ErrTraceLimitReached        = errors.New("the number of logs reached the specified limit")
 	ErrInsufficientBalance      = errors.New("insufficient balance for transfer")
 	ErrContractAddressCollision = errors.New("contract name collision")
+	ErrContractCodeCollision    = errors.New("contract code collision")
+	ErrAccountNotExist          = errors.New("account not exist")
 )
diff --git a/processor/vm/gas_table.go b/processor/vm/gas_table.go
index 312195c0..33109ead 100644
--- a/processor/vm/gas_table.go
+++ b/processor/vm/gas_table.go
@@ -319,14 +319,6 @@ func gasCall(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem
 		gas            = gt.Calls
 		transfersValue = stack.Back(2).Sign() != 0
 	)
-	name, err := common.BigToName(stack.Back(1))
-	if err != nil {
-		return 0, err
-	}
-	accountExist, _ := evm.AccountDB.AccountIsExist(name)
-	if transfersValue && accountExist {
-		gas += params.CallNewAccountGas
-	}
 	if transfersValue {
 		gas += params.CallValueTransferGas
 	}
@@ -381,6 +373,10 @@ func gasRevert(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, m
 	return memoryGasCost(mem, memorySize)
 }
 
+func gasInvalid(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
+	return 0, nil
+}
+
 func gasSuicide(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
 	var gas uint64
 	//todo
@@ -428,6 +424,10 @@ func gasDelegateCall(gt params.GasTable, evm *EVM, contract *Contract, stack *St
 	return gas, nil
 }
 
+func gasIssueAsset(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
+	return gt.IssueAsset, nil
+}
+
 func gasBalanceex(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
 	return gt.Balance, nil
 }
@@ -437,16 +437,37 @@ func gasGetAssetAmount(gt params.GasTable, evm *EVM, contract *Contract, stack *
 }
 
 func gasSnapBalance(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
-	return gt.GetAssetAmount, nil
+	return gt.SnapBalance, nil
+}
+
+func gasGetAccountTime(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
+	return gt.GetAccountTime, nil
 }
 
 func gasGetSnapshotTime(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
 	return gt.GetSnapshotTime, nil
 }
 
+func gasCryptoCalc(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
+	return gt.CryptoCalc, nil
+}
+
+func gasGetDelegate(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
+	return gt.GetDelegate, nil
+}
 func gasAddAsset(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
 
-	return params.CallValueTransferGas + gt.Calls, nil
+	return gt.AddAsset, nil
+}
+
+func gasGetAccountID(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
+
+	return gt.GetAccountID, nil
+}
+
+func gasDestroyAsset(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
+
+	return gt.DestroyAsset, nil
 }
 
 func gasSetAssetOwner(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
diff --git a/processor/vm/instructions.go b/processor/vm/instructions.go
index 5ee794e8..45758878 100644
--- a/processor/vm/instructions.go
+++ b/processor/vm/instructions.go
@@ -18,6 +18,7 @@ package vm
 
 import (
 	"bytes"
+	"crypto/rand"
 	"errors"
 	"fmt"
 	"math/big"
@@ -25,10 +26,12 @@ import (
 	"strings"
 
 	"github.com/ethereum/go-ethereum/common/math"
+	"github.com/ethereum/go-ethereum/log"
 	"github.com/fractalplatform/fractal/accountmanager"
 	"github.com/fractalplatform/fractal/asset"
 	"github.com/fractalplatform/fractal/common"
 	"github.com/fractalplatform/fractal/crypto"
+	"github.com/fractalplatform/fractal/crypto/ecies"
 	"github.com/fractalplatform/fractal/params"
 	"github.com/fractalplatform/fractal/types"
 	"github.com/fractalplatform/fractal/utils/rlp"
@@ -395,6 +398,26 @@ func opAddress(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *
 	return nil, nil
 }
 
+func opGetAccountTime(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
+	account := stack.pop()
+	userID := account.Uint64()
+	acct, err := evm.AccountDB.GetAccountById(userID)
+	if err != nil || acct == nil {
+		stack.push(evm.interpreter.intPool.getZero())
+		return nil, nil
+	}
+
+	number := acct.GetAccountNumber()
+	head := evm.Context.GetHeaderByNumber(number)
+	if head == nil {
+		stack.push(evm.interpreter.intPool.getZero())
+	} else {
+		time := head.Time.Uint64()
+		stack.push(evm.interpreter.intPool.get().SetUint64(time))
+	}
+	return nil, nil
+}
+
 func opGetSnapshotTime(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
 	time, num := stack.pop(), stack.pop()
 	index := num.Uint64()
@@ -423,19 +446,76 @@ func opGetAssetAmount(pc *uint64, evm *EVM, contract *Contract, memory *Memory,
 	return nil, nil
 }
 
+func opGetDelegate(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
+	time, account := stack.pop(), stack.pop()
+	t := time.Uint64()
+	userID := account.Uint64()
+
+	acct, err := evm.AccountDB.GetAccountById(userID)
+	if err == nil {
+		if acct != nil {
+			name := acct.GetName()
+			if dbalance, totalDelegate, totalNum, err := evm.Context.GetDelegatedByTime(name.String(), t, evm.StateDB); err == nil {
+				stack.push(dbalance)
+				stack.push(totalDelegate)
+				stack.push(evm.interpreter.intPool.get().SetUint64(totalNum))
+			}
+		} else {
+			err = errors.New("account object is null")
+		}
+	}
+
+	if err != nil {
+		stack.push(evm.interpreter.intPool.getZero())
+		stack.push(evm.interpreter.intPool.getZero())
+		stack.push(evm.interpreter.intPool.getZero())
+	}
+	evm.interpreter.intPool.put(time, account)
+	return nil, nil
+}
+
 func opSnapBalance(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
-	time, assetId, account := stack.pop(), stack.pop(), stack.pop()
+	opt, time, assetId, account := stack.pop(), stack.pop(), stack.pop(), stack.pop()
+	o := opt.Uint64()
 	assetID := assetId.Uint64()
 	t := time.Uint64()
-	name, err := common.BigToName(account)
-	if err != nil {
-		return nil, err
+	userID := account.Uint64()
+
+	var rbalance = big.NewInt(0)
+
+	acct, err := evm.AccountDB.GetAccountById(userID)
+
+	if o >= 4 {
+		err = errors.New("type id is error")
 	}
-	balance, err := evm.AccountDB.GetBalanceByTime(name, assetID, t)
+
+	if err == nil {
+		if acct != nil {
+			name := acct.GetName()
+			var id uint64
+			if o == 2 || o == 3 {
+				id = 1
+			}
+
+			if balance, err := evm.AccountDB.GetBalanceByTime(name, assetID, id, t); err == nil {
+				if (o == 1 || o == 3) && (assetID == evm.chainConfig.SysTokenID) {
+					if dbalance, _, _, err := evm.Context.GetDelegatedByTime(name.String(), t, evm.StateDB); err == nil {
+						rbalance = new(big.Int).Add(balance, dbalance)
+					}
+				} else {
+					rbalance = balance
+				}
+
+			}
+		} else {
+			err = errors.New("account object is null")
+		}
+	}
+
 	if err != nil {
 		stack.push(evm.interpreter.intPool.getZero())
 	} else {
-		stack.push(balance)
+		stack.push(rbalance)
 	}
 	evm.interpreter.intPool.put(time, assetId)
 	return nil, nil
@@ -443,12 +523,13 @@ func opSnapBalance(pc *uint64, evm *EVM, contract *Contract, memory *Memory, sta
 func opBalanceex(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
 	assetId := stack.pop()
 	slot := stack.peek()
-	name, err := common.BigToName(slot)
+	userID := slot.Uint64()
+	account, err := evm.AccountDB.GetAccountById(userID)
 	if err != nil {
 		slot.Set(big.NewInt(0))
 		return nil, nil
 	}
-	account, _ := evm.AccountDB.GetAccountByName(name)
+
 	if account == nil {
 		slot.Set(big.NewInt(0))
 		return nil, nil
@@ -460,12 +541,14 @@ func opBalanceex(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack
 
 func opBalance(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
 	slot := stack.peek()
-	name, err := common.BigToName(slot)
+	userID := slot.Uint64()
+	//name, err := common.BigToName(slot)
+	account, err := evm.AccountDB.GetAccountById(userID)
 	if err != nil {
 		slot.Set(big.NewInt(0))
 		return nil, nil
 	}
-	account, _ := evm.AccountDB.GetAccountByName(name)
+	//account, _ := evm.AccountDB.GetAccountByName(name)
 	if account == nil {
 		slot.Set(big.NewInt(0))
 		return nil, nil
@@ -537,17 +620,19 @@ func opReturnDataCopy(pc *uint64, evm *EVM, contract *Contract, memory *Memory,
 
 func opExtCodeSize(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
 	slot := stack.peek()
-	name, err := common.BigToName(slot)
+	//name, err := common.BigToName(slot)
+	userID := slot.Uint64()
+	acct, err := evm.AccountDB.GetAccountById(userID)
 	if err != nil {
 		slot.SetUint64(0)
 		return nil, nil
 	}
-	account, _ := evm.AccountDB.GetAccountByName(name)
-	if account == nil {
+	if acct == nil {
 		slot.SetUint64(0)
 		return nil, nil
 	}
-	codeSize := account.GetCodeSize()
+
+	codeSize := acct.GetCodeSize()
 	slot.SetUint64(uint64(codeSize))
 	return nil, nil
 }
@@ -574,18 +659,14 @@ func opCodeCopy(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack
 
 func opExtCodeCopy(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
 	var (
+		addr       = stack.pop()
 		memOffset  = stack.pop()
 		codeOffset = stack.pop()
 		length     = stack.pop()
 	)
-	name, err := common.BigToName(stack.pop())
-	if err != nil {
-		memory.Set(memOffset.Uint64(), length.Uint64(), nil)
-		evm.interpreter.intPool.put(memOffset, codeOffset, length)
-		return nil, nil
-	}
-	account, _ := evm.AccountDB.GetAccountByName(name)
-	if account == nil {
+
+	account, err := evm.AccountDB.GetAccountById(addr.Uint64())
+	if err != nil || account == nil {
 		memory.Set(memOffset.Uint64(), length.Uint64(), nil)
 		evm.interpreter.intPool.put(memOffset, codeOffset, length)
 	} else {
@@ -640,6 +721,11 @@ func opGasLimit(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack
 	return nil, nil
 }
 
+func opCallAssetId(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
+	stack.push(evm.interpreter.intPool.get().SetUint64(contract.AssetId))
+	return nil, nil
+}
+
 func opPop(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
 	evm.interpreter.intPool.put(stack.pop())
 	return nil, nil
@@ -776,8 +862,16 @@ func opCall(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Sta
 	gas := evm.callGasTemp
 	// Pop other call parameters.
 	name, value, inOffset, inSize, retOffset, retSize := stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop()
-	toName, _ := common.BigToName(name)
 	value = math.U256(value)
+	//toName, _ := common.BigToName(name)
+	userID := name.Uint64()
+	acct, err := evm.AccountDB.GetAccountById(userID)
+	if err != nil || acct == nil {
+		stack.push(evm.interpreter.intPool.getZero())
+		return nil, nil
+	}
+	toName := acct.GetName()
+
 	// Get the arguments from the memory.
 	args := memory.Get(inOffset.Int64(), inSize.Int64())
 
@@ -785,7 +879,7 @@ func opCall(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Sta
 		gas += params.CallStipend
 	}
 
-	action := types.NewAction(types.Transfer, contract.Name(), toName, 0, evm.AssetID, gas, value, args)
+	action := types.NewAction(types.CallContract, contract.Name(), toName, 0, evm.AssetID, gas, value, args)
 
 	ret, returnGas, err := evm.Call(contract, action, gas)
 	if err != nil {
@@ -799,6 +893,14 @@ func opCall(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Sta
 	contract.Gas += returnGas
 
 	evm.interpreter.intPool.put(name, value, inOffset, inSize, retOffset, retSize)
+	if evm.vmConfig.ContractLogFlag {
+		errmsg := ""
+		if err != nil {
+			errmsg = err.Error()
+		}
+		internalAction := &types.InternalAction{Action: action.NewRPCAction(0), ActionType: "call", GasUsed: gas - returnGas, GasLimit: gas, Depth: uint64(evm.depth), Error: errmsg}
+		evm.InternalTxs = append(evm.InternalTxs, internalAction)
+	}
 	return ret, nil
 }
 
@@ -810,7 +912,16 @@ func opCallCode(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack
 	//addr, value, inOffset, inSize, retOffset, retSize := stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop()
 	name, value, inOffset, inSize, retOffset, retSize := stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop()
 	//addr, assetId,value, inOffset, inSize, retOffset, retSize := stack.pop(),stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop()
-	toName, _ := common.BigToName(name)
+	//toName, _ := common.BigToName(name)
+	userID := name.Uint64()
+	acct, err := evm.AccountDB.GetAccountById(userID)
+	if err != nil || acct == nil {
+		stack.push(evm.interpreter.intPool.getZero())
+		return nil, nil
+	}
+
+	toName := acct.GetName()
+
 	value = math.U256(value)
 	// Get arguments from the memory.
 	args := memory.Get(inOffset.Int64(), inSize.Int64())
@@ -819,7 +930,7 @@ func opCallCode(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack
 		gas += params.CallStipend
 	}
 	// todo
-	action := types.NewAction(types.Transfer, contract.Name(), toName, 0, evm.AssetID, gas, value, args)
+	action := types.NewAction(types.CallContract, contract.Name(), toName, 0, evm.AssetID, gas, value, args)
 
 	ret, returnGas, err := evm.CallCode(contract, action, gas)
 	if err != nil {
@@ -833,6 +944,14 @@ func opCallCode(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack
 	contract.Gas += returnGas
 
 	evm.interpreter.intPool.put(name, value, inOffset, inSize, retOffset, retSize)
+	if evm.vmConfig.ContractLogFlag {
+		errmsg := ""
+		if err != nil {
+			errmsg = err.Error()
+		}
+		internalAction := &types.InternalAction{Action: action.NewRPCAction(0), ActionType: "callcode", GasUsed: gas - returnGas, GasLimit: gas, Depth: uint64(evm.depth), Error: errmsg}
+		evm.InternalTxs = append(evm.InternalTxs, internalAction)
+	}
 	return ret, nil
 }
 
@@ -842,11 +961,26 @@ func opDelegateCall(pc *uint64, evm *EVM, contract *Contract, memory *Memory, st
 	gas := evm.callGasTemp
 	// Pop other call parameters.
 	name, inOffset, inSize, retOffset, retSize := stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop()
-	toName, _ := common.BigToName(name)
+	//change id to name
+	acct, err := evm.AccountDB.GetAccountById(name.Uint64())
+	if err != nil || acct == nil {
+		stack.push(evm.interpreter.intPool.getZero())
+		return nil, nil
+	}
+	// if err != nil {
+	// 	stack.push(evm.interpreter.intPool.getZero())
+	// 	return nil, err
+	// }
+	// if acct == nil {
+	// 	stack.push(evm.interpreter.intPool.getZero())
+	// 	return nil, fmt.Errorf("account is not exist")
+	// }
+	//toName, _ := common.BigToName(name)
+
 	// Get arguments from the memory.
 	args := memory.Get(inOffset.Int64(), inSize.Int64())
 
-	ret, returnGas, err := evm.DelegateCall(contract, toName, args, gas)
+	ret, returnGas, err := evm.DelegateCall(contract, acct.GetName(), args, gas)
 	if err != nil {
 		stack.push(evm.interpreter.intPool.getZero())
 	} else {
@@ -864,32 +998,163 @@ func opDelegateCall(pc *uint64, evm *EVM, contract *Contract, memory *Memory, st
 //multi-asset
 //Increase asset already exist
 func opAddAsset(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
-	value, assetId := stack.pop(), stack.pop()
+	value, to, assetId := stack.pop(), stack.pop(), stack.pop()
 	assetID := assetId.Uint64()
+	//toName, _ := common.BigToName(to)
 	value = math.U256(value)
+	userID := to.Uint64()
+	acct, err := evm.AccountDB.GetAccountById(userID)
+	if err != nil || acct == nil {
+		stack.push(evm.interpreter.intPool.getZero())
+		return nil, nil
+	}
 
-	err := execAddAsset(evm, contract, assetID, value)
+	err = execAddAsset(evm, contract, assetID, acct.GetName(), value)
 
 	if err != nil {
 		stack.push(evm.interpreter.intPool.getZero())
 	} else {
 		stack.push(evm.interpreter.intPool.get().SetUint64(1))
 	}
-	return nil, err
+	return nil, nil
 }
 
-func execAddAsset(evm *EVM, contract *Contract, assetID uint64, value *big.Int) error {
-	asset := &accountmanager.IncAsset{AssetId: assetID, Amount: value, To: contract.CallerName}
+func execAddAsset(evm *EVM, contract *Contract, assetID uint64, toName common.Name, value *big.Int) error {
+	asset := &accountmanager.IncAsset{AssetId: assetID, Amount: value, To: toName}
 	b, err := rlp.EncodeToBytes(asset)
 	if err != nil {
 		return err
 	}
-	action := types.NewAction(types.IncreaseAsset, contract.CallerName, "", 0, 0, 0, big.NewInt(0), b)
 
-	err = evm.AccountDB.Process(action)
+	action := types.NewAction(types.IncreaseAsset, contract.CallerName, common.Name(evm.chainConfig.AccountName), 0, evm.chainConfig.SysTokenID, 0, big.NewInt(0), b)
+
+	internalActions, err := evm.AccountDB.Process(&types.AccountManagerContext{Action: action, Number: evm.Context.BlockNumber.Uint64()})
+	if evm.vmConfig.ContractLogFlag {
+		errmsg := ""
+		if err != nil {
+			errmsg = err.Error()
+		}
+		internalAction := &types.InternalAction{Action: action.NewRPCAction(0), ActionType: "addasset", GasUsed: 0, GasLimit: contract.Gas, Depth: uint64(evm.depth), Error: errmsg}
+		evm.InternalTxs = append(evm.InternalTxs, internalAction)
+		if len(internalActions) > 0 {
+			for _, iLog := range internalActions {
+				iLog.Depth = uint64(evm.depth)
+			}
+			evm.InternalTxs = append(evm.InternalTxs, internalActions...)
+		}
+	}
 	return err
 }
 
+func opDestroyAsset(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
+	value, assetID := stack.pop(), stack.pop()
+	astID := assetID.Uint64()
+
+	action := types.NewAction(types.DestroyAsset, contract.CallerName, common.Name(evm.chainConfig.AccountName), 0, astID, 0, value, nil)
+
+	internalActions, err := evm.AccountDB.Process(&types.AccountManagerContext{Action: action, Number: evm.Context.BlockNumber.Uint64()})
+	if evm.vmConfig.ContractLogFlag {
+		errmsg := ""
+		if err != nil {
+			errmsg = err.Error()
+		}
+		internalAction := &types.InternalAction{Action: action.NewRPCAction(0), ActionType: "destroyasset", GasUsed: 0, GasLimit: contract.Gas, Depth: uint64(evm.depth), Error: errmsg}
+		evm.InternalTxs = append(evm.InternalTxs, internalAction)
+		if len(internalActions) > 0 {
+			for _, iLog := range internalActions {
+				iLog.Depth = uint64(evm.depth)
+			}
+			evm.InternalTxs = append(evm.InternalTxs, internalActions...)
+		}
+	}
+
+	if err != nil {
+		stack.push(evm.interpreter.intPool.getZero())
+	} else {
+		stack.push(evm.interpreter.intPool.get().SetUint64(astID))
+	}
+	evm.interpreter.intPool.put(assetID)
+	return nil, nil
+}
+
+func opGetAccountID(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
+	account := stack.pop()
+	name, _ := common.BigToName(account)
+
+	if acct, err := evm.AccountDB.GetAccountByName(name); err == nil {
+		if acct != nil {
+			stack.push(evm.interpreter.intPool.get().SetUint64(acct.GetAccountID()))
+		} else {
+			stack.push(evm.interpreter.intPool.getZero())
+		}
+	} else {
+		stack.push(evm.interpreter.intPool.getZero())
+	}
+
+	evm.interpreter.intPool.put(account)
+	return nil, nil
+}
+
+// opCryptoCalc to encrypt or decrypt bytes
+func opCryptoCalc(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
+	typeID, retOffset, retSize, offset2, size2, offset, size := stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop()
+	//
+	data := memory.Get(offset.Int64(), size.Int64())
+	key := memory.Get(offset2.Int64(), size2.Int64())
+	i := typeID.Uint64()
+	//
+	var ret = make([]byte, retSize.Int64()*32)
+	var datalen int
+	var err error
+
+	//consume gas per byte
+	contract.Gas = contract.Gas - uint64(size.Int64())*params.GasTableInstanse.CryptoByte
+
+	if i == 0 {
+		//Encrypt
+		ecdsapubkey, err := crypto.UnmarshalPubkey(key)
+		if err == nil {
+			eciespubkey := ecies.ImportECDSAPublic(ecdsapubkey)
+			ret, err = ecies.Encrypt(rand.Reader, eciespubkey, data, nil, nil)
+			if err == nil {
+				datalen = len(ret)
+				if uint64(datalen) > retSize.Uint64()*32 {
+					err = errors.New("Encrypt error")
+				}
+			}
+
+		}
+
+	} else if i == 1 {
+		ecdsaprikey, err := crypto.ToECDSA(key)
+		//
+		if err == nil {
+			eciesprikey := ecies.ImportECDSA(ecdsaprikey)
+			//ret, err = prv1.Decrypt(data, nil, nil)
+			ret, err = eciesprikey.Decrypt(data, nil, nil)
+			//pintg
+			if err == nil {
+				datalen = len(ret)
+				if uint64(datalen) > retSize.Uint64()*32 {
+					err = errors.New("Decrypt error")
+				}
+			}
+		}
+	}
+
+	if err != nil {
+		stack.push(evm.interpreter.intPool.getZero())
+	} else {
+		//write datalen data real length
+		stack.push(evm.interpreter.intPool.get().SetUint64(uint64(datalen)))
+		//write data
+		memory.Set(retOffset.Uint64(), uint64(datalen), ret)
+	}
+
+	evm.interpreter.intPool.put(offset, size, offset2, size2, typeID)
+	return nil, nil
+}
+
 //issue an asset for multi-asset
 func opIssueAsset(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
 	offset, size := stack.pop(), stack.pop()
@@ -897,63 +1162,92 @@ func opIssueAsset(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stac
 	ret = bytes.TrimRight(ret, "\x00")
 	desc := string(ret)
 
-	err := executeIssuseAsset(evm, contract, desc)
+	assetId, err := executeIssuseAsset(evm, contract, desc)
 	if err != nil {
 		stack.push(evm.interpreter.intPool.getZero())
 	} else {
-		stack.push(evm.interpreter.intPool.get().SetUint64(1))
+		stack.push(evm.interpreter.intPool.get().SetUint64(assetId))
 	}
 	evm.interpreter.intPool.put(offset, size)
-	return nil, err
+	return nil, nil
 }
 
-func executeIssuseAsset(evm *EVM, contract *Contract, desc string) error {
+func executeIssuseAsset(evm *EVM, contract *Contract, desc string) (uint64, error) {
 	input := strings.Split(desc, ",")
 	if len(input) != 7 {
-		return fmt.Errorf("invalid desc string")
+		return 0, fmt.Errorf("invalid desc string")
 	}
 	name := input[0]
 	symbol := input[1]
 	total, ifOK := new(big.Int).SetString(input[2], 10)
 	if !ifOK {
-		return fmt.Errorf("amount not correct")
+		return 0, fmt.Errorf("amount not correct")
 	}
 	decimal, err := strconv.ParseUint(input[3], 10, 64)
 	if err != nil {
-		return err
+		return 0, err
 	}
 	owner := common.Name(input[4])
 	limit, ifOK := new(big.Int).SetString(input[5], 10)
 	if !ifOK {
-		return fmt.Errorf("amount not correct")
+		return 0, fmt.Errorf("amount not correct")
 	}
 	founder := common.Name(input[6])
 	asset := &asset.AssetObject{AssetName: name, Symbol: symbol, Amount: total, Owner: owner, Founder: founder, Decimals: decimal, UpperLimit: limit}
 
 	b, err := rlp.EncodeToBytes(asset)
 	if err != nil {
-		return err
+		return 0, err
 	}
-	action := types.NewAction(types.IssueAsset, contract.CallerName, "", 0, 0, 0, big.NewInt(0), b)
+	action := types.NewAction(types.IssueAsset, contract.CallerName, common.Name(evm.chainConfig.AccountName), 0, evm.chainConfig.SysTokenID, 0, big.NewInt(0), b)
 
-	return evm.AccountDB.Process(action)
+	internalActions, err := evm.AccountDB.Process(&types.AccountManagerContext{Action: action, Number: evm.Context.BlockNumber.Uint64()})
+	if err != nil {
+		return 0, err
+	} else {
+		assetInfo, err := evm.AccountDB.GetAssetInfoByName(name)
+		if err != nil || assetInfo == nil {
+			return 0, err
+		} else {
+			if evm.vmConfig.ContractLogFlag {
+				errmsg := ""
+				if err != nil {
+					errmsg = err.Error()
+				}
+				internalAction := &types.InternalAction{Action: action.NewRPCAction(0), ActionType: "issueasset", GasUsed: 0, GasLimit: contract.Gas, Depth: uint64(evm.depth), Error: errmsg}
+				evm.InternalTxs = append(evm.InternalTxs, internalAction)
+				if len(internalActions) > 0 {
+					for _, iLog := range internalActions {
+						iLog.Depth = uint64(evm.depth)
+					}
+					evm.InternalTxs = append(evm.InternalTxs, internalActions...)
+				}
+			}
+			return assetInfo.AssetId, nil
+		}
+	}
 }
 
 //issue an asset for multi-asset
 func opSetAssetOwner(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
 	newOwner, assetId := stack.pop(), stack.pop()
-	newOwnerName, _ := common.BigToName(newOwner)
+	//newOwnerName, _ := common.BigToName(newOwner)
+	userID := newOwner.Uint64()
+	acct, err := evm.AccountDB.GetAccountById(userID)
+	if err != nil || acct == nil {
+		stack.push(evm.interpreter.intPool.getZero())
+		return nil, nil
+	}
 	assetID := assetId.Uint64()
 
-	err := execSetAssetOwner(evm, contract, assetID, newOwnerName)
+	err = execSetAssetOwner(evm, contract, assetID, acct.GetName())
 	if err != nil {
 		stack.push(evm.interpreter.intPool.getZero())
 	} else {
 		stack.push(evm.interpreter.intPool.get().SetUint64(1))
 	}
-	//todo
 	evm.interpreter.intPool.put(newOwner, assetId)
-	return nil, err
+	return nil, nil
 }
 
 func execSetAssetOwner(evm *EVM, contract *Contract, assetID uint64, owner common.Name) error {
@@ -963,9 +1257,23 @@ func execSetAssetOwner(evm *EVM, contract *Contract, assetID uint64, owner commo
 		return err
 	}
 
-	action := types.NewAction(types.SetAssetOwner, contract.CallerName, "", 0, 0, 0, big.NewInt(0), b)
-	return evm.AccountDB.Process(action)
-
+	action := types.NewAction(types.SetAssetOwner, contract.CallerName, common.Name(evm.chainConfig.AccountName), 0, evm.chainConfig.SysTokenID, 0, big.NewInt(0), b)
+	internalActions, err := evm.AccountDB.Process(&types.AccountManagerContext{Action: action, Number: evm.Context.BlockNumber.Uint64()})
+	if evm.vmConfig.ContractLogFlag {
+		errmsg := ""
+		if err != nil {
+			errmsg = err.Error()
+		}
+		internalAction := &types.InternalAction{Action: action.NewRPCAction(0), ActionType: "setassetowner", GasUsed: 0, GasLimit: contract.Gas, Depth: uint64(evm.depth), Error: errmsg}
+		evm.InternalTxs = append(evm.InternalTxs, internalAction)
+		if len(internalActions) > 0 {
+			for _, iLog := range internalActions {
+				iLog.Depth = uint64(evm.depth)
+			}
+			evm.InternalTxs = append(evm.InternalTxs, internalActions...)
+		}
+	}
+	return err
 }
 
 func opCallEx(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
@@ -973,7 +1281,16 @@ func opCallEx(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *S
 	evm.interpreter.intPool.put(stack.pop())
 	gas := evm.callGasTemp
 	name, assetId, value, inOffset, inSize, retOffset, retSize := stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop()
-	toName, _ := common.BigToName(name)
+
+	//toName, _ := common.BigToName(name)
+	userID := name.Uint64()
+	acct, err := evm.AccountDB.GetAccountById(userID)
+	if err != nil || acct == nil {
+		stack.push(evm.interpreter.intPool.getZero())
+		return nil, nil
+	}
+	toName := acct.GetName()
+
 	assetID := assetId.Uint64()
 	value = math.U256(value)
 	args := memory.Get(inOffset.Int64(), inSize.Int64())
@@ -982,7 +1299,7 @@ func opCallEx(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *S
 		gas += params.CallStipend
 	}
 
-	action := types.NewAction(types.Transfer, contract.Name(), toName, 0, assetID, gas, value, args)
+	action := types.NewAction(types.CallContract, contract.Name(), toName, 0, assetID, gas, value, args)
 
 	ret, returnGas, err := evm.Call(contract, action, gas)
 	if err != nil {
@@ -996,6 +1313,14 @@ func opCallEx(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *S
 	contract.Gas += returnGas
 
 	evm.interpreter.intPool.put(name, value, inOffset, inSize, retOffset, retSize)
+	if evm.vmConfig.ContractLogFlag {
+		errmsg := ""
+		if err != nil {
+			errmsg = err.Error()
+		}
+		internalAction := &types.InternalAction{Action: action.NewRPCAction(0), ActionType: "transferex", GasUsed: 0, GasLimit: gas, Depth: uint64(evm.depth), Error: errmsg}
+		evm.InternalTxs = append(evm.InternalTxs, internalAction)
+	}
 	return ret, nil
 }
 
@@ -1005,7 +1330,16 @@ func opStaticCall(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stac
 	gas := evm.callGasTemp
 	// Pop other call parameters.
 	name, inOffset, inSize, retOffset, retSize := stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop()
-	toName, _ := common.BigToName(name)
+
+	//toName, _ := common.BigToName(name)
+	userID := name.Uint64()
+	acct, err := evm.AccountDB.GetAccountById(userID)
+	if err != nil || acct == nil {
+		stack.push(evm.interpreter.intPool.getZero())
+		return nil, nil
+	}
+	toName := acct.GetName()
+
 	// Get arguments from the memory.
 	args := memory.Get(inOffset.Int64(), inSize.Int64())
 
@@ -1021,6 +1355,14 @@ func opStaticCall(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stac
 	contract.Gas += returnGas
 
 	evm.interpreter.intPool.put(name, inOffset, inSize, retOffset, retSize)
+	if evm.vmConfig.ContractLogFlag {
+		errmsg := ""
+		if err != nil {
+			errmsg = err.Error()
+		}
+		internalAction := &types.InternalAction{ActionType: "staticcall", GasUsed: gas - returnGas, GasLimit: gas, Depth: uint64(evm.depth), Error: errmsg}
+		evm.InternalTxs = append(evm.InternalTxs, internalAction)
+	}
 	return ret, nil
 }
 
@@ -1044,6 +1386,11 @@ func opStop(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Sta
 	return nil, nil
 }
 
+func opInvalid(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
+	log.Error("invalid opcode ")
+	return nil, nil
+}
+
 func opSuicide(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
 	//todo
 	// contractCreater := common.BigToAddress(stack.pop())
diff --git a/processor/vm/interpreter.go b/processor/vm/interpreter.go
index 73a4d703..baacbff8 100644
--- a/processor/vm/interpreter.go
+++ b/processor/vm/interpreter.go
@@ -44,10 +44,11 @@ type Config struct {
 	// JumpTable contains the EVM instruction table. This
 	// may be left uninitialised and will be set to the default
 	// table.
-	JumpTable [256]operation
+	JumpTable       [256]operation
+	ContractLogFlag bool
 }
 
-// Interpreter is used to run Ethereum based contracts and will utilise the
+// Interpreter is used to run based contracts and will utilise the
 // passed evmironment to query external sources for state information.
 // The Interpreter will run the byte code VM or JIT VM based on the passed
 // configuration.
diff --git a/processor/vm/jump_table.go b/processor/vm/jump_table.go
index 8f348cd4..718637a9 100644
--- a/processor/vm/jump_table.go
+++ b/processor/vm/jump_table.go
@@ -91,6 +91,14 @@ func NewByzantiumInstructionSet() [256]operation {
 	instructionSet := NewHomesteadInstructionSet()
 
 	//multi-asset InstructionSet
+	instructionSet[GETACCOUNTTIME] = operation{
+		execute:       opGetAccountTime,
+		gasCost:       gasGetAccountTime,
+		validateStack: makeStackFunc(1, 1),
+		valid:         true,
+		returns:       true,
+	}
+
 	instructionSet[SNAPSHOTTIME] = operation{
 		execute:       opGetSnapshotTime,
 		gasCost:       gasGetSnapshotTime,
@@ -99,6 +107,22 @@ func NewByzantiumInstructionSet() [256]operation {
 		returns:       true,
 	}
 
+	instructionSet[CRYPTOCALC] = operation{
+		execute:       opCryptoCalc,
+		gasCost:       gasCryptoCalc,
+		validateStack: makeStackFunc(2, 1),
+		valid:         true,
+		returns:       true,
+	}
+
+	instructionSet[GETDELEGATE] = operation{
+		execute:       opGetDelegate,
+		gasCost:       gasGetDelegate,
+		validateStack: makeStackFunc(2, 1),
+		valid:         true,
+		returns:       true,
+	}
+
 	instructionSet[ASSETAMOUNT] = operation{
 		execute:       opGetAssetAmount,
 		gasCost:       gasGetAssetAmount,
@@ -133,13 +157,29 @@ func NewByzantiumInstructionSet() [256]operation {
 
 	instructionSet[ISSUEASSET] = operation{
 		execute:       opIssueAsset,
-		gasCost:       gasCreate,
+		gasCost:       gasIssueAsset,
 		validateStack: makeStackFunc(1, 1),
 		memorySize:    memoryReturn,
 		valid:         true,
 		returns:       true,
 	}
 
+	instructionSet[DESTROYASSET] = operation{
+		execute:       opDestroyAsset,
+		gasCost:       gasDestroyAsset,
+		validateStack: makeStackFunc(1, 1),
+		valid:         true,
+		returns:       true,
+	}
+
+	instructionSet[GETACCOUNTID] = operation{
+		execute:       opGetAccountID,
+		gasCost:       gasGetAccountID,
+		validateStack: makeStackFunc(1, 1),
+		valid:         true,
+		returns:       true,
+	}
+
 	instructionSet[SETASSETOWNER] = operation{
 		execute:       opSetAssetOwner,
 		gasCost:       gasSetAssetOwner,
@@ -186,6 +226,14 @@ func NewByzantiumInstructionSet() [256]operation {
 		reverts:       true,
 		returns:       true,
 	}
+	instructionSet[INVALID] = operation{
+		execute:       opInvalid,
+		gasCost:       gasInvalid,
+		validateStack: makeStackFunc(0, 0),
+		valid:         false,
+		reverts:       true,
+		returns:       true,
+	}
 	return instructionSet
 }
 
@@ -471,6 +519,12 @@ func NewFrontierInstructionSet() [256]operation {
 			validateStack: makeStackFunc(0, 1),
 			valid:         true,
 		},
+		CALLASSETID: {
+			execute:       opCallAssetId,
+			gasCost:       constGasFunc(GasQuickStep),
+			validateStack: makeStackFunc(0, 1),
+			valid:         true,
+		},
 		POP: {
 			execute:       opPop,
 			gasCost:       constGasFunc(GasQuickStep),
diff --git a/processor/vm/memory.go b/processor/vm/memory.go
index de5f4359..f9dc3a3e 100644
--- a/processor/vm/memory.go
+++ b/processor/vm/memory.go
@@ -18,7 +18,7 @@ package vm
 
 import "fmt"
 
-// Memory implements a simple memory model for the ethereum virtual machine.
+// Memory implements a simple memory model for the virtual machine.
 type Memory struct {
 	store       []byte
 	lastGasCost uint64
diff --git a/processor/vm/opcodes.go b/processor/vm/opcodes.go
index 398abc77..1347d435 100644
--- a/processor/vm/opcodes.go
+++ b/processor/vm/opcodes.go
@@ -97,6 +97,7 @@ const (
 	NUMBER
 	DIFFICULTY
 	GASLIMIT
+	CALLASSETID
 )
 
 const (
@@ -209,6 +210,13 @@ const (
 	//snapshot num
 	SNAPSHOTTIME = 0xc6
 	SNAPBALANCE  = 0xc7
+	//
+	DESTROYASSET = 0xc8
+	GETACCOUNTID = 0xc9
+
+	GETDELEGATE    = 0xca
+	GETACCOUNTTIME = 0xcb
+	CRYPTOCALC     = 0xcc
 )
 
 const (
@@ -220,7 +228,9 @@ const (
 	DELEGATECALL
 	STATICCALL = 0xfa
 
-	REVERT       = 0xfd
+	REVERT = 0xfd
+	///< invalid instruction for expressing runtime errors (e.g., division-by-zero)
+	INVALID      = 0xfe
 	SELFDESTRUCT = 0xff
 )
 
@@ -277,12 +287,13 @@ var opCodeToString = map[OpCode]string{
 	RETURNDATACOPY: "RETURNDATACOPY",
 
 	// 0x40 range - block operations
-	BLOCKHASH:  "BLOCKHASH",
-	COINBASE:   "COINBASE",
-	TIMESTAMP:  "TIMESTAMP",
-	NUMBER:     "NUMBER",
-	DIFFICULTY: "DIFFICULTY",
-	GASLIMIT:   "GASLIMIT",
+	BLOCKHASH:   "BLOCKHASH",
+	COINBASE:    "COINBASE",
+	TIMESTAMP:   "TIMESTAMP",
+	NUMBER:      "NUMBER",
+	DIFFICULTY:  "DIFFICULTY",
+	GASLIMIT:    "GASLIMIT",
+	CALLASSETID: "CALLASSETID",
 
 	// 0x50 range - 'storage' and execution
 	POP: "POP",
@@ -379,7 +390,7 @@ var opCodeToString = map[OpCode]string{
 	RETURN:       "RETURN",
 	CALLCODE:     "CALLCODE",
 	DELEGATECALL: "DELEGATECALL",
-	//add new asset for multi-asset
+	//0xc0 range add new asset for multi-asset
 	BALANCEEX:     "BALANCEEX",
 	SETASSETOWNER: "SETASSETOWNER",
 	ADDASSET:      "ADDASSET",
@@ -388,6 +399,7 @@ var opCodeToString = map[OpCode]string{
 	ASSETAMOUNT:   "ASSETAMOUNT",
 	SNAPBALANCE:   "SNAPBALANCE",
 	CALLEX:        "CALLEX",
+	CRYPTOCALC:    "CRYPTOCALC",
 	//add end
 	STATICCALL:   "STATICCALL",
 	REVERT:       "REVERT",
@@ -459,6 +471,7 @@ var stringToOp = map[string]OpCode{
 	"NUMBER":         NUMBER,
 	"DIFFICULTY":     DIFFICULTY,
 	"GASLIMIT":       GASLIMIT,
+	"CALLASSETID":    CALLASSETID,
 	"POP":            POP,
 	"MLOAD":          MLOAD,
 	"MSTORE":         MSTORE,
diff --git a/processor/vm/runtime/contract/Asset/Asset.abi b/processor/vm/runtime/contract/Asset/Asset.abi
index 0c0ed6ed..0653a58b 100644
--- a/processor/vm/runtime/contract/Asset/Asset.abi
+++ b/processor/vm/runtime/contract/Asset/Asset.abi
@@ -1 +1 @@
-[{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"newOwner","type":"address"},{"name":"assetId","type":"address"}],"name":"setname","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"desc","type":"string"}],"name":"reg","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"to","type":"address"},{"name":"assetId","type":"address"}],"name":"getbalance","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"t","type":"uint256"},{"name":"time","type":"uint256"}],"name":"getSnapshotTime","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"assetId","type":"uint256"},{"name":"time","type":"uint256"}],"name":"getAssetAmount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"to","type":"address"},{"name":"assetId","type":"address"},{"name":"value","type":"uint256"}],"name":"transAsset","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[{"name":"to","type":"address"},{"name":"assetId","type":"uint256"},{"name":"time","type":"uint256"}],"name":"getSnapBalance","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"assetId","type":"address"},{"name":"value","type":"uint256"}],"name":"add","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"inputs":[],"payable":false,"stateMutability":"nonpayable","type":"constructor"}]
+[{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"desc","type":"string"}],"name":"reg","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"to","type":"address"},{"name":"assetId","type":"uint256"},{"name":"value","type":"uint256"}],"name":"transAsset","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[{"name":"to","type":"address"},{"name":"assetId","type":"uint256"}],"name":"getbalance","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"i","type":"uint256"},{"name":"t","type":"uint256"}],"name":"getSnapshotTime","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"newOwner","type":"address"},{"name":"assetId","type":"uint256"}],"name":"setname","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"assetId","type":"uint256"},{"name":"to","type":"address"},{"name":"value","type":"uint256"}],"name":"add","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"assetId","type":"uint256"},{"name":"t","type":"uint256"}],"name":"getAssetAmount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"getAssetId","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"to","type":"address"},{"name":"assetId","type":"uint256"},{"name":"t","type":"uint256"}],"name":"getSnapBalance","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"inputs":[],"payable":false,"stateMutability":"nonpayable","type":"constructor"}]
\ No newline at end of file
diff --git a/processor/vm/runtime/contract/Asset/Asset.bin b/processor/vm/runtime/contract/Asset/Asset.bin
index a84b7d24..ec2d9bd3 100644
--- a/processor/vm/runtime/contract/Asset/Asset.bin
+++ b/processor/vm/runtime/contract/Asset/Asset.bin
@@ -1 +1 @@
-608060405234801561001057600080fd5b50600a60008190555061057e806100286000396000f300608060405260043610610099576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806318160ddd1461009e578063373db6e7146100c95780634708293e1461012c57806350ec07c3146101955780637a727a411461020c578063d639ec4214610257578063ef9ba08c146102a2578063f208415e14610302578063f5d82b6b1461036d575b600080fd5b3480156100aa57600080fd5b506100b36103ba565b6040518082815260200191505060405180910390f35b3480156100d557600080fd5b5061012a600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506103c0565b005b34801561013857600080fd5b50610193600480360381019080803590602001908201803590602001908080601f0160208091040260200160405190810160405280939291908181526020018383808284378201915050505050509192919290505050610405565b005b3480156101a157600080fd5b506101f6600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610426565b6040518082815260200191505060405180910390f35b34801561021857600080fd5b50610241600480360381019080803590602001909291908035906020019092919050505061045f565b6040518082815260200191505060405180910390f35b34801561026357600080fd5b5061028c600480360381019080803590602001909291908035906020019092919050505061047e565b6040518082815260200191505060405180910390f35b610300600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035906020019092919050505061049d565b005b34801561030e57600080fd5b50610357600480360381019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035906020019092919080359060200190929190505050610503565b6040518082815260200191505060405180910390f35b34801561037957600080fd5b506103b8600480360381019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610523565b005b60005481565b8073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16c2158015610400573d6000803e3d6000fd5b505050565b8060200160405181900390c0158015610422573d6000803e3d6000fd5b5050565b60008273ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16c3905092915050565b60008282c5158015610475573d6000803e3d6000fd5b50905092915050565b60008282c7158015610494573d6000803e3d6000fd5b50905092915050565b8273ffffffffffffffffffffffffffffffffffffffff166108fc8373ffffffffffffffffffffffffffffffffffffffff168391821502919060405160006040518083038186868a8ac49450505050501580156104fd573d6000803e3d6000fd5b50505050565b60008282c7158015610519573d6000803e3d6000fd5b5090509392505050565b8173ffffffffffffffffffffffffffffffffffffffff1681c115801561054d573d6000803e3d6000fd5b5050505600a165627a7a7230582066c0f473454398e8329129efd6ffe74c03d2c99b6af9bff1698952d6299457ae0029
+608060405234801561001057600080fd5b50600a60008190555061052d806100286000396000f3006080604052600436106100a4576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806318160ddd146100a95780634708293e146100d457806368669bc8146101515780636d1837e21461019b5780637a727a41146101fc578063a9a9591c14610247578063b9955e3914610294578063d639ec42146102eb578063d6e2280c14610336578063f208415e14610361575b600080fd5b3480156100b557600080fd5b506100be6103cc565b6040518082815260200191505060405180910390f35b3480156100e057600080fd5b5061013b600480360381019080803590602001908201803590602001908080601f01602080910402602001604051908101604052809392919081815260200183838082843782019150505050505091929192905050506103d2565b6040518082815260200191505060405180910390f35b610199600480360381019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190803590602001909291905050506103e7565b005b3480156101a757600080fd5b506101e6600480360381019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610437565b6040518082815260200191505060405180910390f35b34801561020857600080fd5b50610231600480360381019080803590602001909291908035906020019092919050505061045a565b6040518082815260200191505060405180910390f35b34801561025357600080fd5b50610292600480360381019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610467565b005b3480156102a057600080fd5b506102e960048036038101908080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610496565b005b3480156102f757600080fd5b5061032060048036038101908080359060200190929190803590602001909291905050506104c7565b6040518082815260200191505060405180910390f35b34801561034257600080fd5b5061034b6104d4565b6040518082815260200191505060405180910390f35b34801561036d57600080fd5b506103b6600480360381019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190803590602001909291905050506104dc565b6040518082815260200191505060405180910390f35b60005481565b60008160200160405181900390c09050919050565b8273ffffffffffffffffffffffffffffffffffffffff166108fc838391821502919060405160006040518083038186868a8ac4945050505050158015610431573d6000803e3d6000fd5b50505050565b60008273ffffffffffffffffffffffffffffffffffffffff1682c3905092915050565b60008282c6905092915050565b808273ffffffffffffffffffffffffffffffffffffffff16c2158015610491573d6000803e3d6000fd5b505050565b828273ffffffffffffffffffffffffffffffffffffffff1682c11580156104c1573d6000803e3d6000fd5b50505050565b60008282c5905092915050565b600046905090565b60008373ffffffffffffffffffffffffffffffffffffffff168383c7905093925050505600a165627a7a723058201544c4304e893e9e0562168fc30a297842bc2c02e97895027ebab587362711e00029
\ No newline at end of file
diff --git a/processor/vm/runtime/contract/Asset/Asset.sol b/processor/vm/runtime/contract/Asset/Asset.sol
index a52aac95..2a12b665 100644
--- a/processor/vm/runtime/contract/Asset/Asset.sol
+++ b/processor/vm/runtime/contract/Asset/Asset.sol
@@ -7,19 +7,22 @@ contract Asset {
         totalSupply = 10;
     }
 
-    function reg(string desc) public {
-        issueasset(desc);
+    function reg(string desc) public returns(uint256){
+        return issueasset(desc);
     }
-    function add(address assetId, uint256 value) public {
-        addasset(assetId,value);
+    function add(uint assetId, address to, uint256 value) public {
+        addasset(assetId,to,value);
     }
-    function transAsset(address to, address assetId, uint256 value) public payable {
+    function getAssetId() public returns (uint256) {
+        return msg.assetid;
+    }
+    function transAsset(address to, uint assetId, uint256 value) public payable {
         to.transferex(assetId, value);
     }
-    function setname(address newOwner, address assetId) public {
+    function setname(address newOwner, uint assetId) public {
         setassetowner(assetId, newOwner);
     }
-    function getbalance(address to, address assetId) public returns(uint) {
+    function getbalance(address to, uint assetId) public returns(uint256) {
         return to.balanceex(assetId);
     }
     function getAssetAmount(uint256 assetId, uint256 t) public returns (uint256){
diff --git a/processor/vm/runtime/contract/Ven/VEN.bin b/processor/vm/runtime/contract/Ven/VEN.bin
index acd439b4..aedd5afb 100644
--- a/processor/vm/runtime/contract/Ven/VEN.bin
+++ b/processor/vm/runtime/contract/Ven/VEN.bin
@@ -1 +1 @@
-608060405234801561001057600080fd5b50336000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506120fe806100606000396000f3006080604052600436106100f1576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806306fdde0314610103578063095ea7b31461019357806313af4035146101f857806318160ddd1461023b57806323b872dd14610266578063313ce567146102eb5780633fb27b851461031c578063534eb1d414610333578063631f98521461036057806370a082311461038f5780637ba49b81146103e65780638da5cb5b1461044957806395d89b41146104a0578063a9059cbb14610530578063b5e7324914610595578063cae9ca51146105fe578063dd62ed3e146106a9575b3480156100fd57600080fd5b50600080fd5b34801561010f57600080fd5b50610118610720565b6040518080602001828103825283818151815260200191508051906020019080838360005b8381101561015857808201518184015260208101905061013d565b50505050905090810190601f1680156101855780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561019f57600080fd5b506101de600480360381019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610759565b604051808215151515815260200191505060405180910390f35b34801561020457600080fd5b50610239600480360381019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919050505061084b565b005b34801561024757600080fd5b506102506108e9565b6040518082815260200191505060405180910390f35b34801561027257600080fd5b506102d1600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610924565b604051808215151515815260200191505060405180910390f35b3480156102f757600080fd5b50610300610ce7565b604051808260ff1660ff16815260200191505060405180910390f35b34801561032857600080fd5b50610331610cec565b005b34801561033f57600080fd5b5061035e60048036038101908080359060200190929190505050610d53565b005b34801561036c57600080fd5b50610375610ea5565b604051808215151515815260200191505060405180910390f35b34801561039b57600080fd5b506103d0600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610ee6565b6040518082815260200191505060405180910390f35b3480156103f257600080fd5b50610427600480360381019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919050505061129d565b604051808263ffffffff1663ffffffff16815260200191505060405180910390f35b34801561045557600080fd5b5061045e6112f9565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b3480156104ac57600080fd5b506104b561131e565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156104f55780820151818401526020810190506104da565b50505050905090810190601f1680156105225780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561053c57600080fd5b5061057b600480360381019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050611357565b604051808215151515815260200191505060405180910390f35b3480156105a157600080fd5b506105fc600480360381019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190803515159060200190929190803563ffffffff169060200190929190505050611607565b005b34801561060a57600080fd5b5061068f600480360381019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190803590602001908201803590602001908080601f0160208091040260200160405190810160405280939291908181526020018383808284378201915050505050509192919290505050611a2d565b604051808215151515815260200191505060405180910390f35b3480156106b557600080fd5b5061070a600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050611c7c565b6040518082815260200191505060405180910390f35b6040805190810160405280600d81526020017f5665436861696e20546f6b656e0000000000000000000000000000000000000081525081565b600081600360003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925846040518082815260200191505060405180910390a36001905092915050565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161415156108a657600080fd5b806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b6000600160000160009054906101000a90046fffffffffffffffffffffffffffffffff166fffffffffffffffffffffffffffffffff16905090565b600061092e610ea5565b151561093957600080fd5b61094284611d03565b61094b83611d03565b81600260008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060000160009054906101000a90046dffffffffffffffffffffffffffff166dffffffffffffffffffffffffffff1610158015610a43575081600360008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205410155b8015610a4f5750600082115b15610cdb5781600260008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060000160008282829054906101000a90046dffffffffffffffffffffffffffff160392506101000a8154816dffffffffffffffffffffffffffff02191690836dffffffffffffffffffffffffffff16021790555081600360008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282540392505081905550610bf9610bf4600260008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060000160009054906101000a90046dffffffffffffffffffffffffffff166dffffffffffffffffffffffffffff168461200190919063ffffffff16565b61201f565b600260008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060000160006101000a8154816dffffffffffffffffffffffffffff02191690836dffffffffffffffffffffffffffff1602179055508273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040518082815260200191505060405180910390a360019050610ce0565b600090505b9392505050565b601281565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141515610d4757600080fd5b610d51600061084b565b565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141515610dae57600080fd5b610dc38160045461200190919063ffffffff16565b600481905550610e17610e12600160000160009054906101000a90046fffffffffffffffffffffffffffffffff166fffffffffffffffffffffffffffffffff168361200190919063ffffffff16565b612044565b600160000160006101000a8154816fffffffffffffffffffffffffffffffff02191690836fffffffffffffffffffffffffffffffff1602179055503073ffffffffffffffffffffffffffffffffffffffff1660007fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef836040518082815260200191505060405180910390a350565b6000806000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614905090565b6000806000600260008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600001600e9054906101000a90046dffffffffffffffffffffffffffff166dffffffffffffffffffffffffffff161415610fd257600260008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060000160009054906101000a90046dffffffffffffffffffffffffffff166dffffffffffffffffffffffffffff169150611297565b600060045411156111a9576110a3600160000160109054906101000a90046fffffffffffffffffffffffffffffffff166fffffffffffffffffffffffffffffffff16611095600260008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600001600e9054906101000a90046dffffffffffffffffffffffffffff166dffffffffffffffffffffffffffff1660045461206b90919063ffffffff16565b61209e90919063ffffffff16565b90506111a2600260008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600001600e9054906101000a90046dffffffffffffffffffffffffffff166dffffffffffffffffffffffffffff16611194600260008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060000160009054906101000a90046dffffffffffffffffffffffffffff166dffffffffffffffffffffffffffff168461200190919063ffffffff16565b61200190919063ffffffff16565b9150611297565b611294600260008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600001600e9054906101000a90046dffffffffffffffffffffffffffff166dffffffffffffffffffffffffffff16600260008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060000160009054906101000a90046dffffffffffffffffffffffffffff166dffffffffffffffffffffffffffff1661200190919063ffffffff16565b91505b50919050565b6000600260008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600001601c9054906101000a900463ffffffff169050919050565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6040805190810160405280600381526020017f56454e000000000000000000000000000000000000000000000000000000000081525081565b6000611361610ea5565b151561136c57600080fd5b61137533611d03565b61137e83611d03565b81600260003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060000160009054906101000a90046dffffffffffffffffffffffffffff166dffffffffffffffffffffffffffff16101580156113fa5750600082115b156115fc5781600260003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060000160008282829054906101000a90046dffffffffffffffffffffffffffff160392506101000a8154816dffffffffffffffffffffffffffff02191690836dffffffffffffffffffffffffffff16021790555061151a611515600260008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060000160009054906101000a90046dffffffffffffffffffffffffffff166dffffffffffffffffffffffffffff168461200190919063ffffffff16565b61201f565b600260008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060000160006101000a8154816dffffffffffffffffffffffffffff02191690836dffffffffffffffffffffffffffff1602179055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040518082815260200191505060405180910390a360019050611601565b600090505b92915050565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614151561166257600080fd5b81156117f1576116ef6116ea600260008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600001600e9054906101000a90046dffffffffffffffffffffffffffff166dffffffffffffffffffffffffffff168561200190919063ffffffff16565b61201f565b600260008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600001600e6101000a8154816dffffffffffffffffffffffffffff02191690836dffffffffffffffffffffffffffff1602179055506117b16117ac600160000160109054906101000a90046fffffffffffffffffffffffffffffffff166fffffffffffffffffffffffffffffffff168561200190919063ffffffff16565b612044565b600160000160106101000a8154816fffffffffffffffffffffffffffffffff02191690836fffffffffffffffffffffffffffffffff1602179055506118ed565b611878611873600260008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060000160009054906101000a90046dffffffffffffffffffffffffffff166dffffffffffffffffffffffffffff168561200190919063ffffffff16565b61201f565b600260008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060000160006101000a8154816dffffffffffffffffffffffffffff02191690836dffffffffffffffffffffffffffff1602179055505b80600260008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600001601c6101000a81548163ffffffff021916908363ffffffff16021790555061199c611997600160000160009054906101000a90046fffffffffffffffffffffffffffffffff166fffffffffffffffffffffffffffffffff168561200190919063ffffffff16565b612044565b600160000160006101000a8154816fffffffffffffffffffffffffffffffff02191690836fffffffffffffffffffffffffffffffff1602179055508373ffffffffffffffffffffffffffffffffffffffff1660007fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef856040518082815260200191505060405180910390a350505050565b600082600360003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508373ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925856040518082815260200191505060405180910390a38373ffffffffffffffffffffffffffffffffffffffff16638f4ffcb1338530866040518563ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018481526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200180602001828103825283818151815260200191508051906020019080838360005b83811015611c0a578082015181840152602081019050611bef565b50505050905090810190601f168015611c375780820380516001836020036101000a031916815260200191505b5095505050505050600060405180830381600087803b158015611c5957600080fd5b505af1158015611c6d573d6000803e3d6000fd5b50505050600190509392505050565b6000600360008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905092915050565b600080611d0e610ea5565b1515611d1957600080fd5b6000600260008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600001600e9054906101000a90046dffffffffffffffffffffffffffff166dffffffffffffffffffffffffffff16141515611ffc57611d9883610ee6565b9150611e97600260008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600001600e9054906101000a90046dffffffffffffffffffffffffffff166dffffffffffffffffffffffffffff16611e89600260008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060000160009054906101000a90046dffffffffffffffffffffffffffff166dffffffffffffffffffffffffffff16856120b990919063ffffffff16565b6120b990919063ffffffff16565b9050611ea28261201f565b600260008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060000160006101000a8154816dffffffffffffffffffffffffffff02191690836dffffffffffffffffffffffffffff1602179055506000600260008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600001600e6101000a8154816dffffffffffffffffffffffffffff02191690836dffffffffffffffffffffffffffff1602179055506000811115611ffb578273ffffffffffffffffffffffffffffffffffffffff163073ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef836040518082815260200191505060405180910390a35b5b505050565b600080828401905083811015151561201557fe5b8091505092915050565b600081826dffffffffffffffffffffffffffff1614151561203c57fe5b819050919050565b600081826fffffffffffffffffffffffffffffffff1614151561206357fe5b819050919050565b6000808284029050600084148061208c575082848281151561208957fe5b04145b151561209457fe5b8091505092915050565b60008082848115156120ac57fe5b0490508091505092915050565b60008282111515156120c757fe5b8183039050929150505600a165627a7a723058202ff76a5df53438c019cbf5aa49ea7ebb97fb08962bea8bacb83815c11e9440bc0029
\ No newline at end of file
+608060405234801561001057600080fd5b50336000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506120fe806100606000396000f3006080604052600436106100f1576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806306fdde0314610103578063095ea7b31461019357806313af4035146101f857806318160ddd1461023b57806323b872dd14610266578063313ce567146102eb5780633fb27b851461031c578063534eb1d414610333578063631f98521461036057806370a082311461038f5780637ba49b81146103e65780638da5cb5b1461044957806395d89b41146104a0578063a9059cbb14610530578063b5e7324914610595578063cae9ca51146105fe578063dd62ed3e146106a9575b3480156100fd57600080fd5b50600080fd5b34801561010f57600080fd5b50610118610720565b6040518080602001828103825283818151815260200191508051906020019080838360005b8381101561015857808201518184015260208101905061013d565b50505050905090810190601f1680156101855780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561019f57600080fd5b506101de600480360381019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610759565b604051808215151515815260200191505060405180910390f35b34801561020457600080fd5b50610239600480360381019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919050505061084b565b005b34801561024757600080fd5b506102506108e9565b6040518082815260200191505060405180910390f35b34801561027257600080fd5b506102d1600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610924565b604051808215151515815260200191505060405180910390f35b3480156102f757600080fd5b50610300610ce7565b604051808260ff1660ff16815260200191505060405180910390f35b34801561032857600080fd5b50610331610cec565b005b34801561033f57600080fd5b5061035e60048036038101908080359060200190929190505050610d53565b005b34801561036c57600080fd5b50610375610ea5565b604051808215151515815260200191505060405180910390f35b34801561039b57600080fd5b506103d0600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610ee6565b6040518082815260200191505060405180910390f35b3480156103f257600080fd5b50610427600480360381019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919050505061129d565b604051808263ffffffff1663ffffffff16815260200191505060405180910390f35b34801561045557600080fd5b5061045e6112f9565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b3480156104ac57600080fd5b506104b561131e565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156104f55780820151818401526020810190506104da565b50505050905090810190601f1680156105225780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561053c57600080fd5b5061057b600480360381019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050611357565b604051808215151515815260200191505060405180910390f35b3480156105a157600080fd5b506105fc600480360381019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190803515159060200190929190803563ffffffff169060200190929190505050611607565b005b34801561060a57600080fd5b5061068f600480360381019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190803590602001908201803590602001908080601f0160208091040260200160405190810160405280939291908181526020018383808284378201915050505050509192919290505050611a2d565b604051808215151515815260200191505060405180910390f35b3480156106b557600080fd5b5061070a600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050611c7c565b6040518082815260200191505060405180910390f35b6040805190810160405280600d81526020017f5665436861696e20546f6b656e0000000000000000000000000000000000000081525081565b600081600360003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925846040518082815260200191505060405180910390a36001905092915050565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161415156108a657600080fd5b806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b6000600160000160009054906101000a90046fffffffffffffffffffffffffffffffff166fffffffffffffffffffffffffffffffff16905090565b600061092e610ea5565b151561093957600080fd5b61094284611d03565b61094b83611d03565b81600260008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060000160009054906101000a90046dffffffffffffffffffffffffffff166dffffffffffffffffffffffffffff1610158015610a43575081600360008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205410155b8015610a4f5750600082115b15610cdb5781600260008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060000160008282829054906101000a90046dffffffffffffffffffffffffffff160392506101000a8154816dffffffffffffffffffffffffffff02191690836dffffffffffffffffffffffffffff16021790555081600360008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282540392505081905550610bf9610bf4600260008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060000160009054906101000a90046dffffffffffffffffffffffffffff166dffffffffffffffffffffffffffff168461200190919063ffffffff16565b61201f565b600260008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060000160006101000a8154816dffffffffffffffffffffffffffff02191690836dffffffffffffffffffffffffffff1602179055508273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040518082815260200191505060405180910390a360019050610ce0565b600090505b9392505050565b601281565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141515610d4757600080fd5b610d51600061084b565b565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141515610dae57600080fd5b610dc38160045461200190919063ffffffff16565b600481905550610e17610e12600160000160009054906101000a90046fffffffffffffffffffffffffffffffff166fffffffffffffffffffffffffffffffff168361200190919063ffffffff16565b612044565b600160000160006101000a8154816fffffffffffffffffffffffffffffffff02191690836fffffffffffffffffffffffffffffffff1602179055503073ffffffffffffffffffffffffffffffffffffffff1660007fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef836040518082815260200191505060405180910390a350565b6000806000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614905090565b6000806000600260008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600001600e9054906101000a90046dffffffffffffffffffffffffffff166dffffffffffffffffffffffffffff161415610fd257600260008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060000160009054906101000a90046dffffffffffffffffffffffffffff166dffffffffffffffffffffffffffff169150611297565b600060045411156111a9576110a3600160000160109054906101000a90046fffffffffffffffffffffffffffffffff166fffffffffffffffffffffffffffffffff16611095600260008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600001600e9054906101000a90046dffffffffffffffffffffffffffff166dffffffffffffffffffffffffffff1660045461206b90919063ffffffff16565b61209e90919063ffffffff16565b90506111a2600260008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600001600e9054906101000a90046dffffffffffffffffffffffffffff166dffffffffffffffffffffffffffff16611194600260008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060000160009054906101000a90046dffffffffffffffffffffffffffff166dffffffffffffffffffffffffffff168461200190919063ffffffff16565b61200190919063ffffffff16565b9150611297565b611294600260008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600001600e9054906101000a90046dffffffffffffffffffffffffffff166dffffffffffffffffffffffffffff16600260008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060000160009054906101000a90046dffffffffffffffffffffffffffff166dffffffffffffffffffffffffffff1661200190919063ffffffff16565b91505b50919050565b6000600260008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600001601c9054906101000a900463ffffffff169050919050565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6040805190810160405280600381526020017f56454e000000000000000000000000000000000000000000000000000000000081525081565b6000611361610ea5565b151561136c57600080fd5b61137533611d03565b61137e83611d03565b81600260003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060000160009054906101000a90046dffffffffffffffffffffffffffff166dffffffffffffffffffffffffffff16101580156113fa5750600082115b156115fc5781600260003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060000160008282829054906101000a90046dffffffffffffffffffffffffffff160392506101000a8154816dffffffffffffffffffffffffffff02191690836dffffffffffffffffffffffffffff16021790555061151a611515600260008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060000160009054906101000a90046dffffffffffffffffffffffffffff166dffffffffffffffffffffffffffff168461200190919063ffffffff16565b61201f565b600260008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060000160006101000a8154816dffffffffffffffffffffffffffff02191690836dffffffffffffffffffffffffffff1602179055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040518082815260200191505060405180910390a360019050611601565b600090505b92915050565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614151561166257600080fd5b81156117f1576116ef6116ea600260008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600001600e9054906101000a90046dffffffffffffffffffffffffffff166dffffffffffffffffffffffffffff168561200190919063ffffffff16565b61201f565b600260008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600001600e6101000a8154816dffffffffffffffffffffffffffff02191690836dffffffffffffffffffffffffffff1602179055506117b16117ac600160000160109054906101000a90046fffffffffffffffffffffffffffffffff166fffffffffffffffffffffffffffffffff168561200190919063ffffffff16565b612044565b600160000160106101000a8154816fffffffffffffffffffffffffffffffff02191690836fffffffffffffffffffffffffffffffff1602179055506118ed565b611878611873600260008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060000160009054906101000a90046dffffffffffffffffffffffffffff166dffffffffffffffffffffffffffff168561200190919063ffffffff16565b61201f565b600260008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060000160006101000a8154816dffffffffffffffffffffffffffff02191690836dffffffffffffffffffffffffffff1602179055505b80600260008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600001601c6101000a81548163ffffffff021916908363ffffffff16021790555061199c611997600160000160009054906101000a90046fffffffffffffffffffffffffffffffff166fffffffffffffffffffffffffffffffff168561200190919063ffffffff16565b612044565b600160000160006101000a8154816fffffffffffffffffffffffffffffffff02191690836fffffffffffffffffffffffffffffffff1602179055508373ffffffffffffffffffffffffffffffffffffffff1660007fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef856040518082815260200191505060405180910390a350505050565b600082600360003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508373ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925856040518082815260200191505060405180910390a38373ffffffffffffffffffffffffffffffffffffffff16638f4ffcb1338530866040518563ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018481526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200180602001828103825283818151815260200191508051906020019080838360005b83811015611c0a578082015181840152602081019050611bef565b50505050905090810190601f168015611c375780820380516001836020036101000a031916815260200191505b5095505050505050600060405180830381600087803b158015611c5957600080fd5b505af1158015611c6d573d6000803e3d6000fd5b50505050600190509392505050565b6000600360008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905092915050565b600080611d0e610ea5565b1515611d1957600080fd5b6000600260008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600001600e9054906101000a90046dffffffffffffffffffffffffffff166dffffffffffffffffffffffffffff16141515611ffc57611d9883610ee6565b9150611e97600260008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600001600e9054906101000a90046dffffffffffffffffffffffffffff166dffffffffffffffffffffffffffff16611e89600260008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060000160009054906101000a90046dffffffffffffffffffffffffffff166dffffffffffffffffffffffffffff16856120b990919063ffffffff16565b6120b990919063ffffffff16565b9050611ea28261201f565b600260008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060000160006101000a8154816dffffffffffffffffffffffffffff02191690836dffffffffffffffffffffffffffff1602179055506000600260008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600001600e6101000a8154816dffffffffffffffffffffffffffff02191690836dffffffffffffffffffffffffffff1602179055506000811115611ffb578273ffffffffffffffffffffffffffffffffffffffff163073ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef836040518082815260200191505060405180910390a35b5b505050565b600080828401905083811015151561201557fe5b8091505092915050565b600081826dffffffffffffffffffffffffffff1614151561203c57fe5b819050919050565b600081826fffffffffffffffffffffffffffffffff1614151561206357fe5b819050919050565b6000808284029050600084148061208c575082848281151561208957fe5b04145b151561209457fe5b8091505092915050565b60008082848115156120ac57fe5b0490508091505092915050565b60008282111515156120c757fe5b8183039050929150505600a165627a7a72305820d98b3e8d875a9111c363e3ed54adcdeca8e2b8ad2bd564788aad4821ff5bcb020029
\ No newline at end of file
diff --git a/processor/vm/runtime/contract/Ven/BNB.sol b/processor/vm/runtime/contract/Ven/VEN.sol
similarity index 96%
rename from processor/vm/runtime/contract/Ven/BNB.sol
rename to processor/vm/runtime/contract/Ven/VEN.sol
index 3b88ca8e..edede68e 100644
--- a/processor/vm/runtime/contract/Ven/BNB.sol
+++ b/processor/vm/runtime/contract/Ven/VEN.sol
@@ -382,7 +382,7 @@ contract VENSale is Owned{
     address venVault; // the account to keep non-public offered VEN tokens
 
     uint public constant startTime = 1503057600; // time to start sale
-    uint public constant endTime = 1812010800;   // tiem to close sale
+    uint public constant endTime = 1504180800;   // tiem to close sale
     uint public constant earlyStageLasts = 3 days; // early bird stage lasts in seconds
 
     bool initialized;
diff --git a/processor/vm/runtime/contract/Ven/VENSale.bin b/processor/vm/runtime/contract/Ven/VENSale.bin
index b33dd04d..269e6306 100644
--- a/processor/vm/runtime/contract/Ven/VENSale.bin
+++ b/processor/vm/runtime/contract/Ven/VENSale.bin
@@ -1 +1 @@
-608060405234801561001057600080fd5b50336000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060018060000160006101000a81548161ffff021916908361ffff160217905550611c66806100806000396000f300608060405260043610610107576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806313af403514610111578063165a0e031461015457806318160ddd1461017f5780633197cbb6146101aa5780633ba0b9a9146101d557806348b15166146102005780634bb278f3146102375780635e84d7231461024e57806369d4f28e1461027957806378e97925146102a457806384386004146102cf578063873c56d7146102fa5780638da5cb5b14610325578063a6f2ae3a1461037c578063ab96dd1814610386578063c040e6b8146103b1578063c0c53b8b146103ea578063de009e7f1461046d578063ff91b949146104ba575b61010f6104e5565b005b34801561011d57600080fd5b50610152600480360381019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506109ca565b005b34801561016057600080fd5b50610169610a68565b6040518082815260200191505060405180910390f35b34801561018b57600080fd5b50610194610af9565b6040518082815260200191505060405180910390f35b3480156101b657600080fd5b506101bf610b09565b6040518082815260200191505060405180910390f35b3480156101e157600080fd5b506101ea610b11565b6040518082815260200191505060405180910390f35b34801561020c57600080fd5b50610215610b8e565b604051808263ffffffff1663ffffffff16815260200191505060405180910390f35b34801561024357600080fd5b5061024c610b96565b005b34801561025a57600080fd5b50610263610ec3565b6040518082815260200191505060405180910390f35b34801561028557600080fd5b5061028e610f47565b6040518082815260200191505060405180910390f35b3480156102b057600080fd5b506102b9610f80565b6040518082815260200191505060405180910390f35b3480156102db57600080fd5b506102e4610f88565b6040518082815260200191505060405180910390f35b34801561030657600080fd5b5061030f610fc1565b6040518082815260200191505060405180910390f35b34801561033157600080fd5b5061033a610fd0565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6103846104e5565b005b34801561039257600080fd5b5061039b610ff5565b6040518082815260200191505060405180910390f35b3480156103bd57600080fd5b506103c6610ffc565b604051808260068111156103d657fe5b60ff16815260200191505060405180910390f35b3480156103f657600080fd5b5061046b600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506111c4565b005b34801561047957600080fd5b506104b8600480360381019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035906020019092919050505061175c565b005b3480156104c657600080fd5b506104cf611add565b6040518082815260200191505060405180910390f35b60008060008060006104f633611b53565b15151561050257600080fd5b662386f26fc10000341015151561051857600080fd5b610520610b11565b945060008511151561053157600080fd5b610708600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16637ba49b81336040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050602060405180830381600087803b1580156105f157600080fd5b505af1158015610605573d6000803e3d6000fd5b505050506040513d602081101561061b57600080fd5b810190808051906020019092919050505063ffffffff160161063b610b8e565b63ffffffff161015151561064e57600080fd5b6801a055690d9db800003411156106825761067b856801a055690d9db80000611b8f90919063ffffffff16565b9350610698565b6106958534611b8f90919063ffffffff16565b93505b6106e7600160000160029054906101000a90046effffffffffffffffffffffffffffff166effffffffffffffffffffffffffffff166a353f43a026da2053240000611bc290919063ffffffff16565b9250828411156106f5578293505b6107088585611bdb90919063ffffffff16565b9150600084111561095d57600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663b5e732493386600161075d610b8e565b6040518563ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001848152602001831515151581526020018263ffffffff1663ffffffff168152602001945050505050600060405180830381600087803b15801561080057600080fd5b505af1158015610814573d6000803e3d6000fd5b50505050600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc839081150290604051600060405180830381858888f19350505050158015610880573d6000803e3d6000fd5b506108cd6108c8600160000160029054906101000a90046effffffffffffffffffffffffffffff166effffffffffffffffffffffffffffff1686611bf690919063ffffffff16565b611c14565b600160000160026101000a8154816effffffffffffffffffffffffffffff02191690836effffffffffffffffffffffffffffff1602179055503373ffffffffffffffffffffffffffffffffffffffff167f4d1636c3e75537f2cbca3bdf3cf2c7825eb501463bc634e6923119dee5d1cc438584604051808381526020018281526020019250505060405180910390a25b6109708234611bc290919063ffffffff16565b905060008111156109c3573373ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f193505050501580156109c1573d6000803e3d6000fd5b505b5050505050565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141515610a2557600080fd5b806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b6a353f43a026da2053240000606460166b033b2e3c9fd0803ce800000002811515610a8f57fe5b04606460056b033b2e3c9fd0803ce800000002811515610aab57fe5b04606460176b033b2e3c9fd0803ce800000002811515610ac757fe5b04606460096b033b2e3c9fd0803ce800000002811515610ae357fe5b040101016b033b2e3c9fd0803ce8000000030381565b6b033b2e3c9fd0803ce800000081565b636c01173081565b600060036006811115610b2057fe5b610b28610ffc565b6006811115610b3357fe5b1415610b56576064600f610dac02811515610b4a57fe5b04610dac019050610b8b565b60046006811115610b6357fe5b610b6b610ffc565b6006811115610b7657fe5b1415610b8657610dac9050610b8b565b600090505b90565b600042905090565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141515610bf357600080fd5b60056006811115610c0057fe5b610c08610ffc565b6006811115610c1357fe5b141515610c1f57600080fd5b610d26600160000160119054906101000a90046effffffffffffffffffffffffffffff166effffffffffffffffffffffffffffff16610d18600160000160029054906101000a90046effffffffffffffffffffffffffffff166effffffffffffffffffffffffffffff16606460166b033b2e3c9fd0803ce800000002811515610ca457fe5b04606460056b033b2e3c9fd0803ce800000002811515610cc057fe5b04606460176b033b2e3c9fd0803ce800000002811515610cdc57fe5b04606460096b033b2e3c9fd0803ce800000002811515610cf857fe5b040101016b033b2e3c9fd0803ce800000003611bc290919063ffffffff16565b611bc290919063ffffffff16565b90506000811115610ddb57600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663534eb1d4826040518263ffffffff167c010000000000000000000000000000000000000000000000000000000002815260040180828152602001915050600060405180830381600087803b158015610dc257600080fd5b505af1158015610dd6573d6000803e3d6000fd5b505050505b600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16633fb27b856040518163ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401600060405180830381600087803b158015610e6157600080fd5b505af1158015610e75573d6000803e3d6000fd5b505050506001600460156101000a81548160ff0219169083151502179055507f6c750432a9907ef296a47d6b38305b8ad777291aefc349e462a0a3285799425460405160405180910390a150565b606460166b033b2e3c9fd0803ce800000002811515610ede57fe5b04606460056b033b2e3c9fd0803ce800000002811515610efa57fe5b04606460176b033b2e3c9fd0803ce800000002811515610f1657fe5b04606460096b033b2e3c9fd0803ce800000002811515610f3257fe5b040101016b033b2e3c9fd0803ce80000000381565b6000600160000160029054906101000a90046effffffffffffffffffffffffffffff166effffffffffffffffffffffffffffff16905090565b635996d6c081565b6000600160000160119054906101000a90046effffffffffffffffffffffffffffff166effffffffffffffffffffffffffffff16905090565b6a353f43a026da205324000081565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6203f48081565b6000600460159054906101000a900460ff161561101c57600690506111c1565b600460149054906101000a900460ff16151561103b57600190506111c1565b635996d6c0611048610b8e565b63ffffffff16101561105d57600290506111c1565b606460166b033b2e3c9fd0803ce80000000281151561107857fe5b04606460056b033b2e3c9fd0803ce80000000281151561109457fe5b04606460176b033b2e3c9fd0803ce8000000028115156110b057fe5b04606460096b033b2e3c9fd0803ce8000000028115156110cc57fe5b040101016b033b2e3c9fd0803ce800000003611153600160000160119054906101000a90046effffffffffffffffffffffffffffff166effffffffffffffffffffffffffffff16600160000160029054906101000a90046effffffffffffffffffffffffffffff166effffffffffffffffffffffffffffff16611bf690919063ffffffff16565b10151561116357600590506111c1565b636c011730611170610b8e565b63ffffffff1610156111bc576111966203f480635996d6c0611bf690919063ffffffff16565b61119e610b8e565b63ffffffff1610156111b357600390506111c1565b600490506111c1565b600590505b90565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614151561121f57600080fd5b6001600681111561122c57fe5b611234610ffc565b600681111561123f57fe5b14151561124b57600080fd5b3073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16638da5cb5b6040518163ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401602060405180830381600087803b1580156112c657600080fd5b505af11580156112da573d6000803e3d6000fd5b505050506040513d60208110156112f057600080fd5b810190808051906020019092919050505073ffffffffffffffffffffffffffffffffffffffff1614151561132357600080fd5b60008273ffffffffffffffffffffffffffffffffffffffff161415151561134957600080fd5b60008173ffffffffffffffffffffffffffffffffffffffff161415151561136f57600080fd5b82600260006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555081600360006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555080600460006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663b5e73249600460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff166114dc606460166b033b2e3c9fd0803ce8000000028115156114b157fe5b04606460056b033b2e3c9fd0803ce8000000028115156114cd57fe5b04611bf690919063ffffffff16565b60006114e6610b8e565b6040518563ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001848152602001831515151581526020018263ffffffff1663ffffffff168152602001945050505050600060405180830381600087803b15801561158957600080fd5b505af115801561159d573d6000803e3d6000fd5b50505050600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663b5e73249600460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1661164b606460176b033b2e3c9fd0803ce80000000281151561162057fe5b04606460096b033b2e3c9fd0803ce80000000281151561163c57fe5b04611bf690919063ffffffff16565b6001611655610b8e565b6040518563ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001848152602001831515151581526020018263ffffffff1663ffffffff168152602001945050505050600060405180830381600087803b1580156116f857600080fd5b505af115801561170c573d6000803e3d6000fd5b505050506001600460146101000a81548160ff0219169083151502179055507f1b0e25e2531ab5dbde6724b973ffb1819ece38c4a44247d242e5079db9ce461160405160405180910390a1505050565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161415156117b957600080fd5b6117c1610ffc565b9050600360068111156117d057fe5b8160068111156117dc57fe5b14806117fe5750600460068111156117f057fe5b8160068111156117fc57fe5b145b8061181f57506005600681111561181157fe5b81600681111561181d57fe5b145b151561182a57600080fd5b611876611871600160000160119054906101000a90046effffffffffffffffffffffffffffff166effffffffffffffffffffffffffffff1684611bf690919063ffffffff16565b611c14565b600160000160116101000a8154816effffffffffffffffffffffffffffff02191690836effffffffffffffffffffffffffffff1602179055506a353f43a026da2053240000606460166b033b2e3c9fd0803ce8000000028115156118d657fe5b04606460056b033b2e3c9fd0803ce8000000028115156118f257fe5b04606460176b033b2e3c9fd0803ce80000000281151561190e57fe5b04606460096b033b2e3c9fd0803ce80000000281151561192a57fe5b040101016b033b2e3c9fd0803ce80000000303600160000160119054906101000a90046effffffffffffffffffffffffffffff166effffffffffffffffffffffffffffff161115151561197c57600080fd5b600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663b5e73249848460016119c6610b8e565b6040518563ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001848152602001831515151581526020018263ffffffff1663ffffffff168152602001945050505050600060405180830381600087803b158015611a6957600080fd5b505af1158015611a7d573d6000803e3d6000fd5b505050508273ffffffffffffffffffffffffffffffffffffffff167f4d1636c3e75537f2cbca3bdf3cf2c7825eb501463bc634e6923119dee5d1cc43836000604051808381526020018281526020019250505060405180910390a2505050565b606460166b033b2e3c9fd0803ce800000002811515611af857fe5b04606460056b033b2e3c9fd0803ce800000002811515611b1457fe5b04606460176b033b2e3c9fd0803ce800000002811515611b3057fe5b04606460096b033b2e3c9fd0803ce800000002811515611b4c57fe5b0401010181565b60008060008373ffffffffffffffffffffffffffffffffffffffff161415611b7e5760009150611b89565b823b90506000811191505b50919050565b60008082840290506000841480611bb05750828482811515611bad57fe5b04145b1515611bb857fe5b8091505092915050565b6000828211151515611bd057fe5b818303905092915050565b6000808284811515611be957fe5b0490508091505092915050565b6000808284019050838110151515611c0a57fe5b8091505092915050565b600081826effffffffffffffffffffffffffffff16141515611c3257fe5b8190509190505600a165627a7a72305820506bfe61c8d6a70469fddddac3928edff623cced30f7854e0db3d83f79a030090029
\ No newline at end of file
+608060405234801561001057600080fd5b50336000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060018060000160006101000a81548161ffff021916908361ffff160217905550611c66806100806000396000f300608060405260043610610107576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806313af403514610111578063165a0e031461015457806318160ddd1461017f5780633197cbb6146101aa5780633ba0b9a9146101d557806348b15166146102005780634bb278f3146102375780635e84d7231461024e57806369d4f28e1461027957806378e97925146102a457806384386004146102cf578063873c56d7146102fa5780638da5cb5b14610325578063a6f2ae3a1461037c578063ab96dd1814610386578063c040e6b8146103b1578063c0c53b8b146103ea578063de009e7f1461046d578063ff91b949146104ba575b61010f6104e5565b005b34801561011d57600080fd5b50610152600480360381019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506109ca565b005b34801561016057600080fd5b50610169610a68565b6040518082815260200191505060405180910390f35b34801561018b57600080fd5b50610194610af9565b6040518082815260200191505060405180910390f35b3480156101b657600080fd5b506101bf610b09565b6040518082815260200191505060405180910390f35b3480156101e157600080fd5b506101ea610b11565b6040518082815260200191505060405180910390f35b34801561020c57600080fd5b50610215610b8e565b604051808263ffffffff1663ffffffff16815260200191505060405180910390f35b34801561024357600080fd5b5061024c610b96565b005b34801561025a57600080fd5b50610263610ec3565b6040518082815260200191505060405180910390f35b34801561028557600080fd5b5061028e610f47565b6040518082815260200191505060405180910390f35b3480156102b057600080fd5b506102b9610f80565b6040518082815260200191505060405180910390f35b3480156102db57600080fd5b506102e4610f88565b6040518082815260200191505060405180910390f35b34801561030657600080fd5b5061030f610fc1565b6040518082815260200191505060405180910390f35b34801561033157600080fd5b5061033a610fd0565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6103846104e5565b005b34801561039257600080fd5b5061039b610ff5565b6040518082815260200191505060405180910390f35b3480156103bd57600080fd5b506103c6610ffc565b604051808260068111156103d657fe5b60ff16815260200191505060405180910390f35b3480156103f657600080fd5b5061046b600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506111c4565b005b34801561047957600080fd5b506104b8600480360381019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035906020019092919050505061175c565b005b3480156104c657600080fd5b506104cf611add565b6040518082815260200191505060405180910390f35b60008060008060006104f633611b53565b15151561050257600080fd5b662386f26fc10000341015151561051857600080fd5b610520610b11565b945060008511151561053157600080fd5b610708600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16637ba49b81336040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050602060405180830381600087803b1580156105f157600080fd5b505af1158015610605573d6000803e3d6000fd5b505050506040513d602081101561061b57600080fd5b810190808051906020019092919050505063ffffffff160161063b610b8e565b63ffffffff161015151561064e57600080fd5b6801a055690d9db800003411156106825761067b856801a055690d9db80000611b8f90919063ffffffff16565b9350610698565b6106958534611b8f90919063ffffffff16565b93505b6106e7600160000160029054906101000a90046effffffffffffffffffffffffffffff166effffffffffffffffffffffffffffff166a353f43a026da2053240000611bc290919063ffffffff16565b9250828411156106f5578293505b6107088585611bdb90919063ffffffff16565b9150600084111561095d57600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663b5e732493386600161075d610b8e565b6040518563ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001848152602001831515151581526020018263ffffffff1663ffffffff168152602001945050505050600060405180830381600087803b15801561080057600080fd5b505af1158015610814573d6000803e3d6000fd5b50505050600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc839081150290604051600060405180830381858888f19350505050158015610880573d6000803e3d6000fd5b506108cd6108c8600160000160029054906101000a90046effffffffffffffffffffffffffffff166effffffffffffffffffffffffffffff1686611bf690919063ffffffff16565b611c14565b600160000160026101000a8154816effffffffffffffffffffffffffffff02191690836effffffffffffffffffffffffffffff1602179055503373ffffffffffffffffffffffffffffffffffffffff167f4d1636c3e75537f2cbca3bdf3cf2c7825eb501463bc634e6923119dee5d1cc438584604051808381526020018281526020019250505060405180910390a25b6109708234611bc290919063ffffffff16565b905060008111156109c3573373ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f193505050501580156109c1573d6000803e3d6000fd5b505b5050505050565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141515610a2557600080fd5b806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b6a353f43a026da2053240000606460166b033b2e3c9fd0803ce800000002811515610a8f57fe5b04606460056b033b2e3c9fd0803ce800000002811515610aab57fe5b04606460176b033b2e3c9fd0803ce800000002811515610ac757fe5b04606460096b033b2e3c9fd0803ce800000002811515610ae357fe5b040101016b033b2e3c9fd0803ce8000000030381565b6b033b2e3c9fd0803ce800000081565b636c01173081565b600060036006811115610b2057fe5b610b28610ffc565b6006811115610b3357fe5b1415610b56576064600f610dac02811515610b4a57fe5b04610dac019050610b8b565b60046006811115610b6357fe5b610b6b610ffc565b6006811115610b7657fe5b1415610b8657610dac9050610b8b565b600090505b90565b600042905090565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141515610bf357600080fd5b60056006811115610c0057fe5b610c08610ffc565b6006811115610c1357fe5b141515610c1f57600080fd5b610d26600160000160119054906101000a90046effffffffffffffffffffffffffffff166effffffffffffffffffffffffffffff16610d18600160000160029054906101000a90046effffffffffffffffffffffffffffff166effffffffffffffffffffffffffffff16606460166b033b2e3c9fd0803ce800000002811515610ca457fe5b04606460056b033b2e3c9fd0803ce800000002811515610cc057fe5b04606460176b033b2e3c9fd0803ce800000002811515610cdc57fe5b04606460096b033b2e3c9fd0803ce800000002811515610cf857fe5b040101016b033b2e3c9fd0803ce800000003611bc290919063ffffffff16565b611bc290919063ffffffff16565b90506000811115610ddb57600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663534eb1d4826040518263ffffffff167c010000000000000000000000000000000000000000000000000000000002815260040180828152602001915050600060405180830381600087803b158015610dc257600080fd5b505af1158015610dd6573d6000803e3d6000fd5b505050505b600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16633fb27b856040518163ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401600060405180830381600087803b158015610e6157600080fd5b505af1158015610e75573d6000803e3d6000fd5b505050506001600460156101000a81548160ff0219169083151502179055507f6c750432a9907ef296a47d6b38305b8ad777291aefc349e462a0a3285799425460405160405180910390a150565b606460166b033b2e3c9fd0803ce800000002811515610ede57fe5b04606460056b033b2e3c9fd0803ce800000002811515610efa57fe5b04606460176b033b2e3c9fd0803ce800000002811515610f1657fe5b04606460096b033b2e3c9fd0803ce800000002811515610f3257fe5b040101016b033b2e3c9fd0803ce80000000381565b6000600160000160029054906101000a90046effffffffffffffffffffffffffffff166effffffffffffffffffffffffffffff16905090565b635996d6c081565b6000600160000160119054906101000a90046effffffffffffffffffffffffffffff166effffffffffffffffffffffffffffff16905090565b6a353f43a026da205324000081565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6203f48081565b6000600460159054906101000a900460ff161561101c57600690506111c1565b600460149054906101000a900460ff16151561103b57600190506111c1565b635996d6c0611048610b8e565b63ffffffff16101561105d57600290506111c1565b606460166b033b2e3c9fd0803ce80000000281151561107857fe5b04606460056b033b2e3c9fd0803ce80000000281151561109457fe5b04606460176b033b2e3c9fd0803ce8000000028115156110b057fe5b04606460096b033b2e3c9fd0803ce8000000028115156110cc57fe5b040101016b033b2e3c9fd0803ce800000003611153600160000160119054906101000a90046effffffffffffffffffffffffffffff166effffffffffffffffffffffffffffff16600160000160029054906101000a90046effffffffffffffffffffffffffffff166effffffffffffffffffffffffffffff16611bf690919063ffffffff16565b10151561116357600590506111c1565b636c011730611170610b8e565b63ffffffff1610156111bc576111966203f480635996d6c0611bf690919063ffffffff16565b61119e610b8e565b63ffffffff1610156111b357600390506111c1565b600490506111c1565b600590505b90565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614151561121f57600080fd5b6001600681111561122c57fe5b611234610ffc565b600681111561123f57fe5b14151561124b57600080fd5b3073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16638da5cb5b6040518163ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401602060405180830381600087803b1580156112c657600080fd5b505af11580156112da573d6000803e3d6000fd5b505050506040513d60208110156112f057600080fd5b810190808051906020019092919050505073ffffffffffffffffffffffffffffffffffffffff1614151561132357600080fd5b60008273ffffffffffffffffffffffffffffffffffffffff161415151561134957600080fd5b60008173ffffffffffffffffffffffffffffffffffffffff161415151561136f57600080fd5b82600260006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555081600360006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555080600460006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663b5e73249600460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff166114dc606460166b033b2e3c9fd0803ce8000000028115156114b157fe5b04606460056b033b2e3c9fd0803ce8000000028115156114cd57fe5b04611bf690919063ffffffff16565b60006114e6610b8e565b6040518563ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001848152602001831515151581526020018263ffffffff1663ffffffff168152602001945050505050600060405180830381600087803b15801561158957600080fd5b505af115801561159d573d6000803e3d6000fd5b50505050600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663b5e73249600460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1661164b606460176b033b2e3c9fd0803ce80000000281151561162057fe5b04606460096b033b2e3c9fd0803ce80000000281151561163c57fe5b04611bf690919063ffffffff16565b6001611655610b8e565b6040518563ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001848152602001831515151581526020018263ffffffff1663ffffffff168152602001945050505050600060405180830381600087803b1580156116f857600080fd5b505af115801561170c573d6000803e3d6000fd5b505050506001600460146101000a81548160ff0219169083151502179055507f1b0e25e2531ab5dbde6724b973ffb1819ece38c4a44247d242e5079db9ce461160405160405180910390a1505050565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161415156117b957600080fd5b6117c1610ffc565b9050600360068111156117d057fe5b8160068111156117dc57fe5b14806117fe5750600460068111156117f057fe5b8160068111156117fc57fe5b145b8061181f57506005600681111561181157fe5b81600681111561181d57fe5b145b151561182a57600080fd5b611876611871600160000160119054906101000a90046effffffffffffffffffffffffffffff166effffffffffffffffffffffffffffff1684611bf690919063ffffffff16565b611c14565b600160000160116101000a8154816effffffffffffffffffffffffffffff02191690836effffffffffffffffffffffffffffff1602179055506a353f43a026da2053240000606460166b033b2e3c9fd0803ce8000000028115156118d657fe5b04606460056b033b2e3c9fd0803ce8000000028115156118f257fe5b04606460176b033b2e3c9fd0803ce80000000281151561190e57fe5b04606460096b033b2e3c9fd0803ce80000000281151561192a57fe5b040101016b033b2e3c9fd0803ce80000000303600160000160119054906101000a90046effffffffffffffffffffffffffffff166effffffffffffffffffffffffffffff161115151561197c57600080fd5b600260009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663b5e73249848460016119c6610b8e565b6040518563ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001848152602001831515151581526020018263ffffffff1663ffffffff168152602001945050505050600060405180830381600087803b158015611a6957600080fd5b505af1158015611a7d573d6000803e3d6000fd5b505050508273ffffffffffffffffffffffffffffffffffffffff167f4d1636c3e75537f2cbca3bdf3cf2c7825eb501463bc634e6923119dee5d1cc43836000604051808381526020018281526020019250505060405180910390a2505050565b606460166b033b2e3c9fd0803ce800000002811515611af857fe5b04606460056b033b2e3c9fd0803ce800000002811515611b1457fe5b04606460176b033b2e3c9fd0803ce800000002811515611b3057fe5b04606460096b033b2e3c9fd0803ce800000002811515611b4c57fe5b0401010181565b60008060008373ffffffffffffffffffffffffffffffffffffffff161415611b7e5760009150611b89565b823b90506000811191505b50919050565b60008082840290506000841480611bb05750828482811515611bad57fe5b04145b1515611bb857fe5b8091505092915050565b6000828211151515611bd057fe5b818303905092915050565b6000808284811515611be957fe5b0490508091505092915050565b6000808284019050838110151515611c0a57fe5b8091505092915050565b600081826effffffffffffffffffffffffffffff16141515611c3257fe5b8190509190505600a165627a7a723058207ff151982c527ec14ce88e9241d33f9b671a9c1ecaa16178d690ceef9c98d9b00029
\ No newline at end of file
diff --git a/processor/vm/runtime/contract/crypto/crypto.sol b/processor/vm/runtime/contract/crypto/crypto.sol
new file mode 100644
index 00000000..63528950
--- /dev/null
+++ b/processor/vm/runtime/contract/crypto/crypto.sol
@@ -0,0 +1,22 @@
+pragma solidity ^0.4.11;
+
+contract testencrypt {
+    
+   function myencode() external returns (uint256 len){     
+      bytes memory mycode = "Hello, world.";
+      bytes memory pubkey = "047db227d7094ce215c3a0f57e1bcc732551fe351f94249471934567e0f5dc1bf795962b8cccb87a2eb56b29fbe37d614e2f4c3c45b789ae4f1f51f4cb21972ffd";
+      bytes memory aa = new bytes(10);
+      len = cryptocalc( mycode,pubkey,aa,0);
+      return len;
+    }
+
+   function mydecode() external returns (uint256 len){   
+      bytes memory mycode = "Hello, world.";  
+      bytes memory prikey = "289c2857d4598e37fb9647507e47a309d6133539bf21a8b9cb6df88fd5232032";
+      bytes memory aa = new bytes(10);
+      len = cryptocalc( mycode,prikey,aa,1);
+      return len;
+    }
+    
+    
+}
diff --git a/processor/vm/runtime/contract/crypto/testcrypto.abi b/processor/vm/runtime/contract/crypto/testcrypto.abi
new file mode 100644
index 00000000..bc5f2c7b
--- /dev/null
+++ b/processor/vm/runtime/contract/crypto/testcrypto.abi
@@ -0,0 +1 @@
+[{"constant":false,"inputs":[],"name":"mydecode","outputs":[{"name":"ret","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"myencode","outputs":[{"name":"ret","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"}]
\ No newline at end of file
diff --git a/processor/vm/runtime/contract/crypto/testcrypto.bin b/processor/vm/runtime/contract/crypto/testcrypto.bin
new file mode 100644
index 00000000..ae8f946a
--- /dev/null
+++ b/processor/vm/runtime/contract/crypto/testcrypto.bin
@@ -0,0 +1 @@
+60806040526040805190810160405280600d81526020017f48656c6c6f2c20776f726c642e000000000000000000000000000000000000008152506000908051906020019061004f929190610105565b5060c0604051908101604052806082815260200161049b608291396001908051906020019061007f929190610105565b50606060405190810160405280604081526020017f323839633238353764343539386533376662393634373530376534376133303981526020017f6436313333353339626632316138623963623664663838666435323332303332815250600290805190602001906100f2929190610105565b503480156100ff57600080fd5b506101aa565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061014657805160ff1916838001178555610174565b82800160010185558215610174579182015b82811115610173578251825591602001919060010190610158565b5b5090506101819190610185565b5090565b6101a791905b808211156101a357600081600090555060010161018b565b5090565b90565b6102e2806101b96000396000f30060806040526004361061004c576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806342d6c33514610051578063f1db5416146100e1575b600080fd5b34801561005d57600080fd5b50610066610171565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156100a657808201518184015260208101905061008b565b50505050905090810190601f1680156100d35780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b3480156100ed57600080fd5b506100f6610176565b6040518080602001828103825283818151815260200191508051906020019080838360005b8381101561013657808201518184015260208101905061011b565b50505050905090810190601f1680156101635780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b606090565b606060008054600181600116156101000203166002900480601f01602080910402602001604051908101604052809291908181526020018280546001816001161561010002031660029004801561020e5780601f106101e35761010080835404028352916020019161020e565b820191906000526020600020905b8154815290600101906020018083116101f157829003601f168201915b505050505060018054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156102a95780601f1061027e576101008083540402835291602001916102a9565b820191906000526020600020905b81548152906001019060200180831161028c57829003601f168201915b50505050506000cb9050905600a165627a7a72305820b5e62e768b7e9dc1578783fa08247b0fa4949b31d4da49ae2c14576b8f94e979002930343764623232376437303934636532313563336130663537653162636337333235353166653335316639343234393437313933343536376530663564633162663739353936326238636363623837613265623536623239666265333764363134653266346333633435623738396165346631663531663463623231393732666664
\ No newline at end of file
diff --git a/processor/vm/runtime/run_test.go b/processor/vm/runtime/run_test.go
new file mode 100644
index 00000000..c1a28d4f
--- /dev/null
+++ b/processor/vm/runtime/run_test.go
@@ -0,0 +1,115 @@
+// Copyright 2018 The Fractal Team Authors
+// This file is part of the fractal project.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+package runtime
+
+import (
+	"fmt"
+	"math/big"
+	"testing"
+
+	"github.com/fractalplatform/fractal/accountmanager"
+	"github.com/fractalplatform/fractal/common"
+	"github.com/fractalplatform/fractal/state"
+	"github.com/fractalplatform/fractal/types"
+	mdb "github.com/fractalplatform/fractal/utils/fdb/memdb"
+)
+
+//TestRunCode run runtime code directly
+func TestRunCode(t *testing.T) {
+	fmt.Println("in TestRunCode ...")
+	state, _ := state.New(common.Hash{}, state.NewDatabase(mdb.NewMemDatabase()))
+	account, _ := accountmanager.NewAccountManager(state)
+	fmt.Println("in TestRunCode2 ...")
+	//sender
+	senderName := common.Name("jacobwolf")
+	senderPubkey := common.HexToPubKey("12345")
+	//
+	receiverName := common.Name("denverfolk")
+	receiverPubkey := common.HexToPubKey("12345")
+	//
+	toName := common.Name("fractal.account")
+
+	fmt.Println("in TestRunCode3 ...")
+	if err := account.CreateAccount(senderName, "", 0, 0, senderPubkey); err != nil {
+		fmt.Println("create sender account error\n", err)
+		return
+	}
+
+	if err := account.CreateAccount(receiverName, "", 0, 0, receiverPubkey); err != nil {
+		fmt.Println("create receiver account error\n", err)
+		return
+	}
+
+	action := issueAssetAction(senderName, toName)
+	if _, err := account.Process(&types.AccountManagerContext{Action: action, Number: 0}); err != nil {
+		fmt.Println("issue asset error\n", err)
+		return
+	}
+
+	runtimeConfig := Config{
+		Origin:      senderName,
+		FromPubkey:  senderPubkey,
+		State:       state,
+		Account:     account,
+		AssetID:     1,
+		GasLimit:    10000000000,
+		GasPrice:    big.NewInt(0),
+		Value:       big.NewInt(0),
+		BlockNumber: new(big.Int).SetUint64(0),
+	}
+
+	var code = common.Hex2Bytes("60806040526004361061004c576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806342d6c33514610051578063f1db54161461007c575b600080fd5b34801561005d57600080fd5b506100666100a7565b6040518082815260200191505060405180910390f35b34801561008857600080fd5b506100916100b2565b6040518082815260200191505060405180910390f35b60006001cb80905090565b600060608060606040805190810160405280600d81526020017f48656c6c6f2c20776f726c642e00000000000000000000000000000000000000815250925060c06040519081016040528060828152602001610177608291399150600a6040519080825280601f01601f1916602001820160405280156101415781602001602082028038833980820191505090505b5090508280519060200183805190602001848051906020016000cc80601f01601f191660405101604052935083935050505090560030343764623232376437303934636532313563336130663537653162636337333235353166653335316639343234393437313933343536376530663564633162663739353936326238636363623837613265623536623239666265333764363134653266346333633435623738396165346631663531663463623231393732666664a165627a7a7230582058439b3945a21edad9fde8f2430422ca01d9a2c5092de618efa65db15f44d60e0029")
+	// myBinfile := "./contract/Ven/VEN.bin"
+	myAbifile := "./contract/crypto/testcrypto.abi"
+
+	// myContractName := common.Name("mycontract")
+
+	// err = createContract(myAbifile, myBinfile, venContractName, runtimeConfig)
+	// if err != nil {
+	// 	fmt.Println("create venContractAddress error")
+	// 	return
+	// }
+
+	receiverAcct, err := account.GetAccountByName(receiverName)
+	if err != nil {
+		fmt.Println("GetAccountByName receiverAcct error")
+		return
+	}
+
+	if receiverAcct != nil {
+		receiverAcct.SetCode(code)
+		account.SetAccount(receiverAcct)
+	}
+
+	myInput, err := input(myAbifile, "mydecode")
+	//myInput, err := input(myAbifile, "myencode")
+	if err != nil {
+		fmt.Println("initialize myInput error ", err)
+		return
+	}
+
+	action = types.NewAction(types.Transfer, runtimeConfig.Origin, receiverName, 0, runtimeConfig.AssetID, runtimeConfig.GasLimit, runtimeConfig.Value, myInput)
+
+	ret, _, err := Call(action, &runtimeConfig)
+	if err != nil {
+		fmt.Println("call error ", err)
+		return
+	}
+
+	fmt.Println("ret =", ret)
+	//go test -v -test.run TestRunCode
+}
diff --git a/processor/vm/runtime/runtime.go b/processor/vm/runtime/runtime.go
index 19e35608..18c871a9 100644
--- a/processor/vm/runtime/runtime.go
+++ b/processor/vm/runtime/runtime.go
@@ -55,10 +55,7 @@ type Config struct {
 // sets defaults on the config
 func setDefaults(cfg *Config) {
 	if cfg.ChainConfig == nil {
-		cfg.ChainConfig = &params.ChainConfig{
-			ContractChargeRatio: 80,
-			AssetChargeRatio:    80,
-		}
+		cfg.ChainConfig = params.DefaultChainconfig
 		//cfg.ChainConfig = &params.ChainConfig{
 		//	ChainID:        big.NewInt(1),
 		//	HomesteadBlock: new(big.Int),
@@ -102,10 +99,12 @@ func NewEnv(cfg *Config) *vm.EVM {
 	context := vm.Context{
 		//CanTransfer: vm.CanTransfer,
 		//Transfer:    vm.Transfer,
-		GetHash:     func(uint64) common.Hash { return common.Hash{} },
+		GetHash: func(uint64) common.Hash { return common.Hash{} },
+		GetDelegatedByTime: func(string, uint64, *state.StateDB) (*big.Int, *big.Int, uint64, error) {
+			return big.NewInt(0), big.NewInt(0), 0, nil
+		},
 		Origin:      cfg.Origin,
 		From:        cfg.Origin,
-		FromPubkey:  cfg.FromPubkey,
 		Coinbase:    cfg.Coinbase,
 		BlockNumber: cfg.BlockNumber,
 		Time:        cfg.Time,
diff --git a/processor/vm/runtime/runtime_test.go b/processor/vm/runtime/runtime_test.go
index c8027a12..b7882050 100644
--- a/processor/vm/runtime/runtime_test.go
+++ b/processor/vm/runtime/runtime_test.go
@@ -208,18 +208,18 @@ func TestAsset(t *testing.T) {
 	receiverName := common.Name("denverfolk")
 	receiverPubkey := common.HexToPubKey("12345")
 
-	if err := account.CreateAccount(senderName, "", 0, senderPubkey); err != nil {
+	if err := account.CreateAccount(senderName, "", 0, 0, senderPubkey); err != nil {
 		fmt.Println("create sender account error", err)
 		return
 	}
 
-	if err := account.CreateAccount(receiverName, "", 0, receiverPubkey); err != nil {
+	if err := account.CreateAccount(receiverName, "", 0, 0, receiverPubkey); err != nil {
 		fmt.Println("create receiver account error", err)
 		return
 	}
 
 	action := issueAssetAction(senderName, receiverName)
-	if err := account.Process(action); err != nil {
+	if _, err := account.Process(&types.AccountManagerContext{Action: action, Number: 0}); err != nil {
 		fmt.Println("issue asset error", err)
 		return
 	}
@@ -239,7 +239,7 @@ func TestAsset(t *testing.T) {
 	binfile := "./contract/Asset/Asset.bin"
 	abifile := "./contract/Asset/Asset.abi"
 	contractName := common.Name("assetcontract")
-	if err := account.CreateAccount(contractName, "", 0, receiverPubkey); err != nil {
+	if err := account.CreateAccount(contractName, "", 0, 0, receiverPubkey); err != nil {
 		fmt.Println("create contract account error", err)
 		return
 	}
@@ -257,11 +257,15 @@ func TestAsset(t *testing.T) {
 	}
 	action = types.NewAction(types.Transfer, runtimeConfig.Origin, contractName, 0, 1, runtimeConfig.GasLimit, runtimeConfig.Value, issuseAssetInput)
 
-	_, _, err = Call(action, &runtimeConfig)
+	ret, _, err := Call(action, &runtimeConfig)
 	if err != nil {
 		fmt.Println("call error ", err)
 		return
 	}
+	num := new(big.Int).SetBytes(ret)
+	if num.Cmp(big.NewInt(2)) != 0 {
+		t.Error("getBalance fail, want 2, get ", num)
+	}
 
 	senderAcc, err := account.GetAccountByName(senderName)
 	if err != nil {
@@ -278,7 +282,7 @@ func TestAsset(t *testing.T) {
 		fmt.Println("asset result ", b)
 	}
 
-	addAssetInput, err := input(abifile, "add", common.BigToAddress(big.NewInt(2)), big.NewInt(210000))
+	addAssetInput, err := input(abifile, "add", big.NewInt(2), common.BytesToAddress([]byte(senderName.String())), big.NewInt(210000))
 	if err != nil {
 		fmt.Println("addAssetInput error ", err)
 		return
@@ -302,7 +306,7 @@ func TestAsset(t *testing.T) {
 		fmt.Println("asset result ", b)
 	}
 
-	transferExAssetInput, err := input(abifile, "transAsset", common.BytesToAddress([]byte(receiverName.String())), common.BigToAddress(big.NewInt(2)), big.NewInt(10000))
+	transferExAssetInput, err := input(abifile, "transAsset", common.BytesToAddress([]byte(receiverName.String())), big.NewInt(2), big.NewInt(10000))
 	if err != nil {
 		fmt.Println("transferExAssetInput error ", err)
 		return
@@ -339,7 +343,7 @@ func TestAsset(t *testing.T) {
 		fmt.Println("asset receiver result ", b)
 	}
 
-	setOwnerInput, err := input(abifile, "setname", common.BytesToAddress([]byte(receiverName.String())), common.BigToAddress(big.NewInt(2)))
+	setOwnerInput, err := input(abifile, "setname", common.BytesToAddress([]byte(receiverName.String())), big.NewInt(2))
 	if err != nil {
 		fmt.Println("setOwnerInput error ", err)
 		return
@@ -353,22 +357,39 @@ func TestAsset(t *testing.T) {
 		return
 	}
 
-	getBalanceInput, err := input(abifile, "getbalance", common.BytesToAddress([]byte(receiverName.String())), common.BigToAddress(big.NewInt(2)))
+	getBalanceInput, err := input(abifile, "getbalance", common.BytesToAddress([]byte(receiverName.String())), big.NewInt(2))
 	if err != nil {
 		fmt.Println("getBalanceInput error ", err)
 		return
 	}
 	action = types.NewAction(types.Transfer, runtimeConfig.Origin, contractName, 0, runtimeConfig.AssetID, runtimeConfig.GasLimit, runtimeConfig.Value, getBalanceInput)
 
-	ret, _, err := Call(action, &runtimeConfig)
+	ret, _, err = Call(action, &runtimeConfig)
 	if err != nil {
 		fmt.Println("call error ", err)
 		return
 	}
-	num := new(big.Int).SetBytes(ret)
+	num = new(big.Int).SetBytes(ret)
 	if num.Cmp(big.NewInt(10000)) != 0 {
 		t.Error("getBalance fail, want 10000, get ", num)
 	}
+
+	getAssetIDInput, err := input(abifile, "getAssetId")
+	if err != nil {
+		fmt.Println("getBalanceInput error ", err)
+		return
+	}
+	action = types.NewAction(types.Transfer, runtimeConfig.Origin, contractName, 0, runtimeConfig.AssetID, runtimeConfig.GasLimit, runtimeConfig.Value, getAssetIDInput)
+
+	ret, _, err = Call(action, &runtimeConfig)
+	if err != nil {
+		fmt.Println("call error ", err)
+		return
+	}
+	num = new(big.Int).SetBytes(ret)
+	if num.Cmp(big.NewInt(2)) != 0 {
+		t.Error("getBalance fail, want 10000, get ", num)
+	}
 }
 func TestBNB(t *testing.T) {
 	state, _ := state.New(common.Hash{}, state.NewDatabase(mdb.NewMemDatabase()))
@@ -380,18 +401,18 @@ func TestBNB(t *testing.T) {
 	receiverName := common.Name("denverfolk")
 	receiverPubkey := common.HexToPubKey("12345")
 
-	if err := account.CreateAccount(senderName, common.Name(""), 0, senderPubkey); err != nil {
+	if err := account.CreateAccount(senderName, common.Name(""), 0, 0, senderPubkey); err != nil {
 		fmt.Println("create sender account error", err)
 		return
 	}
 
-	if err := account.CreateAccount(receiverName, common.Name(""), 0, receiverPubkey); err != nil {
+	if err := account.CreateAccount(receiverName, common.Name(""), 0, 0, receiverPubkey); err != nil {
 		fmt.Println("create receiver account error", err)
 		return
 	}
 
 	action := issueAssetAction(senderName, receiverName)
-	if err := account.Process(action); err != nil {
+	if _, err := account.Process(&types.AccountManagerContext{Action: action, Number: 0}); err != nil {
 		fmt.Println("issue asset error", err)
 		return
 	}
@@ -417,16 +438,16 @@ func TestBNB(t *testing.T) {
 	ethvaultName := common.Name("ethvault")
 	venvaultName := common.Name("venvault")
 
-	if err := account.CreateAccount(venContractName, common.Name(""), 0, receiverPubkey); err != nil {
+	if err := account.CreateAccount(venContractName, common.Name(""), 0, 0, receiverPubkey); err != nil {
 		fmt.Println("create venContractName account error", err)
 		return
 	}
-	if err := account.CreateAccount(venSaleContractName, common.Name(""), 0, receiverPubkey); err != nil {
+	if err := account.CreateAccount(venSaleContractName, common.Name(""), 0, 0, receiverPubkey); err != nil {
 		fmt.Println("create venSaleContractName account error", err)
 		return
 	}
-	account.CreateAccount(ethvaultName, common.Name(""), 0, senderPubkey)
-	account.CreateAccount(venvaultName, common.Name(""), 0, senderPubkey)
+	account.CreateAccount(ethvaultName, common.Name(""), 0, 0, senderPubkey)
+	account.CreateAccount(venvaultName, common.Name(""), 0, 0, senderPubkey)
 
 	err := createContract(VenSaleAbifile, VenSaleBinfile, venSaleContractName, runtimeConfig)
 	if err != nil {
diff --git a/processor/vm/stack.go b/processor/vm/stack.go
index 5a72e3cc..d33705bf 100644
--- a/processor/vm/stack.go
+++ b/processor/vm/stack.go
@@ -90,3 +90,15 @@ func (st *Stack) Print() {
 	}
 	fmt.Println("#############")
 }
+
+func (st *Stack) DebugPrint() {
+	fmt.Println("### stack ###")
+	if len(st.data) > 0 {
+		for i, val := range st.data {
+			fmt.Printf("%-3d  %x\n", i, val)
+		}
+	} else {
+		fmt.Println("-- empty --")
+	}
+	fmt.Println("#############")
+}
diff --git a/processor/vm/vm.go b/processor/vm/vm.go
index 5b0ffdba..f3449600 100644
--- a/processor/vm/vm.go
+++ b/processor/vm/vm.go
@@ -33,6 +33,10 @@ import (
 type (
 	// GetHashFunc returns the nth block hash in the blockchain and is used by the BLOCKHASH EVM op code.
 	GetHashFunc func(uint64) common.Hash
+	// GetDelegatedByTimeFunc returns the delegated balance
+	GetDelegatedByTimeFunc func(string, uint64, *state.StateDB) (*big.Int, *big.Int, uint64, error)
+	// GetHeaderByNumberFunc
+	GetHeaderByNumberFunc func(number uint64) *types.Header
 )
 
 // Context provides the EVM with auxiliary information. Once provided
@@ -41,12 +45,17 @@ type Context struct {
 	// GetHash returns the hash corresponding to n
 	GetHash GetHashFunc
 
+	// GetDelegatedByTime returns the delegated balance
+	GetDelegatedByTime GetDelegatedByTimeFunc
+
+	//GetHeaderByNumber
+	GetHeaderByNumber GetHeaderByNumberFunc
+
 	// Message information
-	Origin     common.Name   // Provides information for ORIGIN
-	From       common.Name   // Provides information for ORIGIN
-	FromPubkey common.PubKey // provides from pubkey
-	AssetID    uint64        // provides assetId
-	GasPrice   *big.Int      // Provides information for GASPRICE
+	Origin   common.Name // Provides information for ORIGIN
+	From     common.Name // Provides information for ORIGIN
+	AssetID  uint64      // provides assetId
+	GasPrice *big.Int    // Provides information for GASPRICE
 
 	// Block information
 	Coinbase    common.Name // Provides information for COINBASE
@@ -89,9 +98,22 @@ type EVM struct {
 	// applied in opCall*.
 	callGasTemp uint64
 
-	FounderGasMap map[common.Name]int64
+	FounderGasMap map[common.Name]DistributeGas
+
+	InternalTxs []*types.InternalAction
+}
+
+type DistributeGas struct {
+	Value  int64
+	TypeID uint64
 }
 
+const (
+	AssetGas    = 0
+	ContractGas = 1
+	CoinbaseGas = 2
+)
+
 // NewEVM retutrns a new EVM . The returned EVM is not thread safe and should
 // only ever be used *once*.
 func NewEVM(ctx Context, accountdb *accountmanager.AccountManager, statedb *state.StateDB, chainCfg *params.ChainConfig, vmConfig Config) *EVM {
@@ -103,7 +125,7 @@ func NewEVM(ctx Context, accountdb *accountmanager.AccountManager, statedb *stat
 		vmConfig:    vmConfig,
 	}
 	evm.interpreter = NewInterpreter(evm, vmConfig)
-	evm.FounderGasMap = map[common.Name]int64{}
+	evm.FounderGasMap = map[common.Name]DistributeGas{}
 	return evm
 }
 
@@ -167,17 +189,23 @@ func (evm *EVM) Call(caller ContractRef, action *types.Action, gas uint64) (ret
 		return nil, gas, err
 	}
 
+	var assetName common.Name
 	assetFounder, _ := evm.AccountDB.GetAssetFounder(action.AssetID()) //get asset founder name
-	assetFounderRatio := evm.chainConfig.AssetChargeRatio              //get asset founder charge ratio
-	contractFounder, _ := evm.AccountDB.GetFounder(toName)
-	if len(contractFounder.String()) == 0 {
-		contractFounder = toName
-	}
-	contratFounderRatio := evm.chainConfig.ContractChargeRatio
-	callerFounder, _ := evm.AccountDB.GetFounder(caller.Name())
-	if len(callerFounder.String()) == 0 {
-		callerFounder = caller.Name()
+
+	if len(assetFounder.String()) > 0 {
+		assetInfo, _ := evm.AccountDB.GetAssetInfoByID(action.AssetID())
+		assetName = common.Name(assetInfo.GetAssetName())
 	}
+
+	assetFounderRatio := evm.chainConfig.ChargeCfg.AssetRatio //get asset founder charge ratio
+
+	//
+	contractName := toName
+
+	contratFounderRatio := evm.chainConfig.ChargeCfg.ContractRatio
+	//
+	callerName := caller.Name()
+
 	// Initialise a new contract and set the code that is to be used by the EVM.
 	// The contract is a scoped environment for this execution context only.
 
@@ -186,6 +214,9 @@ func (evm *EVM) Call(caller ContractRef, action *types.Action, gas uint64) (ret
 	if err != nil {
 		return nil, gas, err
 	}
+	if acct == nil {
+		return nil, gas, ErrAccountNotExist
+	}
 	codeHash, err := acct.GetCodeHash()
 	if err != nil {
 		return nil, gas, err
@@ -208,30 +239,41 @@ func (evm *EVM) Call(caller ContractRef, action *types.Action, gas uint64) (ret
 	ret, err = run(evm, contract, action.Data())
 	runGas := gas - contract.Gas
 
-	if runGas > 0 && len(contractFounder.String()) > 0 {
-		if _, ok := evm.FounderGasMap[contractFounder]; !ok {
-			evm.FounderGasMap[contractFounder] = int64(runGas * contratFounderRatio / 100)
+	if runGas > 0 && len(contractName.String()) > 0 {
+		if _, ok := evm.FounderGasMap[contractName]; !ok {
+			dGas := DistributeGas{int64(runGas * contratFounderRatio / 100), ContractGas}
+			evm.FounderGasMap[contractName] = dGas
 		} else {
-			evm.FounderGasMap[contractFounder] += int64(runGas * contratFounderRatio / 100)
+			dGas := DistributeGas{int64(runGas * contratFounderRatio / 100), ContractGas}
+			dGas.Value = evm.FounderGasMap[contractName].Value + dGas.Value
+			evm.FounderGasMap[contractName] = dGas
 		}
 	}
+
 	if action.Value().Sign() != 0 && evm.depth != 0 {
 		callValueGas := int64(params.CallValueTransferGas - contract.Gas)
 		if callValueGas < 0 {
 			callValueGas = 0
 		}
-		if len(assetFounder.String()) > 0 {
-			if _, ok := evm.FounderGasMap[assetFounder]; !ok {
-				evm.FounderGasMap[assetFounder] = int64(callValueGas * int64(assetFounderRatio) / 100)
+		if len(assetName.String()) > 0 {
+			if _, ok := evm.FounderGasMap[assetName]; !ok {
+				dGas := DistributeGas{int64(callValueGas * int64(assetFounderRatio) / 100), AssetGas}
+				evm.FounderGasMap[assetName] = dGas
 			} else {
-				evm.FounderGasMap[assetFounder] += int64(callValueGas * int64(assetFounderRatio) / 100)
+				dGas := DistributeGas{int64(callValueGas * int64(assetFounderRatio) / 100), AssetGas}
+				dGas.Value = evm.FounderGasMap[assetName].Value + dGas.Value
+				evm.FounderGasMap[assetName] = dGas
 			}
 		}
-		if len(callerFounder.String()) > 0 {
-			if _, ok := evm.FounderGasMap[callerFounder]; !ok {
-				evm.FounderGasMap[callerFounder] = -int64(callValueGas * int64(assetFounderRatio) / 100)
+		if len(callerName.String()) > 0 {
+			if _, ok := evm.FounderGasMap[callerName]; !ok {
+				dGas := DistributeGas{-int64(callValueGas * int64(assetFounderRatio) / 100), AssetGas}
+				dGas.Value = evm.FounderGasMap[callerName].Value - dGas.Value
+				evm.FounderGasMap[callerName] = dGas
 			} else {
-				evm.FounderGasMap[callerFounder] -= int64(callValueGas * int64(assetFounderRatio) / 100)
+				dGas := DistributeGas{int64(callValueGas * int64(assetFounderRatio) / 100), AssetGas}
+				dGas.Value = evm.FounderGasMap[callerName].Value - dGas.Value
+				evm.FounderGasMap[callerName] = dGas
 			}
 		}
 	}
@@ -248,8 +290,9 @@ func (evm *EVM) Call(caller ContractRef, action *types.Action, gas uint64) (ret
 
 	actualUsedGas := gas - contract.Gas
 	if evm.depth == 0 && actualUsedGas != runGas {
-		for _, gas := range evm.FounderGasMap {
-			gas = (gas / int64(runGas)) * int64(actualUsedGas)
+		for name, gas := range evm.FounderGasMap {
+			v := DistributeGas{(gas.Value / int64(runGas)) * int64(actualUsedGas), gas.TypeID}
+			evm.FounderGasMap[name] = v
 		}
 	}
 
@@ -303,18 +346,24 @@ func (evm *EVM) CallCode(caller ContractRef, action *types.Action, gas uint64) (
 	ret, err = run(evm, contract, action.Data())
 	runGas := gas - contract.Gas
 
+	var contractName common.Name
 	contractFounder, _ := evm.AccountDB.GetFounder(toName)
 	if len(contractFounder.String()) == 0 {
-		contractFounder = toName
+		contractName = toName
 	}
-	contratFounderRatio := evm.chainConfig.ContractChargeRatio
-	if runGas > 0 && len(contractFounder.String()) > 0 {
-		if _, ok := evm.FounderGasMap[contractFounder]; !ok {
-			evm.FounderGasMap[contractFounder] = int64(runGas * contratFounderRatio / 100)
+
+	contratFounderRatio := evm.chainConfig.ChargeCfg.ContractRatio
+	if runGas > 0 && len(contractName.String()) > 0 {
+		if _, ok := evm.FounderGasMap[contractName]; !ok {
+			dGas := DistributeGas{int64(runGas * contratFounderRatio / 100), ContractGas}
+			evm.FounderGasMap[contractName] = dGas
 		} else {
-			evm.FounderGasMap[contractFounder] += int64(runGas * contratFounderRatio / 100)
+			dGas := DistributeGas{int64(runGas * contratFounderRatio / 100), ContractGas}
+			dGas.Value = evm.FounderGasMap[contractName].Value + dGas.Value
+			evm.FounderGasMap[contractName] = dGas
 		}
 	}
+
 	if err != nil {
 		evm.StateDB.RevertToSnapshot(snapshot)
 		if err != errExecutionReverted {
@@ -361,16 +410,21 @@ func (evm *EVM) DelegateCall(caller ContractRef, name common.Name, input []byte,
 	ret, err = run(evm, contract, input)
 	runGas := gas - contract.Gas
 
+	var contractName common.Name
 	contractFounder, _ := evm.AccountDB.GetFounder(name)
 	if len(contractFounder.String()) == 0 {
-		contractFounder = name
+		contractName = name
 	}
-	contratFounderRatio := evm.chainConfig.ContractChargeRatio
-	if runGas > 0 && len(contractFounder.String()) > 0 {
-		if _, ok := evm.FounderGasMap[contractFounder]; !ok {
-			evm.FounderGasMap[contractFounder] = int64(runGas * contratFounderRatio / 100)
+
+	contratFounderRatio := evm.chainConfig.ChargeCfg.ContractRatio
+	if runGas > 0 && len(contractName.String()) > 0 {
+		if _, ok := evm.FounderGasMap[contractName]; !ok {
+			dGas := DistributeGas{int64(runGas * contratFounderRatio / 100), ContractGas}
+			evm.FounderGasMap[contractName] = dGas
 		} else {
-			evm.FounderGasMap[contractFounder] += int64(runGas * contratFounderRatio / 100)
+			dGas := DistributeGas{int64(runGas * contratFounderRatio / 100), ContractGas}
+			dGas.Value = evm.FounderGasMap[contractName].Value + dGas.Value
+			evm.FounderGasMap[contractName] = dGas
 		}
 	}
 
@@ -430,18 +484,24 @@ func (evm *EVM) StaticCall(caller ContractRef, name common.Name, input []byte, g
 	ret, err = run(evm, contract, input)
 	runGas := gas - contract.Gas
 
+	var contractName common.Name
 	contractFounder, _ := evm.AccountDB.GetFounder(to.Name())
 	if len(contractFounder.String()) == 0 {
-		contractFounder = to.Name()
+		contractName = to.Name()
 	}
-	contratFounderRatio := evm.chainConfig.ContractChargeRatio
-	if runGas > 0 && len(contractFounder.String()) > 0 {
-		if _, ok := evm.FounderGasMap[contractFounder]; !ok {
-			evm.FounderGasMap[contractFounder] = int64(runGas * contratFounderRatio / 100)
+
+	contratFounderRatio := evm.chainConfig.ChargeCfg.ContractRatio
+	if runGas > 0 && len(contractName.String()) > 0 {
+		if _, ok := evm.FounderGasMap[contractName]; !ok {
+			dGas := DistributeGas{int64(runGas * contratFounderRatio / 100), ContractGas}
+			evm.FounderGasMap[contractName] = dGas
 		} else {
-			evm.FounderGasMap[contractFounder] += int64(runGas * contratFounderRatio / 100)
+			dGas := DistributeGas{int64(runGas * contratFounderRatio / 100), ContractGas}
+			dGas.Value = evm.FounderGasMap[contractName].Value + dGas.Value
+			evm.FounderGasMap[contractName] = dGas
 		}
 	}
+
 	if err != nil {
 		evm.StateDB.RevertToSnapshot(snapshot)
 		if err != errExecutionReverted {
@@ -466,9 +526,11 @@ func (evm *EVM) Create(caller ContractRef, action *types.Action, gas uint64) (re
 	contractName := action.Recipient()
 	snapshot := evm.StateDB.Snapshot()
 
-	// if err := evm.AccountDB.CreateAccount(contractName, evm.FromPubkey); err != nil {
-	// 	return nil, 0, err
-	// }
+	if b, err := evm.AccountDB.AccountHaveCode(contractName); err != nil {
+		return nil, 0, err
+	} else if b == true {
+		return nil, 0, ErrContractCodeCollision
+	}
 
 	if err := evm.AccountDB.TransferAsset(action.Sender(), action.Recipient(), evm.AssetID, action.Value()); err != nil {
 		evm.StateDB.RevertToSnapshot(snapshot)
@@ -491,6 +553,19 @@ func (evm *EVM) Create(caller ContractRef, action *types.Action, gas uint64) (re
 	start := time.Now()
 
 	ret, err = run(evm, contract, nil)
+	runGas := gas - contract.Gas
+
+	contratFounderRatio := evm.chainConfig.ChargeCfg.ContractRatio
+	if runGas > 0 && len(contractName.String()) > 0 {
+		if _, ok := evm.FounderGasMap[contractName]; !ok {
+			dGas := DistributeGas{int64(runGas * contratFounderRatio / 100), ContractGas}
+			evm.FounderGasMap[contractName] = dGas
+		} else {
+			dGas := DistributeGas{int64(runGas * contratFounderRatio / 100), ContractGas}
+			dGas.Value = evm.FounderGasMap[contractName].Value + dGas.Value
+			evm.FounderGasMap[contractName] = dGas
+		}
+	}
 
 	// check whether the max code size has been exceeded
 	//maxCodeSizeExceeded := evm.ChainConfig().IsEIP158(evm.BlockNumber) && len(ret) > params.MaxCodeSize
diff --git a/rawdb/accessors_chain.go b/rawdb/accessors_chain.go
index 2718b4a3..d8e61a66 100644
--- a/rawdb/accessors_chain.go
+++ b/rawdb/accessors_chain.go
@@ -77,35 +77,38 @@ func WriteHeadHeaderHash(db DatabaseWriter, hash common.Hash) {
 	}
 }
 
-// ReadHeadBlockHash retrieves the hash of the current canonical head block.
-func ReadHeadBlockHash(db DatabaseReader) common.Hash {
-	data, _ := db.Get(headBlockKey)
+// ReadIrreversibleNumber retrieves the irreversible number of chain.
+func ReadIrreversibleNumber(db DatabaseReader) uint64 {
+	data, err := db.Get(irreversibleNumberKey)
+	if err != nil {
+		log.Crit("Failed to get irreversible number ", "err", err)
+	}
 	if len(data) == 0 {
-		return common.Hash{}
+		return 0
 	}
-	return common.BytesToHash(data)
+	return decodeBlockNumber(data)
 }
 
-// WriteHeadBlockHash stores the head block's hash.
-func WriteHeadBlockHash(db DatabaseWriter, hash common.Hash) {
-	if err := db.Put(headBlockKey, hash.Bytes()); err != nil {
-		log.Crit("Failed to store last block's hash", "err", err)
+// WriteIrreversibleNumber stores the irreversible number of chain.
+func WriteIrreversibleNumber(db DatabaseWriter, number uint64) {
+	if err := db.Put(irreversibleNumberKey, encodeBlockNumber(number)); err != nil {
+		log.Crit("Failed to store irreversible number ", "err", err)
 	}
 }
 
-// ReadHeadFastBlockHash retrieves the hash of the current fast-sync head block.
-func ReadHeadFastBlockHash(db DatabaseReader) common.Hash {
-	data, _ := db.Get(headFastBlockKey)
+// ReadHeadBlockHash retrieves the hash of the current canonical head block.
+func ReadHeadBlockHash(db DatabaseReader) common.Hash {
+	data, _ := db.Get(headBlockKey)
 	if len(data) == 0 {
 		return common.Hash{}
 	}
 	return common.BytesToHash(data)
 }
 
-// WriteHeadFastBlockHash stores the hash of the current fast-sync head block.
-func WriteHeadFastBlockHash(db DatabaseWriter, hash common.Hash) {
-	if err := db.Put(headFastBlockKey, hash.Bytes()); err != nil {
-		log.Crit("Failed to store last fast block's hash", "err", err)
+// WriteHeadBlockHash stores the head block's hash.
+func WriteHeadBlockHash(db DatabaseWriter, hash common.Hash) {
+	if err := db.Put(headBlockKey, hash.Bytes()); err != nil {
+		log.Crit("Failed to store last block's hash", "err", err)
 	}
 }
 
@@ -249,6 +252,7 @@ func WriteBlock(db DatabaseWriter, block *types.Block) {
 // DeleteBlock removes all block data associated with a hash.
 func DeleteBlock(db DatabaseDeleter, hash common.Hash, number uint64) {
 	DeleteReceipts(db, hash, number)
+	DeleteDetailTxs(db, hash, number)
 	DeleteHeader(db, hash, number)
 	DeleteBody(db, hash, number)
 	DeleteTd(db, hash, number)
@@ -330,6 +334,50 @@ func DeleteReceipts(db DatabaseDeleter, hash common.Hash, number uint64) {
 	}
 }
 
+// ReadDetailTxs retrieves all the contract log belonging to a block.
+func ReadDetailTxs(db DatabaseReader, hash common.Hash, number uint64) []*types.DetailTx {
+	// Retrieve the flattened receipt slice
+	data, _ := db.Get(blockDetailTxsKey(number, hash))
+	if len(data) == 0 {
+		return nil
+	}
+	// Convert the revceipts from their storage form to their internal representation
+	storageDetailTxs := []*types.DetailTx{}
+	if err := rlp.DecodeBytes(data, &storageDetailTxs); err != nil {
+		fmt.Println("Invalid detailtxs array RLP", "hash", hash.String(), "err", err)
+		return nil
+	}
+	detailtxs := make([]*types.DetailTx, len(storageDetailTxs))
+	for i, detailtx := range storageDetailTxs {
+		detailtxs[i] = (*types.DetailTx)(detailtx)
+	}
+	return detailtxs
+}
+
+// WriteDetailTxs stores all the contract log belonging to a block.
+func WriteDetailTxs(db DatabaseWriter, hash common.Hash, number uint64, dtxs []*types.DetailTx) {
+	// Convert the receipts into their storage form and serialize them
+	storageDetailTxs := make([]*types.DetailTx, len(dtxs))
+	for i, dtx := range dtxs {
+		storageDetailTxs[i] = (*types.DetailTx)(dtx)
+	}
+	bytes, err := rlp.EncodeToBytes(storageDetailTxs)
+	if err != nil {
+		log.Crit("Failed to encode block detailtxs", "err", err)
+	}
+	// Store the flattened receipt slice
+	if err := db.Put(blockDetailTxsKey(number, hash), bytes); err != nil {
+		log.Crit("Failed to store block detailtxs", "err", err)
+	}
+}
+
+// DeleteDetailTxs removes all contract log data associated with a block hash.
+func DeleteDetailTxs(db DatabaseDeleter, hash common.Hash, number uint64) {
+	if err := db.Delete(blockDetailTxsKey(number, hash)); err != nil {
+		log.Crit("Failed to delete block detailtxs", "err", err)
+	}
+}
+
 // FindCommonAncestor returns the last common ancestor of two block headers
 func FindCommonAncestor(db DatabaseReader, a, b *types.Header) *types.Header {
 	for bn := b.Number.Uint64(); a.Number.Uint64() > bn; {
diff --git a/rawdb/accessors_chain_test.go b/rawdb/accessors_chain_test.go
index ca73b987..e6a237d4 100644
--- a/rawdb/accessors_chain_test.go
+++ b/rawdb/accessors_chain_test.go
@@ -225,7 +225,6 @@ func TestHeadStorage(t *testing.T) {
 		Head: &types.Header{Extra: []byte("test block header")},
 	}
 	blockFull := &types.Block{Head: &types.Header{Extra: []byte("test block full"), Coinbase: "coinbase"}}
-	blockFast := types.Block{Head: &types.Header{Extra: []byte("test block fast"), Coinbase: "coinbase"}}
 
 	// Check that no head entries are in a pristine database
 	if entry := ReadHeadHeaderHash(db); entry != (common.Hash{}) {
@@ -234,13 +233,10 @@ func TestHeadStorage(t *testing.T) {
 	if entry := ReadHeadBlockHash(db); entry != (common.Hash{}) {
 		t.Fatalf("Non head block entry returned: %v", entry)
 	}
-	if entry := ReadHeadFastBlockHash(db); entry != (common.Hash{}) {
-		t.Fatalf("Non fast head block entry returned: %v", entry)
-	}
+
 	// Assign separate entries for the head header and block
 	WriteHeadHeaderHash(db, blockHead.Hash())
 	WriteHeadBlockHash(db, blockFull.Hash())
-	WriteHeadFastBlockHash(db, blockFast.Hash())
 
 	// Check that both heads are present, and different (i.e. two heads maintained)
 	if entry := ReadHeadHeaderHash(db); entry != blockHead.Hash() {
@@ -249,9 +245,7 @@ func TestHeadStorage(t *testing.T) {
 	if entry := ReadHeadBlockHash(db); entry != blockFull.Hash() {
 		t.Fatalf("Head block hash mismatch: have %v, want %v", entry, blockFull.Hash())
 	}
-	if entry := ReadHeadFastBlockHash(db); entry != blockFast.Hash() {
-		t.Fatalf("Fast head block hash mismatch: have %v, want %v", entry, blockFast.Hash())
-	}
+
 }
 
 // Tests that receipts associated with a single block can be stored and retrieved.
@@ -308,3 +302,16 @@ func TestBlockReceiptStorage(t *testing.T) {
 		t.Fatalf("deleted receipts returned: %v", rs)
 	}
 }
+
+func TestIrreversibleNumberStore(t *testing.T) {
+	db := mdb.NewMemDatabase()
+
+	number := uint64(100)
+
+	WriteIrreversibleNumber(db, number)
+
+	if n := ReadIrreversibleNumber(db); n != number {
+		t.Fatalf("number mismatch: have %v, want %v", n, number)
+	}
+
+}
diff --git a/rawdb/accessors_metadata.go b/rawdb/accessors_metadata.go
index f158bf22..fef258a0 100644
--- a/rawdb/accessors_metadata.go
+++ b/rawdb/accessors_metadata.go
@@ -22,27 +22,8 @@ import (
 	"github.com/ethereum/go-ethereum/log"
 	"github.com/fractalplatform/fractal/common"
 	"github.com/fractalplatform/fractal/params"
-	"github.com/fractalplatform/fractal/utils/rlp"
 )
 
-// ReadDatabaseVersion retrieves the version number of the database.
-func ReadDatabaseVersion(db DatabaseReader) int {
-	var version int
-
-	enc, _ := db.Get(databaseVerisionKey)
-	rlp.DecodeBytes(enc, &version)
-
-	return version
-}
-
-// WriteDatabaseVersion stores the version number of the database
-func WriteDatabaseVersion(db DatabaseWriter, version int) {
-	enc, _ := rlp.EncodeToBytes(version)
-	if err := db.Put(databaseVerisionKey, enc); err != nil {
-		log.Crit("Failed to store the database version", "err", err)
-	}
-}
-
 // ReadChainConfig retrieves the consensus settings based on the given genesis hash.
 func ReadChainConfig(db DatabaseReader, hash common.Hash) *params.ChainConfig {
 	data, _ := db.Get(configKey(hash))
diff --git a/rawdb/schema.go b/rawdb/schema.go
index c1eca4de..3352fb5d 100644
--- a/rawdb/schema.go
+++ b/rawdb/schema.go
@@ -25,26 +25,23 @@ import (
 
 // The fields below define the low level database schema prefixing.
 var (
-	// databaseVerisionKey tracks the current database version.
-	databaseVerisionKey = []byte("DatabaseVersion")
-
+	//irreversibleNumberKey tracks the blcokchain irreversible number
+	irreversibleNumberKey = []byte("irreversibleNumber")
 	// headHeaderKey tracks the latest know header's hash.
 	headHeaderKey = []byte("LastHeader")
 
 	// headBlockKey tracks the latest know full block's hash.
 	headBlockKey = []byte("LastBlock")
 
-	// headFastBlockKey tracks the latest known incomplete block's hash duirng fast sync.
-	headFastBlockKey = []byte("LastFast")
-
 	// Data item prefixes (use single byte to avoid mixing data types, avoid `i`, used for indexes).
 	headerPrefix       = []byte("h") // headerPrefix + num (uint64 big endian) + hash -> header
 	headerTDSuffix     = []byte("t") // headerPrefix + num (uint64 big endian) + hash + headerTDSuffix -> td
 	headerHashSuffix   = []byte("n") // headerPrefix + num (uint64 big endian) + headerHashSuffix -> hash
 	headerNumberPrefix = []byte("H") // headerNumberPrefix + hash -> num (uint64 big endian)
 
-	blockBodyPrefix     = []byte("b") // blockBodyPrefix + num (uint64 big endian) + hash -> block body
-	blockReceiptsPrefix = []byte("r") // blockReceiptsPrefix + num (uint64 big endian) + hash -> block receipts
+	blockBodyPrefix      = []byte("b") // blockBodyPrefix + num (uint64 big endian) + hash -> block body
+	blockReceiptsPrefix  = []byte("r") // blockReceiptsPrefix + num (uint64 big endian) + hash -> block receipts
+	blockDetailTxsPrefix = []byte("d")
 
 	txLookupPrefix  = []byte("l") // txLookupPrefix + hash -> transaction/receipt lookup metadata
 	bloomBitsPrefix = []byte("B") // bloomBitsPrefix + bit (uint16 big endian) + section (uint64 big endian) + hash -> bloom bits
@@ -78,6 +75,11 @@ func encodeBlockNumber(number uint64) []byte {
 	return enc
 }
 
+// decodeBlockNumber decodes bytes as uint64
+func decodeBlockNumber(dec []byte) uint64 {
+	return binary.BigEndian.Uint64(dec)
+}
+
 // headerKey = headerPrefix + num (uint64 big endian) + hash
 func headerKey(number uint64, hash common.Hash) []byte {
 	return append(append(headerPrefix, encodeBlockNumber(number)...), hash.Bytes()...)
@@ -107,6 +109,11 @@ func blockReceiptsKey(number uint64, hash common.Hash) []byte {
 	return append(append(blockReceiptsPrefix, encodeBlockNumber(number)...), hash.Bytes()...)
 }
 
+// blockDetailTxsKey = blockDetailTxsPrefix + num (uint64 big endian) + hash
+func blockDetailTxsKey(number uint64, hash common.Hash) []byte {
+	return append(append(blockDetailTxsPrefix, encodeBlockNumber(number)...), hash.Bytes()...)
+}
+
 // blockStatePrefix + num (uint64 big endian) + hash -> block revert info
 func blockStateOutKey(hash common.Hash) []byte {
 	return append(blockStateOutPrefix, hash.Bytes()...)
diff --git a/rpc/subscription.go b/rpc/subscription.go
index 6ce7befa..c0ce9b84 100644
--- a/rpc/subscription.go
+++ b/rpc/subscription.go
@@ -1,18 +1,18 @@
-// Copyright 2016 The go-ethereum Authors
-// This file is part of the go-ethereum library.
+// Copyright 2018 The Fractal Team Authors
+// This file is part of the fractal project.
 //
-// The go-ethereum library is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Lesser General Public License as published by
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
 // the Free Software Foundation, either version 3 of the License, or
 // (at your option) any later version.
 //
-// The go-ethereum library is distributed in the hope that it will be useful,
+// This program is distributed in the hope that it will be useful,
 // but WITHOUT ANY WARRANTY; without even the implied warranty of
 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU Lesser General Public License for more details.
+// GNU General Public License for more details.
 //
-// You should have received a copy of the GNU Lesser General Public License
-// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
 
 package rpc
 
diff --git a/internal/api/account.go b/rpcapi/account.go
similarity index 81%
rename from internal/api/account.go
rename to rpcapi/account.go
index 0537b126..4df2d0b3 100644
--- a/internal/api/account.go
+++ b/rpcapi/account.go
@@ -14,7 +14,7 @@
 // You should have received a copy of the GNU General Public License
 // along with this program. If not, see <http://www.gnu.org/licenses/>.
 
-package api
+package rpcapi
 
 import (
 	"context"
@@ -51,6 +51,18 @@ func (aapi *AccountAPI) AccountIsExist(ctx context.Context, acctName common.Name
 	return acct.AccountIsExist(acctName)
 }
 
+//GetAccountByID
+func (aapi *AccountAPI) GetAccountByID(ctx context.Context, accountID uint64) (*accountmanager.Account, error) {
+	am, err := aapi.b.GetAccountManager()
+	if err != nil {
+		return nil, err
+	}
+	if am == nil {
+		return nil, ErrGetAccounManagerErr
+	}
+	return am.GetAccountById(accountID)
+}
+
 //GetAccountByName
 func (aapi *AccountAPI) GetAccountByName(ctx context.Context, accountName common.Name) (*accountmanager.Account, error) {
 	am, err := aapi.b.GetAccountManager()
@@ -64,7 +76,7 @@ func (aapi *AccountAPI) GetAccountByName(ctx context.Context, accountName common
 }
 
 //GetAccountBalanceByID
-func (aapi *AccountAPI) GetAccountBalanceByID(ctx context.Context, accountName common.Name, assetID uint64) (*big.Int, error) {
+func (aapi *AccountAPI) GetAccountBalanceByID(ctx context.Context, accountName common.Name, assetID uint64, typeID uint64) (*big.Int, error) {
 	am, err := aapi.b.GetAccountManager()
 	if err != nil {
 		return nil, err
@@ -72,33 +84,9 @@ func (aapi *AccountAPI) GetAccountBalanceByID(ctx context.Context, accountName c
 	if am == nil {
 		return nil, ErrGetAccounManagerErr
 	}
-	return am.GetAccountBalanceByID(accountName, assetID)
+	return am.GetAccountBalanceByID(accountName, assetID, typeID)
 }
 
-//func (aapi *AccountAPI) GetAccountBalanceByName(ctx context.Context, accountName common.Name, assetName string) (*big.Int, error) {
-//	acct, err := aapi.b.GetAccountManager()
-//	if err != nil {
-//		return nil, err
-//	}
-//	if acct == nil {
-//		return nil, ErrGetAccounManagerErr
-//	}
-//	a, err := acct.GetAccountByName(accountName)
-//	if err != nil {
-//		return nil, err
-//	}
-//	return a.GetBalanceByID(assetID)
-//}
-
-//
-//func (aapi *AccountAPI) GetBalancesList(ctx context.Context,accountName common.Name) ([]*AssetBalance, error){
-//	acct := aapi.b.GetAccountManager()
-//	if acct == nil {
-//		return nil,ErrGetAccounManagerErr
-//	}
-//	return acct.GetBalancesList(accountName)
-//}
-
 //GetCode
 func (aapi *AccountAPI) GetCode(ctx context.Context, accountName common.Name) (hexutil.Bytes, error) {
 	acct, err := aapi.b.GetAccountManager()
@@ -154,8 +142,20 @@ func (aapi *AccountAPI) GetAssetInfoByID(ctx context.Context, assetID uint64) (*
 	return acct.GetAssetInfoByID(assetID)
 }
 
+//GetAssetAmountByTime
+func (aapi *AccountAPI) GetAssetAmountByTime(ctx context.Context, assetID uint64, time uint64) (*big.Int, error) {
+	am, err := aapi.b.GetAccountManager()
+	if err != nil {
+		return nil, err
+	}
+	if am == nil {
+		return nil, ErrGetAccounManagerErr
+	}
+	return am.GetAssetAmountByTime(assetID, time)
+}
+
 //GetAccountBalanceByTime
-func (aapi *AccountAPI) GetAccountBalanceByTime(ctx context.Context, accountName common.Name, assetID uint64, time uint64) (*big.Int, error) {
+func (aapi *AccountAPI) GetAccountBalanceByTime(ctx context.Context, accountName common.Name, assetID uint64, typeID uint64, time uint64) (*big.Int, error) {
 	am, err := aapi.b.GetAccountManager()
 	if err != nil {
 		return nil, err
@@ -163,7 +163,7 @@ func (aapi *AccountAPI) GetAccountBalanceByTime(ctx context.Context, accountName
 	if am == nil {
 		return nil, ErrGetAccounManagerErr
 	}
-	return am.GetBalanceByTime(accountName, assetID, time)
+	return am.GetBalanceByTime(accountName, assetID, typeID, time)
 }
 
 //GetSnapshotLast  get last snapshot time
diff --git a/internal/api/addrlock.go b/rpcapi/addrlock.go
similarity index 99%
rename from internal/api/addrlock.go
rename to rpcapi/addrlock.go
index 77e59ef8..00824de9 100644
--- a/internal/api/addrlock.go
+++ b/rpcapi/addrlock.go
@@ -14,7 +14,7 @@
 // You should have received a copy of the GNU General Public License
 // along with this program. If not, see <http://www.gnu.org/licenses/>.
 
-package api
+package rpcapi
 
 import (
 	"sync"
diff --git a/internal/api/backend.go b/rpcapi/backend.go
similarity index 86%
rename from internal/api/backend.go
rename to rpcapi/backend.go
index 557825b6..8842552c 100644
--- a/internal/api/backend.go
+++ b/rpcapi/backend.go
@@ -14,24 +14,23 @@
 // You should have received a copy of the GNU General Public License
 // along with this program. If not, see <http://www.gnu.org/licenses/>.
 
-// Package api implements the general Ethereum API functions.
-package api
+// package rpcapi implements the general API functions.
+
+package rpcapi
 
 import (
 	"context"
 	"math/big"
 
-	"github.com/fractalplatform/fractal/consensus"
-
 	"github.com/fractalplatform/fractal/accountmanager"
 	"github.com/fractalplatform/fractal/common"
+	"github.com/fractalplatform/fractal/consensus"
 	"github.com/fractalplatform/fractal/params"
 	"github.com/fractalplatform/fractal/processor/vm"
 	"github.com/fractalplatform/fractal/rpc"
 	"github.com/fractalplatform/fractal/state"
 	"github.com/fractalplatform/fractal/types"
 	"github.com/fractalplatform/fractal/utils/fdb"
-	"github.com/fractalplatform/fractal/wallet"
 )
 
 // Backend interface provides the common API services (that are provided by
@@ -49,8 +48,13 @@ type Backend interface {
 	StateAndHeaderByNumber(ctx context.Context, blockNr rpc.BlockNumber) (*state.StateDB, *types.Header, error)
 	GetBlock(ctx context.Context, blockHash common.Hash) (*types.Block, error)
 	GetReceipts(ctx context.Context, blockHash common.Hash) ([]*types.Receipt, error)
+	GetDetailTxsLog(ctx context.Context, hash common.Hash) ([]*types.DetailTx, error)
+	GetBlockDetailLog(ctx context.Context, blockNr rpc.BlockNumber) *types.BlockAndResult
 	GetTd(blockHash common.Hash) *big.Int
 	GetEVM(ctx context.Context, account *accountmanager.AccountManager, state *state.StateDB, from common.Name, assetID uint64, gasPrice *big.Int, header *types.Header, vmCfg vm.Config) (*vm.EVM, func() error, error)
+	GetDetailTxByFilter(ctx context.Context, filterFn func(common.Name) bool, blockNr rpc.BlockNumber, lookbackNum uint64) []*types.DetailTx
+	GetTxsByFilter(ctx context.Context, filterFn func(common.Name) bool, blockNr rpc.BlockNumber, lookbackNum uint64) []common.Hash
+	GetBadBlocks(ctx context.Context) ([]*types.Block, error)
 
 	// TxPool API
 	SendTx(ctx context.Context, signedTx *types.Transaction) error
@@ -64,9 +68,6 @@ type Backend interface {
 
 	SetGasPrice(gasPrice *big.Int) bool
 
-	//Wallet
-	Wallet() *wallet.Wallet
-
 	// P2P
 	AddPeer(url string) error
 	RemovePeer(url string) error
@@ -75,9 +76,7 @@ type Backend interface {
 	PeerCount() int
 	Peers() []string
 	SelfNode() string
-
 	Engine() consensus.IEngine
-
 	APIs() []rpc.API
 }
 
@@ -98,11 +97,6 @@ func GetAPIs(apiBackend Backend) []rpc.API {
 			Version:   "1.0",
 			Service:   NewPublicFractalAPI(apiBackend),
 			Public:    true,
-		}, {
-			Namespace: "keystore",
-			Version:   "1.0",
-			Service:   NewPrivateKeyStoreAPI(apiBackend),
-			Public:    true,
 		},
 		{
 			Namespace: "account",
diff --git a/internal/api/blockchain.go b/rpcapi/blockchain.go
similarity index 72%
rename from internal/api/blockchain.go
rename to rpcapi/blockchain.go
index d0295a49..fd8243cb 100644
--- a/internal/api/blockchain.go
+++ b/rpcapi/blockchain.go
@@ -14,10 +14,11 @@
 // You should have received a copy of the GNU General Public License
 // along with this program. If not, see <http://www.gnu.org/licenses/>.
 
-package api
+package rpcapi
 
 import (
 	"context"
+	"encoding/json"
 	"fmt"
 	"math"
 	"math/big"
@@ -35,17 +36,17 @@ import (
 	"github.com/fractalplatform/fractal/types"
 )
 
-// PublicBlockChainAPI provides an API to access the Ethereum blockchain.
+// PublicBlockChainAPI provides an API to access the blockchain.
 // It offers only methods that operate on public data that is freely available to anyone.
 const (
-	defaultGasPrice = params.GWei
+	defaultGasPrice = 1e9
 )
 
 type PublicBlockChainAPI struct {
 	b Backend
 }
 
-// NewPublicBlockChainAPI creates a new Ethereum blockchain API.
+// NewPublicBlockChainAPI creates a new blockchain API.
 func NewPublicBlockChainAPI(b Backend) *PublicBlockChainAPI {
 	return &PublicBlockChainAPI{b}
 }
@@ -83,51 +84,6 @@ func (s *PublicBlockChainAPI) GetBlockByNumber(ctx context.Context, blockNr rpc.
 	}
 	return nil, err
 }
-func (s *PublicBlockChainAPI) GetTxNumByBlockHash(ctx context.Context, blockHash common.Hash) (int, error) {
-	block, err := s.b.GetBlock(ctx, blockHash)
-	if block != nil {
-		return len(block.Transactions()), nil
-	}
-	return 0, err
-}
-func (s *PublicBlockChainAPI) GetTxNumByBlockNum(ctx context.Context, blockNr rpc.BlockNumber) (int, error) {
-	block, err := s.b.BlockByNumber(ctx, blockNr)
-	if block != nil {
-		return len(block.Transactions()), nil
-	}
-	return 0, err
-}
-func (s *PublicBlockChainAPI) GetTotalTxNumByBlockHash(ctx context.Context, blockHash common.Hash, lookbackNum uint64) (*big.Int, error) {
-	block, err := s.b.GetBlock(ctx, blockHash)
-	if block != nil {
-		txNum := len(block.Transactions())
-		totalTxNum := big.NewInt(int64(txNum))
-		height := block.Number().Uint64()
-		for i := height - 1; i >= 0 && i > height-lookbackNum; i-- {
-			block, err := s.b.BlockByNumber(ctx, rpc.BlockNumber(i))
-			if block != nil {
-				totalTxNum = totalTxNum.Add(totalTxNum, big.NewInt(int64(len(block.Transactions()))))
-			} else {
-				return nil, err
-			}
-		}
-		return totalTxNum, nil
-	}
-
-	return nil, err
-}
-func (s *PublicBlockChainAPI) GetTotalTxNumByBlockNum(ctx context.Context, blockNr rpc.BlockNumber, lookbackNum uint64) (*big.Int, error) {
-	totalTxNum := big.NewInt(0)
-	for i := blockNr; i >= 0 && i > blockNr-rpc.BlockNumber(lookbackNum); i-- {
-		block, err := s.b.BlockByNumber(ctx, i)
-		if block != nil {
-			totalTxNum = totalTxNum.Add(totalTxNum, big.NewInt(int64(len(block.Transactions()))))
-		} else {
-			return nil, err
-		}
-	}
-	return totalTxNum, nil
-}
 
 // rpcOutputBlock uses the generalized output filler, then adds the total difficulty field, which requires
 // a `PublicBlockchainAPI`.
@@ -170,6 +126,78 @@ func (s *PublicBlockChainAPI) GetTransactionReceipt(ctx context.Context, hash co
 	return receipt.NewRPCReceipt(blockHash, blockNumber, index, tx), nil
 }
 
+func (s *PublicBlockChainAPI) GetBlockAndResultByNumber(ctx context.Context, blockNr rpc.BlockNumber) (*types.BlockAndResult, error) {
+	r := s.b.GetBlockDetailLog(ctx, blockNr)
+	if r == nil {
+		return nil, nil
+	}
+	block, err := s.GetBlockByNumber(ctx, blockNr, true)
+	r.Block = block
+	return r, err
+}
+
+func (s *PublicBlockChainAPI) GetTxsByAccount(ctx context.Context, acctName common.Name, blockNr rpc.BlockNumber, lookbackNum uint64) ([]common.Hash, error) {
+	filterFn := func(name common.Name) bool {
+		return name == acctName
+	}
+
+	return s.b.GetTxsByFilter(ctx, filterFn, blockNr, lookbackNum), nil
+}
+
+func (s *PublicBlockChainAPI) GetTxsByBloom(ctx context.Context, bloomByte hexutil.Bytes, blockNr rpc.BlockNumber, lookbackNum uint64) ([]common.Hash, error) {
+	bloom := types.BytesToBloom(bloomByte)
+
+	filterFn := func(name common.Name) bool {
+		return bloom.TestBytes([]byte(name))
+	}
+	return s.b.GetTxsByFilter(ctx, filterFn, blockNr, lookbackNum), nil
+}
+
+func (s *PublicBlockChainAPI) GetInternalTxByAccount(ctx context.Context, acctName common.Name, blockNr rpc.BlockNumber, lookbackNum uint64) ([]*types.DetailTx, error) {
+	filterFn := func(name common.Name) bool {
+		return name == acctName
+	}
+
+	return s.b.GetDetailTxByFilter(ctx, filterFn, blockNr, lookbackNum), nil
+}
+
+func (s *PublicBlockChainAPI) GetInternalTxByBloom(ctx context.Context, bloomByte hexutil.Bytes, blockNr rpc.BlockNumber, lookbackNum uint64) ([]*types.DetailTx, error) {
+	bloom := types.BytesToBloom(bloomByte)
+
+	filterFn := func(name common.Name) bool {
+		return bloom.TestBytes([]byte(name))
+	}
+	return s.b.GetDetailTxByFilter(ctx, filterFn, blockNr, lookbackNum), nil
+}
+
+func (s *PublicBlockChainAPI) GetInternalTxByHash(ctx context.Context, hash common.Hash) (*types.DetailTx, error) {
+	tx, blockHash, blockNumber, index := rawdb.ReadTransaction(s.b.ChainDb(), hash)
+	if tx == nil {
+		return nil, nil
+	}
+
+	detailtxs := rawdb.ReadDetailTxs(s.b.ChainDb(), blockHash, blockNumber)
+	if len(detailtxs) <= int(index) {
+		return nil, nil
+	}
+
+	return detailtxs[index], nil
+}
+
+func (s *PublicBlockChainAPI) GetBadBlocks(ctx context.Context, fullTx bool) ([]map[string]interface{}, error) {
+	blocks, err := s.b.GetBadBlocks(ctx)
+	if len(blocks) != 0 {
+		ret_block := make([]map[string]interface{}, len(blocks))
+
+		for i, b := range blocks {
+			ret_block[i] = s.rpcOutputBlock(s.b.ChainConfig().ChainID, b, true, fullTx)
+		}
+
+		return ret_block, nil
+	}
+	return nil, err
+}
+
 type CallArgs struct {
 	ActionType types.ActionType `json:"actionType"`
 	From       common.Name      `json:"from"`
@@ -286,3 +314,27 @@ func (s *PublicBlockChainAPI) EstimateGas(ctx context.Context, args CallArgs) (h
 	}
 	return hexutil.Uint64(hi), nil
 }
+
+// GetChainConfig returns chain config.
+func (s *PublicBlockChainAPI) GetChainConfig() map[string]interface{} {
+	ret := map[string]interface{}{}
+	g, err := s.b.BlockByNumber(context.Background(), 0)
+	if err != nil {
+		return ret
+	}
+	cfg := rawdb.ReadChainConfig(s.b.ChainDb(), g.Hash())
+	bts, _ := json.Marshal(cfg)
+	json.Unmarshal(bts, &ret)
+	return ret
+}
+
+// GetGeneisisJson returns geneisis config.
+func (s *PublicBlockChainAPI) GetGeneisis() map[string]interface{} {
+	ret := map[string]interface{}{}
+	g, err := s.b.BlockByNumber(context.Background(), 0)
+	if err != nil {
+		return ret
+	}
+	json.Unmarshal(g.Head.Extra, &ret)
+	return ret
+}
diff --git a/internal/api/fractal.go b/rpcapi/fractal.go
similarity index 51%
rename from internal/api/fractal.go
rename to rpcapi/fractal.go
index 3919c170..47c41903 100644
--- a/internal/api/fractal.go
+++ b/rpcapi/fractal.go
@@ -14,16 +14,14 @@
 // You should have received a copy of the GNU General Public License
 // along with this program. If not, see <http://www.gnu.org/licenses/>.
 
-package api
+package rpcapi
 
 import (
 	"context"
-	"errors"
 	"math/big"
 
 	"github.com/ethereum/go-ethereum/common/hexutil"
 	"github.com/fractalplatform/fractal/common"
-	"github.com/fractalplatform/fractal/crypto"
 	"github.com/fractalplatform/fractal/types"
 	"github.com/fractalplatform/fractal/utils/rlp"
 )
@@ -52,56 +50,3 @@ func (s *PublicFractalAPI) SendRawTransaction(ctx context.Context, encodedTx hex
 	}
 	return submitTransaction(ctx, s.b, tx)
 }
-
-type SendArgs struct {
-	ChainID    *big.Int         `json:"chainID"`
-	ActionType types.ActionType `json:"actionType"`
-	GasAssetID uint64           `json:"gasAssetId"`
-	From       common.Name      `json:"from"`
-	To         common.Name      `json:"to"`
-	Nonce      uint64           `json:"nonce"`
-	AssetID    uint64           `json:"assetId"`
-	Gas        uint64           `json:"gas"`
-	GasPrice   *big.Int         `json:"gasPrice"`
-	Value      *big.Int         `json:"value"`
-	Data       hexutil.Bytes    `json:"data"`
-	Passphrase string           `json:"password"`
-}
-
-func (s *PublicFractalAPI) SendTransaction(ctx context.Context, args SendArgs) (common.Hash, error) {
-	acct, err := s.b.GetAccountManager()
-	if err != nil {
-		return common.Hash{}, err
-	}
-	if acct == nil {
-		return common.Hash{}, ErrGetAccounManagerErr
-	}
-	fromAcct, err := acct.GetAccountByName(args.From)
-	if err != nil {
-		return common.Hash{}, err
-	}
-	if fromAcct == nil {
-		return common.Hash{}, errors.New("invalid user")
-	}
-
-	pubByte, _ := crypto.UnmarshalPubkey(fromAcct.PublicKey.Bytes())
-	if !s.b.Wallet().HasAddress(crypto.PubkeyToAddress(*pubByte)) {
-		return common.Hash{}, errors.New("user not in local wallet")
-	}
-	cacheAcct, err := s.b.Wallet().Find(crypto.PubkeyToAddress(*pubByte))
-	if err != nil {
-		return common.Hash{}, err
-	}
-
-	assetID := uint64(args.AssetID)
-	gas := uint64(args.Gas)
-	action := types.NewAction(args.ActionType, args.From, args.To, args.Nonce, assetID, gas, args.Value, args.Data)
-	tx := types.NewTransaction(args.GasAssetID, args.GasPrice, action)
-
-	tx, err = s.b.Wallet().SignTxWithPassphrase(cacheAcct, args.Passphrase, tx, action, args.ChainID)
-	if err != nil {
-		return common.Hash{}, err
-	}
-
-	return submitTransaction(ctx, s.b, tx)
-}
diff --git a/internal/api/p2p.go b/rpcapi/p2p.go
similarity index 99%
rename from internal/api/p2p.go
rename to rpcapi/p2p.go
index 0fed9caa..8ecbe341 100644
--- a/internal/api/p2p.go
+++ b/rpcapi/p2p.go
@@ -14,7 +14,7 @@
 // You should have received a copy of the GNU General Public License
 // along with this program. If not, see <http://www.gnu.org/licenses/>.
 
-package api
+package rpcapi
 
 import (
 	"context"
diff --git a/internal/api/txpool.go b/rpcapi/txpool.go
similarity index 99%
rename from internal/api/txpool.go
rename to rpcapi/txpool.go
index ef33b149..d36bea81 100644
--- a/internal/api/txpool.go
+++ b/rpcapi/txpool.go
@@ -14,7 +14,7 @@
 // You should have received a copy of the GNU General Public License
 // along with this program. If not, see <http://www.gnu.org/licenses/>.
 
-package api
+package rpcapi
 
 import (
 	"fmt"
diff --git a/internal/api/utils.go b/rpcapi/utils.go
similarity index 99%
rename from internal/api/utils.go
rename to rpcapi/utils.go
index c10989c1..ed1899d1 100644
--- a/internal/api/utils.go
+++ b/rpcapi/utils.go
@@ -14,7 +14,7 @@
 // You should have received a copy of the GNU General Public License
 // along with this program. If not, see <http://www.gnu.org/licenses/>.
 
-package api
+package rpcapi
 
 import (
 	"context"
diff --git a/scripts/test.sh b/scripts/test.sh
index 7a030f6a..fe486fc4 100755
--- a/scripts/test.sh
+++ b/scripts/test.sh
@@ -16,6 +16,19 @@
 
 #!/usr/bin/env bash
 
+# clear test_sdk data
+rm -r ./build/test_sdk
+
+# generate test directory
+mkdir ./build/test_sdk
+
+# clear test node 
+ps -ef | grep ./build/test_sdk/ft | grep -v grep |  awk -F ' ' '{print $2}' | xargs kill -9
+
+# start test node
+./build/bin/ft --datadir ./build/test_sdk/ft --log_level=4 --miner_start > ./build/test_sdk/test.log 2>&1 &
+
+# collect code coverrage data
 set -e
 echo "mode: count" >coverage.out
 
@@ -28,3 +41,9 @@ for d in $(go list ./... | grep -v vendor | grep -v test); do
     fi
 done
 
+# kill test node 
+ps -ef | grep ./build/test_sdk/ft | grep -v grep |  awk -F ' ' '{print $2}' | xargs kill -9
+
+# clear test_sdk data
+rm -r ./build/test_sdk
+
diff --git a/sdk/account.go b/sdk/account.go
new file mode 100644
index 00000000..7580a9d3
--- /dev/null
+++ b/sdk/account.go
@@ -0,0 +1,931 @@
+// Copyright 2018 The Fractal Team Authors
+// This file is part of the fractal project.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+package sdk
+
+import (
+	"crypto/ecdsa"
+	"math"
+	"math/big"
+	"time"
+
+	"github.com/fractalplatform/fractal/accountmanager"
+	"github.com/fractalplatform/fractal/asset"
+	"github.com/fractalplatform/fractal/common"
+	"github.com/fractalplatform/fractal/consensus/dpos"
+	"github.com/fractalplatform/fractal/crypto"
+	"github.com/fractalplatform/fractal/types"
+	"github.com/fractalplatform/fractal/utils/rlp"
+)
+
+var (
+	timeout = int64(time.Second) * 10
+)
+
+// Account account object
+type Account struct {
+	api      *API
+	name     common.Name
+	priv     *ecdsa.PrivateKey
+	gasprice *big.Int
+	feeid    uint64
+	nonce    uint64 // nonce == math.MaxUint64, auto get
+	checked  bool   // check result
+	chainID  *big.Int
+}
+
+// NewAccount new account object
+func NewAccount(api *API, name common.Name, priv *ecdsa.PrivateKey, feeid uint64, nonce uint64, checked bool, chainID *big.Int) *Account {
+	return &Account{
+		api:      api,
+		name:     name,
+		priv:     priv,
+		gasprice: big.NewInt(1e10),
+		feeid:    feeid,
+		nonce:    nonce,
+		checked:  checked,
+		chainID:  chainID,
+	}
+}
+
+// Pubkey account pub key
+func (acc *Account) Pubkey() common.PubKey {
+	return common.BytesToPubKey(crypto.FromECDSAPub(&acc.priv.PublicKey))
+}
+
+//=====================================================================================
+//                       Transactions
+//=====================================================================================
+
+// CreateAccount new account
+func (acc *Account) CreateAccount(to common.Name, value *big.Int, id uint64, gas uint64, newacct *accountmanager.AccountAction) (hash common.Hash, err error) {
+	nonce := acc.nonce
+	if nonce == math.MaxUint64 {
+		nonce, err = acc.api.AccountNonce(acc.name.String())
+		if err != nil {
+			return
+		}
+	}
+	payload, _ := rlp.EncodeToBytes(newacct)
+	action := types.NewAction(types.CreateAccount, acc.name, to, nonce, id, gas, value, payload)
+	tx := types.NewTransaction(acc.feeid, acc.gasprice, []*types.Action{action}...)
+	key := types.MakeKeyPair(acc.priv, []uint64{0})
+	err = types.SignActionWithMultiKey(action, tx, types.NewSigner(acc.chainID), []*types.KeyPair{key})
+	if err != nil {
+		return
+	}
+	rawtx, _ := rlp.EncodeToBytes(tx)
+	checked := acc.checked || acc.nonce == math.MaxUint64
+	var checkedfunc func() error
+	if checked {
+		// before
+		checkedfunc, err = acc.checkCreateAccount(action)
+		if err != nil {
+			return
+		}
+	}
+	hash, err = acc.api.SendRawTransaction(rawtx)
+	if err != nil {
+		return
+	}
+	if checked {
+		//after
+		err = acc.utilReceipt(hash, timeout)
+		if err != nil {
+			return
+		}
+		err = checkedfunc()
+		if err != nil {
+			return
+		}
+	}
+
+	if acc.nonce != math.MaxUint64 {
+		acc.nonce++
+	}
+	return
+}
+
+// UpdateAccount update accout
+func (acc *Account) UpdateAccount(to common.Name, value *big.Int, id uint64, gas uint64, newacct *accountmanager.AccountAction) (hash common.Hash, err error) {
+	nonce := acc.nonce
+	if nonce == math.MaxUint64 {
+		nonce, err = acc.api.AccountNonce(acc.name.String())
+		if err != nil {
+			return
+		}
+	}
+
+	bts, _ := rlp.EncodeToBytes(newacct)
+	action := types.NewAction(types.UpdateAccount, acc.name, to, nonce, id, gas, value, bts)
+	tx := types.NewTransaction(acc.feeid, acc.gasprice, []*types.Action{action}...)
+	key := types.MakeKeyPair(acc.priv, []uint64{0})
+	err = types.SignActionWithMultiKey(action, tx, types.NewSigner(acc.chainID), []*types.KeyPair{key})
+	if err != nil {
+		return
+	}
+	rawtx, _ := rlp.EncodeToBytes(tx)
+	checked := acc.checked || acc.nonce == math.MaxUint64
+	var checkedfunc func() error
+	if checked {
+		// before
+		checkedfunc, err = acc.checkUpdateAccount(action)
+		if err != nil {
+			return
+		}
+	}
+	hash, err = acc.api.SendRawTransaction(rawtx)
+	if err != nil {
+		return
+	}
+	if checked {
+		//after
+		err = acc.utilReceipt(hash, timeout)
+		if err != nil {
+			return
+		}
+		err = checkedfunc()
+		if err != nil {
+			return
+		}
+	}
+
+	if acc.nonce != math.MaxUint64 {
+		acc.nonce++
+	}
+	return
+}
+
+// Transfer transfer tokens
+func (acc *Account) Transfer(to common.Name, value *big.Int, id uint64, gas uint64) (hash common.Hash, err error) {
+	nonce := acc.nonce
+	if nonce == math.MaxUint64 {
+		nonce, err = acc.api.AccountNonce(acc.name.String())
+		if err != nil {
+			return
+		}
+	}
+
+	// transfer
+	action := types.NewAction(types.Transfer, acc.name, to, nonce, id, gas, value, nil)
+	tx := types.NewTransaction(acc.feeid, acc.gasprice, []*types.Action{action}...)
+	key := types.MakeKeyPair(acc.priv, []uint64{0})
+	err = types.SignActionWithMultiKey(action, tx, types.NewSigner(acc.chainID), []*types.KeyPair{key})
+	if err != nil {
+		return
+	}
+	rawtx, _ := rlp.EncodeToBytes(tx)
+	checked := acc.checked || acc.nonce == math.MaxUint64
+	var checkedfunc func() error
+	if checked {
+		//before
+		checkedfunc, err = acc.checkTranfer(action)
+		if err != nil {
+			return
+		}
+	}
+	hash, err = acc.api.SendRawTransaction(rawtx)
+	if err != nil {
+		return
+	}
+	if checked {
+		//after
+		err = acc.utilReceipt(hash, timeout)
+		if err != nil {
+			return
+		}
+		err = checkedfunc()
+		if err != nil {
+			return
+		}
+	}
+
+	if acc.nonce != math.MaxUint64 {
+		acc.nonce++
+	}
+	return
+}
+
+// IssueAsset new asset
+func (acc *Account) IssueAsset(to common.Name, value *big.Int, id uint64, gas uint64, asset *asset.AssetObject) (hash common.Hash, err error) {
+	nonce := acc.nonce
+	if nonce == math.MaxUint64 {
+		nonce, err = acc.api.AccountNonce(acc.name.String())
+		if err != nil {
+			return
+		}
+	}
+
+	payload, _ := rlp.EncodeToBytes(asset)
+	action := types.NewAction(types.IssueAsset, acc.name, to, nonce, id, gas, value, payload)
+	tx := types.NewTransaction(acc.feeid, acc.gasprice, []*types.Action{action}...)
+	key := types.MakeKeyPair(acc.priv, []uint64{0})
+	err = types.SignActionWithMultiKey(action, tx, types.NewSigner(acc.chainID), []*types.KeyPair{key})
+	if err != nil {
+		return
+	}
+	rawtx, _ := rlp.EncodeToBytes(tx)
+	checked := acc.checked || acc.nonce == math.MaxUint64
+	var checkedfunc func() error
+	if checked {
+		// before
+		checkedfunc, err = acc.checkIssueAsset(action)
+		if err != nil {
+			return
+		}
+	}
+	hash, err = acc.api.SendRawTransaction(rawtx)
+	if err != nil {
+		return
+	}
+	if checked {
+		//after
+		err = acc.utilReceipt(hash, timeout)
+		if err != nil {
+			return
+		}
+		err = checkedfunc()
+		if err != nil {
+			return
+		}
+	}
+	if err != nil {
+		return
+	}
+
+	if acc.nonce != math.MaxUint64 {
+		acc.nonce++
+	}
+	return
+}
+
+// UpdateAsset update asset
+func (acc *Account) UpdateAsset(to common.Name, value *big.Int, id uint64, gas uint64, asset *asset.AssetObject) (hash common.Hash, err error) {
+	nonce := acc.nonce
+	if nonce == math.MaxUint64 {
+		nonce, err = acc.api.AccountNonce(acc.name.String())
+		if err != nil {
+			return
+		}
+	}
+
+	payload, _ := rlp.EncodeToBytes(asset)
+	action := types.NewAction(types.UpdateAsset, acc.name, to, nonce, id, gas, value, payload)
+	tx := types.NewTransaction(acc.feeid, acc.gasprice, []*types.Action{action}...)
+	key := types.MakeKeyPair(acc.priv, []uint64{0})
+
+	err = types.SignActionWithMultiKey(action, tx, types.NewSigner(acc.chainID), []*types.KeyPair{key})
+	if err != nil {
+		return
+	}
+	rawtx, _ := rlp.EncodeToBytes(tx)
+	checked := acc.checked || acc.nonce == math.MaxUint64
+	var checkedfunc func() error
+	if checked {
+		// before
+		checkedfunc, err = acc.checkUpdateAsset(action)
+		if err != nil {
+			return
+		}
+	}
+	hash, err = acc.api.SendRawTransaction(rawtx)
+	if err != nil {
+		return
+	}
+	if checked {
+		//after
+		err = acc.utilReceipt(hash, timeout)
+		if err != nil {
+			return
+		}
+		err = checkedfunc()
+		if err != nil {
+			return
+		}
+	}
+
+	if acc.nonce != math.MaxUint64 {
+		acc.nonce++
+	}
+	return
+}
+
+// IncreaseAsset update asset
+func (acc *Account) IncreaseAsset(to common.Name, value *big.Int, id uint64, gas uint64, asset *accountmanager.IncAsset) (hash common.Hash, err error) {
+	nonce := acc.nonce
+	if nonce == math.MaxUint64 {
+		nonce, err = acc.api.AccountNonce(acc.name.String())
+		if err != nil {
+			return
+		}
+	}
+
+	payload, _ := rlp.EncodeToBytes(asset)
+	action := types.NewAction(types.IncreaseAsset, acc.name, to, nonce, id, gas, value, payload)
+	tx := types.NewTransaction(acc.feeid, acc.gasprice, []*types.Action{action}...)
+	key := types.MakeKeyPair(acc.priv, []uint64{0})
+
+	err = types.SignActionWithMultiKey(action, tx, types.NewSigner(acc.chainID), []*types.KeyPair{key})
+	if err != nil {
+		return
+	}
+	rawtx, _ := rlp.EncodeToBytes(tx)
+	checked := acc.checked || acc.nonce == math.MaxUint64
+	var checkedfunc func() error
+	if checked {
+		// before
+		checkedfunc, err = acc.checkIncreaseAsset(action)
+		if err != nil {
+			return
+		}
+	}
+	hash, err = acc.api.SendRawTransaction(rawtx)
+	if err != nil {
+		return
+	}
+	if checked {
+		//after
+		err = acc.utilReceipt(hash, timeout)
+		if err != nil {
+			return
+		}
+		err = checkedfunc()
+		if err != nil {
+			return
+		}
+	}
+
+	if acc.nonce != math.MaxUint64 {
+		acc.nonce++
+	}
+	return
+}
+
+// DestroyAsset destory asset
+func (acc *Account) DestroyAsset(to common.Name, value *big.Int, id uint64, gas uint64) (hash common.Hash, err error) {
+	nonce := acc.nonce
+	if nonce == math.MaxUint64 {
+		nonce, err = acc.api.AccountNonce(acc.name.String())
+		if err != nil {
+			return
+		}
+	}
+
+	action := types.NewAction(types.DestroyAsset, acc.name, to, nonce, id, gas, value, nil)
+	tx := types.NewTransaction(acc.feeid, acc.gasprice, []*types.Action{action}...)
+	key := types.MakeKeyPair(acc.priv, []uint64{0})
+
+	err = types.SignActionWithMultiKey(action, tx, types.NewSigner(acc.chainID), []*types.KeyPair{key})
+	if err != nil {
+		return
+	}
+	rawtx, _ := rlp.EncodeToBytes(tx)
+	checked := acc.checked || acc.nonce == math.MaxUint64
+	var checkedfunc func() error
+	if checked {
+		// before
+		checkedfunc, err = acc.checkDestroyAsset(action)
+		if err != nil {
+			return
+		}
+	}
+	hash, err = acc.api.SendRawTransaction(rawtx)
+	if err != nil {
+		return
+	}
+	if checked {
+		//after
+		err = acc.utilReceipt(hash, timeout)
+		if err != nil {
+			return
+		}
+		err = checkedfunc()
+		if err != nil {
+			return
+		}
+	}
+
+	if acc.nonce != math.MaxUint64 {
+		acc.nonce++
+	}
+	return
+}
+
+// SetAssetOwner update asset owner
+func (acc *Account) SetAssetOwner(to common.Name, value *big.Int, id uint64, gas uint64, asset *asset.AssetObject) (hash common.Hash, err error) {
+	nonce := acc.nonce
+	if nonce == math.MaxUint64 {
+		nonce, err = acc.api.AccountNonce(acc.name.String())
+		if err != nil {
+			return
+		}
+	}
+
+	payload, _ := rlp.EncodeToBytes(asset)
+	action := types.NewAction(types.SetAssetOwner, acc.name, to, nonce, id, gas, value, payload)
+	tx := types.NewTransaction(acc.feeid, acc.gasprice, []*types.Action{action}...)
+	key := types.MakeKeyPair(acc.priv, []uint64{0})
+
+	err = types.SignActionWithMultiKey(action, tx, types.NewSigner(acc.chainID), []*types.KeyPair{key})
+	if err != nil {
+		return
+	}
+	rawtx, _ := rlp.EncodeToBytes(tx)
+	checked := acc.checked || acc.nonce == math.MaxUint64
+	var checkedfunc func() error
+	if checked {
+		// before
+		checkedfunc, err = acc.checkSetAssetOwner(action)
+		if err != nil {
+			return
+		}
+	}
+	hash, err = acc.api.SendRawTransaction(rawtx)
+	if err != nil {
+		return
+	}
+	if checked {
+		//after
+		err = acc.utilReceipt(hash, timeout)
+		if err != nil {
+			return
+		}
+		err = checkedfunc()
+		if err != nil {
+			return
+		}
+	}
+
+	if acc.nonce != math.MaxUint64 {
+		acc.nonce++
+	}
+	return
+}
+
+// RegCadidate new cadidate
+func (acc *Account) RegCadidate(to common.Name, value *big.Int, id uint64, gas uint64, arg *dpos.RegisterCadidate) (hash common.Hash, err error) {
+	nonce := acc.nonce
+	if nonce == math.MaxUint64 {
+		nonce, err = acc.api.AccountNonce(acc.name.String())
+		if err != nil {
+			return
+		}
+	}
+
+	payload, _ := rlp.EncodeToBytes(arg)
+	action := types.NewAction(types.RegCadidate, acc.name, to, nonce, id, gas, value, payload)
+	tx := types.NewTransaction(acc.feeid, big.NewInt(1e10), []*types.Action{action}...)
+	key := types.MakeKeyPair(acc.priv, []uint64{0})
+
+	err = types.SignActionWithMultiKey(action, tx, types.NewSigner(acc.chainID), []*types.KeyPair{key})
+	if err != nil {
+		return
+	}
+	rawtx, _ := rlp.EncodeToBytes(tx)
+	checked := acc.checked || acc.nonce == math.MaxUint64
+	var checkedfunc func() error
+	if checked {
+		// before
+		checkedfunc, err = acc.chekRegProdoucer(action)
+		if err != nil {
+			return
+		}
+	}
+	hash, err = acc.api.SendRawTransaction(rawtx)
+	if err != nil {
+		return
+	}
+	if checked {
+		// after
+		err = acc.utilReceipt(hash, timeout)
+		if err != nil {
+			return
+		}
+		err = checkedfunc()
+		if err != nil {
+			return
+		}
+	}
+
+	if acc.nonce != math.MaxUint64 {
+		acc.nonce++
+	}
+	return
+}
+
+// UpdateCadidate update cadidate
+func (acc *Account) UpdateCadidate(to common.Name, value *big.Int, id uint64, gas uint64, arg *dpos.UpdateCadidate) (hash common.Hash, err error) {
+	nonce := acc.nonce
+	if nonce == math.MaxUint64 {
+		nonce, err = acc.api.AccountNonce(acc.name.String())
+		if err != nil {
+			return
+		}
+	}
+
+	payload, _ := rlp.EncodeToBytes(arg)
+	action := types.NewAction(types.UpdateCadidate, acc.name, to, nonce, id, gas, value, payload)
+	tx := types.NewTransaction(acc.feeid, big.NewInt(1e10), []*types.Action{action}...)
+	key := types.MakeKeyPair(acc.priv, []uint64{0})
+
+	err = types.SignActionWithMultiKey(action, tx, types.NewSigner(acc.chainID), []*types.KeyPair{key})
+	if err != nil {
+		return
+	}
+	rawtx, _ := rlp.EncodeToBytes(tx)
+	checked := acc.checked || acc.nonce == math.MaxUint64
+	var checkedfunc func() error
+	if checked {
+		// before
+		checkedfunc, err = acc.chekUpdateProdoucer(action)
+		if err != nil {
+			return
+		}
+	}
+	hash, err = acc.api.SendRawTransaction(rawtx)
+	if err != nil {
+		return
+	}
+	if checked {
+		// after
+		err = acc.utilReceipt(hash, timeout)
+		if err != nil {
+			return
+		}
+		err = checkedfunc()
+		if err != nil {
+			return
+		}
+	}
+
+	if acc.nonce != math.MaxUint64 {
+		acc.nonce++
+	}
+	return
+}
+
+// UnRegCadidate remove cadiate
+func (acc *Account) UnRegCadidate(to common.Name, value *big.Int, id uint64, gas uint64) (hash common.Hash, err error) {
+	nonce := acc.nonce
+	if nonce == math.MaxUint64 {
+		nonce, err = acc.api.AccountNonce(acc.name.String())
+		if err != nil {
+			return
+		}
+	}
+
+	action := types.NewAction(types.UnregCadidate, acc.name, to, nonce, id, gas, value, nil)
+	tx := types.NewTransaction(acc.feeid, big.NewInt(1e10), []*types.Action{action}...)
+	key := types.MakeKeyPair(acc.priv, []uint64{0})
+
+	err = types.SignActionWithMultiKey(action, tx, types.NewSigner(acc.chainID), []*types.KeyPair{key})
+	if err != nil {
+		panic(err)
+	}
+	rawtx, _ := rlp.EncodeToBytes(tx)
+	checked := acc.checked || acc.nonce == math.MaxUint64
+	var checkedfunc func() error
+	if checked {
+		// before
+		checkedfunc, err = acc.chekUnregProdoucer(action)
+		if err != nil {
+			return
+		}
+	}
+	hash, err = acc.api.SendRawTransaction(rawtx)
+	if err != nil {
+		return
+	}
+	if checked {
+		// after
+		err = acc.utilReceipt(hash, timeout)
+		if err != nil {
+			return
+		}
+		err = checkedfunc()
+		if err != nil {
+			return
+		}
+	}
+
+	if acc.nonce != math.MaxUint64 {
+		acc.nonce++
+	}
+	return
+}
+
+// VoteCadidate vote cadiate
+func (acc *Account) VoteCadidate(to common.Name, value *big.Int, id uint64, gas uint64, arg *dpos.VoteCadidate) (hash common.Hash, err error) {
+	nonce := acc.nonce
+	if nonce == math.MaxUint64 {
+		nonce, err = acc.api.AccountNonce(acc.name.String())
+		if err != nil {
+			return
+		}
+	}
+
+	payload, _ := rlp.EncodeToBytes(arg)
+	action := types.NewAction(types.VoteCadidate, acc.name, to, nonce, id, gas, value, payload)
+	tx := types.NewTransaction(acc.feeid, big.NewInt(1e10), []*types.Action{action}...)
+	key := types.MakeKeyPair(acc.priv, []uint64{0})
+
+	err = types.SignActionWithMultiKey(action, tx, types.NewSigner(acc.chainID), []*types.KeyPair{key})
+	if err != nil {
+		panic(err)
+	}
+	rawtx, _ := rlp.EncodeToBytes(tx)
+	checked := acc.checked || acc.nonce == math.MaxUint64
+	var checkedfunc func() error
+	if checked {
+		// before
+		checkedfunc, err = acc.chekVoteProdoucer(action)
+		if err != nil {
+			return
+		}
+	}
+	hash, err = acc.api.SendRawTransaction(rawtx)
+	if err != nil {
+		return
+	}
+	if checked {
+		// after
+		err = acc.utilReceipt(hash, timeout)
+		if err != nil {
+			return
+		}
+		err = checkedfunc()
+		if err != nil {
+			return
+		}
+	}
+
+	if acc.nonce != math.MaxUint64 {
+		acc.nonce++
+	}
+	return
+}
+
+// ChangeCadidate change cadidate
+func (acc *Account) ChangeCadidate(to common.Name, value *big.Int, id uint64, gas uint64, arg *dpos.ChangeCadidate) (hash common.Hash, err error) {
+	nonce := acc.nonce
+	if nonce == math.MaxUint64 {
+		nonce, err = acc.api.AccountNonce(acc.name.String())
+		if err != nil {
+			return
+		}
+	}
+
+	payload, _ := rlp.EncodeToBytes(arg)
+	action := types.NewAction(types.ChangeCadidate, acc.name, to, nonce, id, gas, value, payload)
+	tx := types.NewTransaction(acc.feeid, big.NewInt(1e10), []*types.Action{action}...)
+	key := types.MakeKeyPair(acc.priv, []uint64{0})
+
+	err = types.SignActionWithMultiKey(action, tx, types.NewSigner(acc.chainID), []*types.KeyPair{key})
+	if err != nil {
+		return
+	}
+	rawtx, _ := rlp.EncodeToBytes(tx)
+	checked := acc.checked || acc.nonce == math.MaxUint64
+	var checkedfunc func() error
+	if checked {
+		// before
+		checkedfunc, err = acc.chekChangeProdoucer(action)
+		if err != nil {
+			return
+		}
+	}
+	hash, err = acc.api.SendRawTransaction(rawtx)
+	if err != nil {
+		return
+	}
+	if checked {
+		// after
+		err = acc.utilReceipt(hash, timeout)
+		if err != nil {
+			return
+		}
+		err = checkedfunc()
+		if err != nil {
+			return
+		}
+	}
+
+	if acc.nonce != math.MaxUint64 {
+		acc.nonce++
+	}
+	return
+}
+
+// UnvoteCadidate unvote cadidate
+func (acc *Account) UnvoteCadidate(to common.Name, value *big.Int, id uint64, gas uint64) (hash common.Hash, err error) {
+	nonce := acc.nonce
+	if nonce == math.MaxUint64 {
+		nonce, err = acc.api.AccountNonce(acc.name.String())
+		if err != nil {
+			return
+		}
+	}
+
+	action := types.NewAction(types.UnvoteCadidate, acc.name, to, nonce, id, gas, value, nil)
+	tx := types.NewTransaction(acc.feeid, big.NewInt(1e10), []*types.Action{action}...)
+	key := types.MakeKeyPair(acc.priv, []uint64{0})
+
+	err = types.SignActionWithMultiKey(action, tx, types.NewSigner(acc.chainID), []*types.KeyPair{key})
+	if err != nil {
+		return
+	}
+	rawtx, _ := rlp.EncodeToBytes(tx)
+	checked := acc.checked || acc.nonce == math.MaxUint64
+	var checkedfunc func() error
+	if checked {
+		// before
+		checkedfunc, err = acc.chekUnvoteProdoucer(action)
+		if err != nil {
+			return
+		}
+	}
+	hash, err = acc.api.SendRawTransaction(rawtx)
+	if err != nil {
+		return
+	}
+	if checked {
+		// after
+		err = acc.utilReceipt(hash, timeout)
+		if err != nil {
+			return
+		}
+		err = checkedfunc()
+		if err != nil {
+			return
+		}
+	}
+
+	if acc.nonce != math.MaxUint64 {
+		acc.nonce++
+	}
+	return
+}
+
+// UnvoteVoter remove voter
+func (acc *Account) UnvoteVoter(to common.Name, value *big.Int, id uint64, gas uint64, arg *dpos.RemoveVoter) (hash common.Hash, err error) {
+	nonce := acc.nonce
+	if nonce == math.MaxUint64 {
+		nonce, err = acc.api.AccountNonce(acc.name.String())
+		if err != nil {
+			return
+		}
+	}
+
+	payload, _ := rlp.EncodeToBytes(arg)
+	action := types.NewAction(types.RemoveVoter, acc.name, to, nonce, id, gas, value, payload)
+	tx := types.NewTransaction(acc.feeid, big.NewInt(1e10), []*types.Action{action}...)
+	key := types.MakeKeyPair(acc.priv, []uint64{0})
+
+	err = types.SignActionWithMultiKey(action, tx, types.NewSigner(acc.chainID), []*types.KeyPair{key})
+	if err != nil {
+		return
+	}
+	rawtx, _ := rlp.EncodeToBytes(tx)
+	checked := acc.checked || acc.nonce == math.MaxUint64
+	var checkedfunc func() error
+	if checked {
+		// before
+		checkedfunc, err = acc.chekRemoveVoter(action)
+		if err != nil {
+			return
+		}
+	}
+	hash, err = acc.api.SendRawTransaction(rawtx)
+	if err != nil {
+		return
+	}
+	if checked {
+		// after
+		err = acc.utilReceipt(hash, timeout)
+		if err != nil {
+			return
+		}
+		err = checkedfunc()
+		if err != nil {
+			return
+		}
+	}
+
+	if acc.nonce != math.MaxUint64 {
+		acc.nonce++
+	}
+	return
+}
+
+// KickedCadidate kicked cadidates
+func (acc *Account) KickedCadidate(to common.Name, value *big.Int, id uint64, gas uint64, arg *dpos.KickedCadidate) (hash common.Hash, err error) {
+	nonce := acc.nonce
+	if nonce == math.MaxUint64 {
+		nonce, err = acc.api.AccountNonce(acc.name.String())
+		if err != nil {
+			return
+		}
+	}
+
+	payload, _ := rlp.EncodeToBytes(arg)
+	action := types.NewAction(types.KickedCadidate, acc.name, to, nonce, id, gas, value, payload)
+	tx := types.NewTransaction(acc.feeid, big.NewInt(1e10), []*types.Action{action}...)
+	key := types.MakeKeyPair(acc.priv, []uint64{0})
+
+	err = types.SignActionWithMultiKey(action, tx, types.NewSigner(acc.chainID), []*types.KeyPair{key})
+	if err != nil {
+		return
+	}
+	rawtx, _ := rlp.EncodeToBytes(tx)
+	checked := acc.checked || acc.nonce == math.MaxUint64
+	var checkedfunc func() error
+	if checked {
+		// before
+		checkedfunc, err = acc.chekKickedCadidate(action)
+		if err != nil {
+			return
+		}
+	}
+	hash, err = acc.api.SendRawTransaction(rawtx)
+	if err != nil {
+		return
+	}
+	if checked {
+		// after
+		err = acc.utilReceipt(hash, timeout)
+		if err != nil {
+			return
+		}
+		err = checkedfunc()
+		if err != nil {
+			return
+		}
+	}
+
+	if acc.nonce != math.MaxUint64 {
+		acc.nonce++
+	}
+	return
+}
+
+// ExitTakeOver exit take over
+func (acc *Account) ExitTakeOver(to common.Name, value *big.Int, id uint64, gas uint64) (hash common.Hash, err error) {
+	nonce := acc.nonce
+	if nonce == math.MaxUint64 {
+		nonce, err = acc.api.AccountNonce(acc.name.String())
+		if err != nil {
+			return
+		}
+	}
+
+	action := types.NewAction(types.ExitTakeOver, acc.name, to, nonce, id, gas, value, nil)
+	tx := types.NewTransaction(acc.feeid, big.NewInt(1e10), []*types.Action{action}...)
+	key := types.MakeKeyPair(acc.priv, []uint64{0})
+	err = types.SignActionWithMultiKey(action, tx, types.NewSigner(acc.chainID), []*types.KeyPair{key})
+	if err != nil {
+		return
+	}
+	rawtx, _ := rlp.EncodeToBytes(tx)
+	checked := acc.checked || acc.nonce == math.MaxUint64
+	var checkedfunc func() error
+	if checked {
+		// before
+		checkedfunc, err = acc.chekKickedCadidate(action)
+		if err != nil {
+			return
+		}
+	}
+	hash, err = acc.api.SendRawTransaction(rawtx)
+	if err != nil {
+		return
+	}
+	if checked {
+		// after
+		err = acc.utilReceipt(hash, timeout)
+		if err != nil {
+			return
+		}
+		err = checkedfunc()
+		if err != nil {
+			return
+		}
+	}
+
+	if acc.nonce != math.MaxUint64 {
+		acc.nonce++
+	}
+	return
+}
diff --git a/sdk/account_test.go b/sdk/account_test.go
new file mode 100644
index 00000000..84016244
--- /dev/null
+++ b/sdk/account_test.go
@@ -0,0 +1,211 @@
+// Copyright 2018 The Fractal Team Authors
+// This file is part of the fractal project.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+package sdk
+
+import (
+	"fmt"
+	"math"
+	"math/big"
+	"testing"
+
+	"github.com/fractalplatform/fractal/accountmanager"
+	"github.com/fractalplatform/fractal/common"
+	"github.com/fractalplatform/fractal/consensus/dpos"
+	"github.com/fractalplatform/fractal/crypto"
+	"github.com/fractalplatform/fractal/params"
+	. "github.com/smartystreets/goconvey/convey"
+)
+
+var (
+	// 	tAssetName   = "testasset"
+	// 	tAssetSymbol = "tat"
+	// 	tAmount      = new(big.Int).Mul(big.NewInt(1000000), big.NewInt(1e8))
+	// 	tDecimals    = uint64(8)
+	// 	tAssetID     uint64
+	rpchost         = "http://127.0.0.1:8545"
+	systemaccount   = params.DefaultChainconfig.SysName
+	accountaccount  = params.DefaultChainconfig.AccountName
+	dposaccount     = params.DefaultChainconfig.DposName
+	systemprivkey   = "289c2857d4598e37fb9647507e47a309d6133539bf21a8b9cb6df88fd5232032"
+	systemassetname = params.DefaultChainconfig.SysToken
+	systemassetid   = uint64(1)
+	chainid         = big.NewInt(1)
+	tValue          = new(big.Int).Mul(big.NewInt(300000), big.NewInt(1e18))
+	tGas            = uint64(90000)
+)
+
+func TestAccount(t *testing.T) {
+	Convey("Account", t, func() {
+		api := NewAPI(rpchost)
+		var systempriv, _ = crypto.HexToECDSA(systemprivkey)
+		sysAcct := NewAccount(api, common.StrToName(systemaccount), systempriv, systemassetid, math.MaxUint64, true, chainid)
+		// CreateAccount
+		priv, pub := GenerateKey()
+		accountName := common.StrToName(GenerateAccountName("test", 8))
+		hash, err := sysAcct.CreateAccount(common.StrToName(accountaccount), tValue, systemassetid, tGas, &accountmanager.AccountAction{
+			AccountName: accountName,
+			PublicKey:   pub,
+		})
+		So(err, ShouldBeNil)
+		So(hash, ShouldNotBeNil)
+
+		// Transfer
+		hash, err = sysAcct.Transfer(accountName, tValue, systemassetid, tGas)
+		So(err, ShouldBeNil)
+		So(hash, ShouldNotBeNil)
+
+		// UpdateAccount
+		acct := NewAccount(api, accountName, priv, systemassetid, math.MaxUint64, true, chainid)
+		_, npub := GenerateKey()
+		hash, err = acct.UpdateAccount(common.StrToName(accountaccount), new(big.Int).Mul(tValue, big.NewInt(0)), systemassetid, tGas, &accountmanager.AccountAction{
+			AccountName: accountName,
+			PublicKey:   npub,
+		})
+		So(err, ShouldBeNil)
+		So(hash, ShouldNotBeNil)
+
+		// DestroyAccount
+	})
+}
+
+func TestAsset(t *testing.T) {
+	// Convey("types.IssueAsset", t, func() {
+	// 	api := NewAPI(rpchost)
+	// 	var systempriv, _ = crypto.HexToECDSA(systemprivkey)
+	// 	sysAcct := NewAccount(api, common.StrToName(systemaccount), systempriv, systemassetid, math.MaxUint64, true, chainid)
+	// 	priv, pub := GenerateKey()
+	// 	accountName := common.StrToName(GenerateAccountName("test", 8))
+	// 	hash, err := sysAcct.CreateAccount(common.StrToName(systemaccount), tValue, systemassetid, tGas, &accountmanager.AccountAction{
+	// 		AccountName: accountName,
+	// 		PublicKey:   pub,
+	// 	})
+	// 	So(err, ShouldBeNil)
+	// 	So(hash, ShouldNotBeNil)
+
+	// 	acct := NewAccount(api, accountName, priv, systemassetid, math.MaxUint64, true, chainid)
+	// 	assetname := common.StrToName(GenerateAccountName("asset", 8)).String()
+	// 	// IssueAsset
+	// 	hash, err = acct.IssueAsset(accountName, new(big.Int).Div(tValue, big.NewInt(10)), systemassetid, tGas, &asset.AssetObject{
+	// 		AssetName:  assetname,
+	// 		Symbol:     assetname[len(assetname)-4:],
+	// 		Amount:     new(big.Int).Mul(big.NewInt(10000000), big.NewInt(1e18)),
+	// 		Decimals:   18,
+	// 		Owner:      accountName,
+	// 		Founder:    accountName,
+	// 		AddIssue:   big.NewInt(0),
+	// 		UpperLimit: big.NewInt(0),
+	// 	})
+	// 	So(err, ShouldBeNil)
+	// 	So(hash, ShouldNotBeNil)
+
+	// 	// acct.UpdateAsset()
+	// 	// acct.IncreaseAsset()
+	// 	// acct.SetAssetOwner()
+	// 	// acct.DestroyAsset()
+	// })
+}
+
+func TestDPOS(t *testing.T) {
+	Convey("DPOS", t, func() {
+		api := NewAPI(rpchost)
+		var systempriv, _ = crypto.HexToECDSA(systemprivkey)
+		sysAcct := NewAccount(api, common.StrToName(systemaccount), systempriv, systemassetid, math.MaxUint64, true, chainid)
+		priv, pub := GenerateKey()
+		accountName := common.StrToName(GenerateAccountName("prod", 8))
+		hash, err := sysAcct.CreateAccount(common.StrToName(accountaccount), tValue, systemassetid, tGas, &accountmanager.AccountAction{
+			AccountName: accountName,
+			PublicKey:   pub,
+		})
+		So(err, ShouldBeNil)
+		So(hash, ShouldNotBeNil)
+
+		priv2, pub2 := GenerateKey()
+		accountName2 := common.StrToName(GenerateAccountName("voter", 8))
+		hash, err = sysAcct.CreateAccount(common.StrToName(accountaccount), tValue, systemassetid, tGas, &accountmanager.AccountAction{
+			AccountName: accountName2,
+			PublicKey:   pub2,
+		})
+		So(err, ShouldBeNil)
+		So(hash, ShouldNotBeNil)
+
+		// RegCadidate
+		acct := NewAccount(api, accountName, priv, systemassetid, math.MaxUint64, true, chainid)
+		acct2 := NewAccount(api, accountName2, priv2, systemassetid, math.MaxUint64, true, chainid)
+		hash, err = acct.RegCadidate(common.StrToName(dposaccount), new(big.Int).Div(tValue, big.NewInt(3)), systemassetid, tGas, &dpos.RegisterCadidate{
+			Url: fmt.Sprintf("www.%s.com", accountName.String()),
+		})
+		So(err, ShouldBeNil)
+		So(hash, ShouldNotBeNil)
+
+		// VoteCadidate
+		hash, err = acct2.VoteCadidate(common.StrToName(dposaccount), new(big.Int).Div(tValue, big.NewInt(3)), systemassetid, tGas, &dpos.VoteCadidate{
+			Cadidate: accountName.String(),
+		})
+		So(err, ShouldBeNil)
+		So(hash, ShouldNotBeNil)
+
+		// UnvoteCadidate
+		hash, err = acct2.UnvoteCadidate(common.StrToName(dposaccount), new(big.Int).Mul(tValue, big.NewInt(0)), systemassetid, tGas)
+		So(err, ShouldBeNil)
+		So(hash, ShouldNotBeNil)
+
+		// VoteCadidate
+		hash, err = acct2.VoteCadidate(common.StrToName(dposaccount), new(big.Int).Div(tValue, big.NewInt(3)), systemassetid, tGas, &dpos.VoteCadidate{
+			Cadidate: systemaccount,
+		})
+		So(err, ShouldBeNil)
+		So(hash, ShouldNotBeNil)
+
+		// ChangeCadidate
+		hash, err = acct2.ChangeCadidate(common.StrToName(dposaccount), new(big.Int).Mul(tValue, big.NewInt(0)), systemassetid, tGas, &dpos.ChangeCadidate{
+			Cadidate: accountName.String(),
+		})
+		So(err, ShouldBeNil)
+		So(hash, ShouldNotBeNil)
+
+		// UnvoteVoter
+		hash, err = acct.UnvoteVoter(common.StrToName(dposaccount), new(big.Int).Mul(tValue, big.NewInt(0)), systemassetid, tGas, &dpos.RemoveVoter{
+			Voters: []string{accountName2.String()},
+		})
+		So(err, ShouldBeNil)
+		So(hash, ShouldNotBeNil)
+
+		hash, err = sysAcct.KickedCadidate(common.StrToName(dposaccount), new(big.Int).Mul(tValue, big.NewInt(0)), systemassetid, tGas, &dpos.KickedCadidate{
+			Cadidates: []string{accountName.String()},
+		})
+		So(err, ShouldBeNil)
+		So(hash, ShouldNotBeNil)
+
+		// UnRegCadidate
+		hash, err = acct.UnRegCadidate(common.StrToName(dposaccount), new(big.Int).Mul(tValue, big.NewInt(0)), systemassetid, tGas)
+		So(err, ShouldBeNil)
+		So(hash, ShouldNotBeNil)
+	})
+}
+func TestManual(t *testing.T) {
+	Convey("Manual", t, func() {
+		api := NewAPI(rpchost)
+		var systempriv, _ = crypto.HexToECDSA(systemprivkey)
+		sysAcct := NewAccount(api, common.StrToName(systemaccount), systempriv, systemassetid, math.MaxUint64, true, chainid)
+
+		hash, err := sysAcct.KickedCadidate(common.StrToName(dposaccount), new(big.Int).Mul(tValue, big.NewInt(0)), systemassetid, tGas, &dpos.KickedCadidate{
+			Cadidates: []string{"ftcadidate1", "ftcadidate2", "ftcadidate3"},
+		})
+		So(err, ShouldBeNil)
+		So(hash, ShouldNotBeNil)
+	})
+}
diff --git a/sdk/accountck.go b/sdk/accountck.go
new file mode 100644
index 00000000..3483efb8
--- /dev/null
+++ b/sdk/accountck.go
@@ -0,0 +1,173 @@
+// Copyright 2018 The Fractal Team Authors
+// This file is part of the fractal project.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+package sdk
+
+import (
+	"fmt"
+	"time"
+
+	"github.com/fractalplatform/fractal/common"
+	"github.com/fractalplatform/fractal/types"
+)
+
+func (acc *Account) utilReceipt(hash common.Hash, timeout int64) error {
+	cnt := int64(10)
+	ticker := time.NewTicker(time.Duration(timeout / cnt))
+	defer ticker.Stop()
+	for {
+		select {
+		case <-ticker.C:
+			r, _ := acc.api.TransactionReceiptByHash(hash)
+			if r != nil && r.BlockNumber > 0 {
+				if len(r.ActionResults[0].Error) > 0 {
+					return fmt.Errorf(r.ActionResults[0].Error)
+				}
+				return nil
+			}
+			cnt--
+			if cnt == 0 {
+				return fmt.Errorf("not found %v receipt", hash.String())
+			}
+		}
+	}
+}
+
+func (acc *Account) checkCreateAccount(action *types.Action) (func() error, error) {
+	function := func() error {
+		return nil
+	}
+	return function, nil
+}
+
+func (acc *Account) checkUpdateAccount(action *types.Action) (func() error, error) {
+	function := func() error {
+		return nil
+	}
+	return function, nil
+}
+
+func (acc *Account) checkTranfer(action *types.Action) (func() error, error) {
+	// TODO
+	function := func() error {
+		return nil
+	}
+	return function, nil
+}
+
+func (acc *Account) checkIssueAsset(action *types.Action) (func() error, error) {
+	// TODO
+	function := func() error {
+		return nil
+	}
+	return function, nil
+}
+
+func (acc *Account) checkUpdateAsset(action *types.Action) (func() error, error) {
+	// TODO
+	function := func() error {
+		return nil
+	}
+	return function, nil
+}
+
+func (acc *Account) checkDestroyAsset(action *types.Action) (func() error, error) {
+	// TODO
+	function := func() error {
+		return nil
+	}
+	return function, nil
+}
+
+func (acc *Account) checkIncreaseAsset(action *types.Action) (func() error, error) {
+	// TODO
+	function := func() error {
+		return nil
+	}
+	return function, nil
+}
+
+func (acc *Account) checkSetAssetOwner(action *types.Action) (func() error, error) {
+	// TODO
+	function := func() error {
+		return nil
+	}
+	return function, nil
+}
+
+func (acc *Account) chekRegProdoucer(action *types.Action) (func() error, error) {
+	// TODO
+	function := func() error {
+		return nil
+	}
+	return function, nil
+}
+
+func (acc *Account) chekUpdateProdoucer(action *types.Action) (func() error, error) {
+	// TODO
+	function := func() error {
+		return nil
+	}
+	return function, nil
+}
+
+func (acc *Account) chekUnregProdoucer(action *types.Action) (func() error, error) {
+	// TODO
+	function := func() error {
+		return nil
+	}
+	return function, nil
+}
+
+func (acc *Account) chekVoteProdoucer(action *types.Action) (func() error, error) {
+	// TODO
+	function := func() error {
+		return nil
+	}
+	return function, nil
+}
+
+func (acc *Account) chekChangeProdoucer(action *types.Action) (func() error, error) {
+	// TODO
+	function := func() error {
+		return nil
+	}
+	return function, nil
+}
+
+func (acc *Account) chekUnvoteProdoucer(action *types.Action) (func() error, error) {
+	// TODO
+	function := func() error {
+		return nil
+	}
+	return function, nil
+}
+
+func (acc *Account) chekRemoveVoter(action *types.Action) (func() error, error) {
+	// TODO
+	function := func() error {
+		return nil
+	}
+	return function, nil
+}
+
+func (acc *Account) chekKickedCadidate(action *types.Action) (func() error, error) {
+	// TODO
+	function := func() error {
+		return nil
+	}
+	return function, nil
+}
diff --git a/wallet/keystore/errors.go b/sdk/api.go
similarity index 64%
rename from wallet/keystore/errors.go
rename to sdk/api.go
index 5872ba9f..0a8c12a2 100644
--- a/wallet/keystore/errors.go
+++ b/sdk/api.go
@@ -14,11 +14,28 @@
 // You should have received a copy of the GNU General Public License
 // along with this program. If not, see <http://www.gnu.org/licenses/>.
 
-package keystore
+package sdk
 
-import "errors"
+import (
+	"fmt"
 
-var (
-	// ErrDecrypt decrypt key error
-	ErrDecrypt = errors.New("could not decrypt key with given passphrase")
+	"github.com/fractalplatform/fractal/rpc"
 )
+
+// API rpc api
+type API struct {
+	rpchost string
+	client  *rpc.Client
+}
+
+// NewAPI create api interface
+func NewAPI(rpchost string) *API {
+	client, err := rpc.DialHTTP(rpchost)
+	if err != nil {
+		panic(fmt.Sprintf("dial http %v err %v", rpchost, err))
+	}
+	api := &API{}
+	api.rpchost = rpchost
+	api.client = client
+	return api
+}
diff --git a/sdk/api_account.go b/sdk/api_account.go
new file mode 100644
index 00000000..ca44c372
--- /dev/null
+++ b/sdk/api_account.go
@@ -0,0 +1,72 @@
+// Copyright 2018 The Fractal Team Authors
+// This file is part of the fractal project.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+package sdk
+
+import (
+	"math/big"
+
+	"github.com/fractalplatform/fractal/asset"
+)
+
+// AccountIsExist account exist
+func (api *API) AccountIsExist(name string) (bool, error) {
+	isExist := false
+	err := api.client.Call(&isExist, "account_accountIsExist", name)
+	return isExist, err
+}
+
+// AccountInfo get account by name
+func (api *API) AccountInfo(name string) (map[string]interface{}, error) {
+	account := map[string]interface{}{}
+	err := api.client.Call(account, "account_getAccountByName", name)
+	return account, err
+}
+
+// AccountCode get account code
+func (api *API) AccountCode(name string) ([]byte, error) {
+	code := []byte{}
+	err := api.client.Call(code, "account_getCode", name)
+	return code, err
+}
+
+// AccountNonce get account nonce
+func (api *API) AccountNonce(name string) (uint64, error) {
+	nonce := uint64(0)
+	err := api.client.Call(&nonce, "account_getNonce", name)
+	return nonce, err
+}
+
+// AssetInfoByName get asset info
+func (api *API) AssetInfoByName(name string) (*asset.AssetObject, error) {
+	assetInfo := &asset.AssetObject{}
+	err := api.client.Call(assetInfo, "account_getAssetInfoByName", name)
+	return assetInfo, err
+}
+
+// AssetInfoByID get asset info
+func (api *API) AssetInfoByID(id uint64) (*asset.AssetObject, error) {
+	assetInfo := &asset.AssetObject{}
+	err := api.client.Call(assetInfo, "account_getAssetInfoByID", id)
+	return assetInfo, err
+}
+
+// BalanceByAssetID get asset balance
+func (api *API) BalanceByAssetID(name string, id uint64, typeID uint64) (*big.Int, error) {
+	balance := big.NewInt(0)
+	err := api.client.Call(balance, "account_getAccountBalanceByID", name, id, typeID)
+	return balance, err
+}
diff --git a/sdk/api_account_test.go b/sdk/api_account_test.go
new file mode 100644
index 00000000..c162bc0f
--- /dev/null
+++ b/sdk/api_account_test.go
@@ -0,0 +1,80 @@
+// Copyright 2018 The Fractal Team Authors
+// This file is part of the fractal project.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+package sdk
+
+import (
+	"testing"
+
+	. "github.com/smartystreets/goconvey/convey"
+)
+
+func TestAccountIsExist(t *testing.T) {
+	Convey("account_accountIsExist", t, func() {
+		api := NewAPI(rpchost)
+		existed, err := api.AccountIsExist(systemaccount)
+		So(err, ShouldBeNil)
+		So(existed, ShouldBeTrue)
+	})
+}
+func TestAccountInfo(t *testing.T) {
+	Convey("account_getAccountByName", t, func() {
+		api := NewAPI(rpchost)
+		acct, err := api.AccountInfo(systemaccount)
+		So(err, ShouldBeNil)
+		So(acct, ShouldNotBeNil)
+	})
+}
+func TestAccountCode(t *testing.T) {
+	Convey("account_getCode", t, func() {
+		api := NewAPI(rpchost)
+		code, err := api.AccountCode(systemaccount)
+		So(err, ShouldNotBeNil)
+		So(code, ShouldBeEmpty)
+	})
+}
+func TestAccountNonce(t *testing.T) {
+	Convey("account_getNonce", t, func() {
+		api := NewAPI(rpchost)
+		nonce, err := api.AccountNonce(systemaccount)
+		So(err, ShouldBeNil)
+		So(nonce, ShouldNotBeNil)
+	})
+}
+func TestAssetInfoByName(t *testing.T) {
+	Convey("account_getAssetInfoByName", t, func() {
+		api := NewAPI(rpchost)
+		asset, err := api.AssetInfoByName(systemassetname)
+		So(err, ShouldBeNil)
+		So(asset, ShouldNotBeNil)
+	})
+}
+func TestAssetInfoByID(t *testing.T) {
+	Convey("account_getAssetInfoByID", t, func() {
+		api := NewAPI(rpchost)
+		asset, err := api.AssetInfoByID(systemassetid)
+		So(err, ShouldBeNil)
+		So(asset, ShouldNotBeNil)
+	})
+}
+func TestBalanceByAssetID(t *testing.T) {
+	Convey("account_getAccountBalanceByID", t, func() {
+		api := NewAPI(rpchost)
+		balance, err := api.BalanceByAssetID(systemaccount, systemassetid, 0)
+		So(err, ShouldBeNil)
+		So(balance, ShouldNotBeNil)
+	})
+}
diff --git a/sdk/api_dpos.go b/sdk/api_dpos.go
new file mode 100644
index 00000000..6e791f84
--- /dev/null
+++ b/sdk/api_dpos.go
@@ -0,0 +1,66 @@
+// Copyright 2018 The Fractal Team Authors
+// This file is part of the fractal project.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+package sdk
+
+// DposInfo dpos info
+func (api *API) DposInfo() (map[string]interface{}, error) {
+	info := map[string]interface{}{}
+	err := api.client.Call(&info, "dpos_info")
+	return info, err
+}
+
+// DposIrreversible dpos irreversible info
+func (api *API) DposIrreversible() (map[string]interface{}, error) {
+	info := map[string]interface{}{}
+	err := api.client.Call(&info, "dpos_irreversible")
+	return info, err
+}
+
+// DposEpcho dpos state info by height
+func (api *API) DposEpcho(height uint64) (map[string]interface{}, error) {
+	info := map[string]interface{}{}
+	err := api.client.Call(&info, "dpos_epcho", height)
+	return info, err
+}
+
+// DposLatestEpcho dpos state info by height
+func (api *API) DposLatestEpcho() (map[string]interface{}, error) {
+	info := map[string]interface{}{}
+	err := api.client.Call(&info, "dpos_latestEpcho")
+	return info, err
+}
+
+// DposValidateEpcho dpos state info
+func (api *API) DposValidateEpcho() (map[string]interface{}, error) {
+	info := map[string]interface{}{}
+	err := api.client.Call(&info, "dpos_validateEpcho")
+	return info, err
+}
+
+// DposCadidates dpos cadidate info
+func (api *API) DposCadidates() ([]map[string]interface{}, error) {
+	info := []map[string]interface{}{}
+	err := api.client.Call(&info, "dpos_cadidates")
+	return info, err
+}
+
+// DposAccount dpos account info
+func (api *API) DposAccount(name string) (map[string]interface{}, error) {
+	info := map[string]interface{}{}
+	err := api.client.Call(&info, "dpos_account", name)
+	return info, err
+}
diff --git a/sdk/api_dpos_test.go b/sdk/api_dpos_test.go
new file mode 100644
index 00000000..98b54c00
--- /dev/null
+++ b/sdk/api_dpos_test.go
@@ -0,0 +1,80 @@
+// Copyright 2018 The Fractal Team Authors
+// This file is part of the fractal project.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+package sdk
+
+import (
+	"testing"
+
+	. "github.com/smartystreets/goconvey/convey"
+)
+
+func TestDposInfo(t *testing.T) {
+	Convey("dpos_info", t, func() {
+		api := NewAPI(rpchost)
+		info, err := api.DposInfo()
+		So(err, ShouldBeNil)
+		So(info, ShouldNotBeEmpty)
+	})
+}
+func TestDposIrreversible(t *testing.T) {
+	Convey("dpos_irreversible", t, func() {
+		api := NewAPI(rpchost)
+		info, err := api.DposIrreversible()
+		So(err, ShouldBeNil)
+		So(info, ShouldNotBeEmpty)
+	})
+}
+func TestDposEpcho(t *testing.T) {
+	Convey("dpos_epcho", t, func() {
+		api := NewAPI(rpchost)
+		info, err := api.DposEpcho(0)
+		So(err, ShouldBeNil)
+		So(info, ShouldNotBeEmpty)
+	})
+}
+func TestDposLatestEpcho(t *testing.T) {
+	Convey("dpos_latestEpcho", t, func() {
+		api := NewAPI(rpchost)
+		info, err := api.DposLatestEpcho()
+		So(err, ShouldBeNil)
+		So(info, ShouldNotBeEmpty)
+	})
+}
+func TestDposValidateEpcho(t *testing.T) {
+	Convey("dpos_validateEpcho", t, func() {
+		api := NewAPI(rpchost)
+		info, err := api.DposValidateEpcho()
+		So(err, ShouldBeNil)
+		So(info, ShouldNotBeEmpty)
+	})
+}
+func TestDposCadidates(t *testing.T) {
+	Convey("dpos_cadidates", t, func() {
+		api := NewAPI(rpchost)
+		info, err := api.DposCadidates()
+		So(err, ShouldBeNil)
+		So(info, ShouldNotBeEmpty)
+	})
+}
+func TestDposAccount(t *testing.T) {
+	Convey("dpos_account", t, func() {
+		api := NewAPI(rpchost)
+		info, err := api.DposAccount(systemaccount)
+		So(err, ShouldBeNil)
+		So(info, ShouldNotBeEmpty)
+	})
+}
diff --git a/sdk/api_ft.go b/sdk/api_ft.go
new file mode 100644
index 00000000..ff2e0f28
--- /dev/null
+++ b/sdk/api_ft.go
@@ -0,0 +1,75 @@
+// Copyright 2018 The Fractal Team Authors
+// This file is part of the fractal project.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+package sdk
+
+import (
+	"math/big"
+
+	"github.com/ethereum/go-ethereum/common/hexutil"
+	"github.com/fractalplatform/fractal/common"
+	"github.com/fractalplatform/fractal/rpc"
+	"github.com/fractalplatform/fractal/types"
+)
+
+// SendRawTransaction send tx
+func (api *API) SendRawTransaction(rawTx []byte) (common.Hash, error) {
+	hash := new(common.Hash)
+	err := api.client.Call(hash, "ft_sendRawTransaction", hexutil.Bytes(rawTx))
+	return *hash, err
+}
+
+// CurrentBlock current block info
+func (api *API) CurrentBlock(fullTx bool) (map[string]interface{}, error) {
+	block := map[string]interface{}{}
+	err := api.client.Call(&block, "ft_getCurrentBlock", fullTx)
+	return block, err
+}
+
+// BlockByHash block info
+func (api *API) BlockByHash(hash common.Hash, fullTx bool) (map[string]interface{}, error) {
+	block := map[string]interface{}{}
+	err := api.client.Call(&block, "ft_getBlockByHash", hash, fullTx)
+	return block, err
+}
+
+// BlockByNumber block info
+func (api *API) BlockByNumber(number int64, fullTx bool) (map[string]interface{}, error) {
+	block := map[string]interface{}{}
+	err := api.client.Call(&block, "ft_getBlockByNumber", rpc.BlockNumber(number), fullTx)
+	return block, err
+}
+
+// TransactionByHash tx info
+func (api *API) TransactionByHash(hash common.Hash) (*types.RPCTransaction, error) {
+	tx := &types.RPCTransaction{}
+	err := api.client.Call(tx, "ft_getTransactionByHash", hash)
+	return tx, err
+}
+
+// TransactionReceiptByHash tx info
+func (api *API) TransactionReceiptByHash(hash common.Hash) (*types.RPCReceipt, error) {
+	receipt := &types.RPCReceipt{}
+	err := api.client.Call(receipt, "ft_getTransactionReceipt", hash)
+	return receipt, err
+}
+
+// GasPrice gas price
+func (api *API) GasPrice() (*big.Int, error) {
+	gasprice := big.NewInt(0)
+	err := api.client.Call(gasprice, "ft_gasPrice")
+	return gasprice, err
+}
diff --git a/sdk/api_ft_test.go b/sdk/api_ft_test.go
new file mode 100644
index 00000000..7652eed6
--- /dev/null
+++ b/sdk/api_ft_test.go
@@ -0,0 +1,82 @@
+// Copyright 2018 The Fractal Team Authors
+// This file is part of the fractal project.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+package sdk
+
+import (
+	"testing"
+
+	"github.com/fractalplatform/fractal/common"
+	. "github.com/smartystreets/goconvey/convey"
+)
+
+func TestCurrentBlock(t *testing.T) {
+	Convey("ft_getCurrentBlock", t, func() {
+		api := NewAPI(rpchost)
+		block, err := api.CurrentBlock(false)
+		So(err, ShouldBeNil)
+		So(block, ShouldNotBeNil)
+	})
+}
+
+func TestBlockByHash(t *testing.T) {
+	Convey("ft_getBlockByHash", t, func() {
+		api := NewAPI(rpchost)
+		block, err := api.CurrentBlock(false)
+		So(err, ShouldBeNil)
+		hash := common.HexToHash(block["hash"].(string))
+		block, err = api.BlockByHash(hash, false)
+		So(err, ShouldBeNil)
+		So(block, ShouldNotBeNil)
+	})
+}
+
+func TestBlockByNumber(t *testing.T) {
+	Convey("ft_getBlockByNumber", t, func() {
+		api := NewAPI(rpchost)
+		block, err := api.CurrentBlock(false)
+		So(err, ShouldBeNil)
+		block, err = api.BlockByNumber((int64(block["number"].(float64))), false)
+		So(err, ShouldBeNil)
+		So(block, ShouldNotBeNil)
+	})
+}
+func TestTransactionByHash(t *testing.T) {
+	Convey("ft_getTransactionByHash", t, func() {
+		hash := common.HexToHash("")
+		api := NewAPI(rpchost)
+		tx, err := api.TransactionByHash(hash)
+		So(err, ShouldBeNil)
+		So(tx, ShouldNotBeNil)
+	})
+}
+func TestTransactionReceiptByHash(t *testing.T) {
+	Convey("ft_getTransactionReceipt", t, func() {
+		hash := common.HexToHash("")
+		api := NewAPI(rpchost)
+		receipt, err := api.TransactionReceiptByHash(hash)
+		So(err, ShouldBeNil)
+		So(receipt, ShouldNotBeNil)
+	})
+}
+func TestGasPrice(t *testing.T) {
+	Convey("ft_gasPrice", t, func() {
+		api := NewAPI(rpchost)
+		gasprice, err := api.GasPrice()
+		So(err, ShouldBeNil)
+		So(gasprice, ShouldNotBeNil)
+	})
+}
diff --git a/sdk/api_miner.go b/sdk/api_miner.go
new file mode 100644
index 00000000..eefde0ce
--- /dev/null
+++ b/sdk/api_miner.go
@@ -0,0 +1,52 @@
+// Copyright 2018 The Fractal Team Authors
+// This file is part of the fractal project.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+package sdk
+
+// MinerStart start
+func (api *API) MinerStart() (bool, error) {
+	ret := false
+	err := api.client.Call(&ret, "miner_start")
+	return ret, err
+}
+
+// MinerStop stop
+func (api *API) MinerStop() (bool, error) {
+	ret := false
+	err := api.client.Call(&ret, "miner_stop")
+	return ret, err
+}
+
+// MinerMining mining
+func (api *API) MinerMining() (bool, error) {
+	ret := false
+	err := api.client.Call(&ret, "miner_mining")
+	return ret, err
+}
+
+// MinerSetExtra extra
+func (api *API) MinerSetExtra(extra []byte) (bool, error) {
+	ret := true
+	err := api.client.Call(&ret, "miner_setExtra", extra)
+	return ret, err
+}
+
+// MinerSetCoinbase coinbase
+func (api *API) MinerSetCoinbase(name string, privKeys []string) (bool, error) {
+	ret := true
+	err := api.client.Call(&ret, "miner_setCoinbase", name, privKeys)
+	return ret, err
+}
diff --git a/sdk/api_miner_test.go b/sdk/api_miner_test.go
new file mode 100644
index 00000000..75ee68ec
--- /dev/null
+++ b/sdk/api_miner_test.go
@@ -0,0 +1,81 @@
+// Copyright 2018 The Fractal Team Authors
+// This file is part of the fractal project.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+package sdk
+
+import (
+	"testing"
+
+	. "github.com/smartystreets/goconvey/convey"
+)
+
+func TestMinerMining(t *testing.T) {
+	Convey("miner_mining", t, func() {
+		api := NewAPI(rpchost)
+		_, err := api.MinerMining()
+		So(err, ShouldBeNil)
+	})
+}
+func TestMinerStart(t *testing.T) {
+	Convey("miner_start", t, func() {
+		api := NewAPI(rpchost)
+		mining, _ := api.MinerMining()
+		ret, err := api.MinerStart()
+		So(err, ShouldBeNil)
+		if mining {
+			So(ret, ShouldBeFalse)
+		} else {
+			So(ret, ShouldBeTrue)
+		}
+	})
+}
+func TestMinerStop(t *testing.T) {
+	Convey("miner_stop", t, func() {
+		api := NewAPI(rpchost)
+		mining, _ := api.MinerMining()
+		ret, err := api.MinerStop()
+		So(err, ShouldBeNil)
+		if mining {
+			So(ret, ShouldBeTrue)
+		} else {
+			So(ret, ShouldBeFalse)
+		}
+	})
+}
+func TestMinerSetExtra(t *testing.T) {
+	Convey("miner_setExtra", t, func() {
+		api := NewAPI(rpchost)
+		ret, err := api.MinerSetExtra([]byte("testextra"))
+		So(err, ShouldBeNil)
+		So(ret, ShouldBeTrue)
+	})
+}
+func TestMinerSetCoinbase(t *testing.T) {
+	Convey("miner_setCoinbase", t, func() {
+		api := NewAPI(rpchost)
+		ret, err := api.MinerSetCoinbase(systemaccount, []string{systemprivkey})
+		So(err, ShouldBeNil)
+		So(ret, ShouldBeTrue)
+	})
+}
+func TestMinerSetExtraTooLong(t *testing.T) {
+	Convey("miner_setExtra", t, func() {
+		api := NewAPI(rpchost)
+		ret, err := api.MinerSetExtra([]byte("testextratestextratestextratestextratestextratestextra"))
+		So(err, ShouldNotBeNil)
+		So(ret, ShouldBeTrue)
+	})
+}
diff --git a/wallet/keystore/keyjson_test.go b/sdk/utils.go
similarity index 53%
rename from wallet/keystore/keyjson_test.go
rename to sdk/utils.go
index 423e5154..a8947c28 100644
--- a/wallet/keystore/keyjson_test.go
+++ b/sdk/utils.go
@@ -14,39 +14,35 @@
 // You should have received a copy of the GNU General Public License
 // along with this program. If not, see <http://www.gnu.org/licenses/>.
 
-package keystore
+package sdk
 
 import (
 	"crypto/ecdsa"
-	crand "crypto/rand"
-	"testing"
+	"math/rand"
+	"time"
 
+	"github.com/fractalplatform/fractal/common"
 	"github.com/fractalplatform/fractal/crypto"
-	"github.com/stretchr/testify/assert"
 )
 
-func TestEncryptAndDecryptKey(t *testing.T) {
-	keyj := new(keyJSON)
-
-	privateKeyECDSA, err := ecdsa.GenerateKey(crypto.S256(), crand.Reader)
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	key := &Key{
-		Addr:       crypto.PubkeyToAddress(privateKeyECDSA.PublicKey),
-		PrivateKey: privateKeyECDSA,
-	}
-
-	err = keyj.encryptKey(key, "pwd", StandardScryptN, StandardScryptP)
-	if err != nil {
-		t.Fatal(err)
-	}
+var (
+	availableChars = "abcdefghijklmnopqrstuvwxyz0123456789"
+)
 
-	newk, err := keyj.decryptKey("pwd")
-	if err != nil {
-		t.Fatal(err)
+// GenerateAccountName generate account name
+func GenerateAccountName(namePrefix string, addStrLen int) string {
+	newRandomName := namePrefix
+	size := len(availableChars)
+	rand.Seed(time.Now().UnixNano())
+	for i := 0; i < addStrLen; i++ {
+		index := rand.Intn(10000) % size
+		newRandomName += string(availableChars[index])
 	}
+	return newRandomName
+}
 
-	assert.Equal(t, newk, key)
+// GenerateKey generate pubkey and privkey
+func GenerateKey() (*ecdsa.PrivateKey, common.PubKey) {
+	prikey, _ := crypto.GenerateKey()
+	return prikey, common.BytesToPubKey(crypto.FromECDSAPub(&prikey.PublicKey))
 }
diff --git a/state/mtp/encoding.go b/state/mtp/encoding.go
index 76aba61d..d121275b 100644
--- a/state/mtp/encoding.go
+++ b/state/mtp/encoding.go
@@ -25,14 +25,6 @@ package mtp
 // 'terminator' byte of value 0x10 which indicates whether or not the node at the key
 // contains a value. Hex key encoding is used for nodes loaded in memory because it's
 // convenient to access.
-//
-// COMPACT encoding is defined by the Ethereum Yellow Paper (it's called "hex prefix
-// encoding" there) and contains the bytes of the key and a flag. The high nibble of the
-// first byte contains the flag; the lowest bit encoding the oddness of the length and
-// the second-lowest encoding whether the node at the key is a value node. The low nibble
-// of the first byte is zero in the case of an even number of nibbles and the first nibble
-// in the case of an odd number. All remaining nibbles (now an even number) fit properly
-// into the remaining bytes. Compact encoding is used for nodes stored on disk.
 
 func hexToCompact(hex []byte) []byte {
 	terminator := byte(0)
diff --git a/state/statedb.go b/state/statedb.go
index 80a6ff88..cd604041 100644
--- a/state/statedb.go
+++ b/state/statedb.go
@@ -22,11 +22,12 @@ import (
 	"errors"
 	"fmt"
 	"sort"
+	"strings"
 	"sync"
-	"time"
 
 	"github.com/ethereum/go-ethereum/log"
 	"github.com/fractalplatform/fractal/common"
+	"github.com/fractalplatform/fractal/event"
 	"github.com/fractalplatform/fractal/rawdb"
 	trie "github.com/fractalplatform/fractal/state/mtp"
 	"github.com/fractalplatform/fractal/types"
@@ -49,6 +50,9 @@ type StateDB struct {
 	db   Database
 	trie Trie
 
+	iterator *trie.Iterator
+	triehd   *trie.SecureTrie
+
 	readSet  map[string][]byte   // save old/unmodified data
 	writeSet map[string][]byte   // last modify data
 	dirtySet map[string]struct{} // writeSet which key is modified
@@ -90,6 +94,8 @@ func New(root common.Hash, db Database) (*StateDB, error) {
 	return &StateDB{
 		db:         db,
 		trie:       tr,
+		iterator:   nil,
+		triehd:     nil,
 		readSet:    make(map[string][]byte),
 		writeSet:   make(map[string][]byte),
 		dirtySet:   make(map[string]struct{}),
@@ -117,6 +123,8 @@ func (s *StateDB) Reset(root common.Hash) error {
 	}
 
 	s.trie = tr
+	s.iterator = nil
+	s.triehd = nil
 	s.readSet = make(map[string][]byte)
 	s.writeSet = make(map[string][]byte)
 	s.dirtySet = make(map[string]struct{})
@@ -279,6 +287,8 @@ func (s *StateDB) Copy() *StateDB {
 	state := &StateDB{
 		db:        s.db,
 		trie:      s.trie,
+		iterator:  nil,
+		triehd:    nil,
 		readSet:   make(map[string][]byte, len(s.writeSet)),
 		writeSet:  make(map[string][]byte, len(s.writeSet)),
 		dirtySet:  make(map[string]struct{}, len(s.dirtySet)),
@@ -482,131 +492,184 @@ func TraceNew(blockHash common.Hash, cache Database) (*StateDB, error) {
 	return stateDb, nil
 }
 
-func SnapShotblk(db fdb.Database, Ticktime, snapshotTime uint64) { //  snapshotTime uint : second
+const second = 1000000000
 
-	var curSnapshotTime uint64
+type SnapshotSt struct {
+	db           fdb.Database
+	tickTime     uint64
+	snapshotTime uint64
+	intervalTime uint64
+	stop         chan struct{}
+}
+
+func NewSnapshot(db fdb.Database, sptime uint64) *SnapshotSt {
+	snapshot := &SnapshotSt{
+		db:           db,
+		snapshotTime: sptime,
+		stop:         make(chan struct{}),
+		intervalTime: (sptime * second),
+	}
+
+	return snapshot
+}
+
+func (sn *SnapshotSt) Start() {
+	log.Info("Snapshot start", "snapshot interval=", sn.snapshotTime)
+	go sn.SnapShotblk()
+}
+
+func (sn *SnapshotSt) Stop() {
+	close(sn.stop)
+	log.Info("Snapshot stopped")
+}
+
+func (sn *SnapshotSt) checkInterrupt() bool {
+	select {
+	case <-sn.stop:
+		return true
+	default:
+		return false
+	}
+}
+
+func (sn *SnapshotSt) getBlcok(blockNum uint64) (uint64, *types.Header) {
+	if sn.checkInterrupt() {
+		return 0, nil
+	}
+	hash := rawdb.ReadCanonicalHash(sn.db, blockNum)
+	head := rawdb.ReadHeader(sn.db, hash, blockNum)
+	time := head.Time.Uint64()
+	return time, head
+}
+
+func (sn *SnapshotSt) getlastBlcok() (uint64, uint64) {
+	if sn.checkInterrupt() {
+		return 0, 0
+	}
+	hash := rawdb.ReadHeadBlockHash(sn.db)
+	number := rawdb.ReadHeaderNumber(sn.db, hash)
+	head := rawdb.ReadHeader(sn.db, hash, *number)
+	time := head.Time.Uint64()
+	return time, *number
+}
+
+func (sn *SnapshotSt) writeSnapshot(snapshottime, prevsnptime, number uint64, root common.Hash) error {
+	if sn.checkInterrupt() {
+		return fmt.Errorf("interrupt")
+	}
+
+	snapshotmsg := types.SnapshotMsg{
+		Time:   prevsnptime,
+		Number: number,
+		Root:   root,
+	}
+
+	batch := sn.db.NewBatch()
+	rawdb.WriteBlockSnapshotTime(batch, snapshottime, snapshotmsg)
+	rawdb.WriteBlockSnapshotLast(batch, snapshottime)
+	if err := batch.Write(); err != nil {
+		return err
+	}
+	return nil
+}
+
+func (sn *SnapshotSt) lookupBlock(blockNum, prevBlockTime, lastBlockTime, lastBlockNum uint64) (uint64, *types.Header) {
+	var nextHead *types.Header
+	var nextTimeHour, nextTime uint64
+	prevTimeHour := (prevBlockTime / sn.intervalTime) * sn.intervalTime
+
+	for {
+		nextTime, nextHead = sn.getBlcok(blockNum)
+		if nextHead == nil {
+			return 0, nil
+		}
+
+		nextTimeHour = (nextTime / sn.intervalTime) * sn.intervalTime
+		if prevTimeHour == nextTimeHour {
+			blockNum = blockNum + 1
+			if blockNum < lastBlockNum {
+				continue
+			} else {
+				return 0, nil
+			}
+		} else {
+			if lastBlockTime-nextTime >= sn.intervalTime {
+				break
+			} else {
+				return 0, nil
+			}
+		}
+	}
+	return nextTimeHour, nextHead
+}
+
+func (sn *SnapshotSt) snapshotRecord(block *types.Block) bool {
 	var blockNum uint64
-	var snapshotInfo types.SnapshotMsg
+	var curSnapshotTime uint64
+	var prevTime uint64
+	var head *types.Header
 
-	var prevHash, nextHash common.Hash
-	var prevTimeHour, nextTimeHour uint64
-	log.Info("Start snapshot", "tick=", Ticktime, "interval=", snapshotTime)
+	snapshotTimeLast := rawdb.ReadSnapshotLast(sn.db)
+	if len(snapshotTimeLast) == 0 {
+		blockNum = 0
+		prevTime, head = sn.getBlcok(blockNum)
+		if head == nil {
+			return false
+		}
+		curSnapshotTime = (prevTime / sn.intervalTime) * sn.intervalTime
+	} else {
+		curSnapshotTime = binary.BigEndian.Uint64(snapshotTimeLast)
+		snapshotInfo := rawdb.ReadSnapshotTime(sn.db, curSnapshotTime)
+		blockNum = snapshotInfo.Number
+		prevTime, head = sn.getBlcok(blockNum)
+		if head == nil {
+			return false
+		}
+	}
 
-	futureTimer := time.NewTicker(time.Duration(Ticktime) * time.Second)
-	defer futureTimer.Stop()
+	curBlockTime, lastBlockNum := block.Head.Time.Uint64(), block.Head.Number.Uint64()
+	if blockNum >= lastBlockNum {
+		return false
+	}
+
+	if curBlockTime-curSnapshotTime > 2*sn.intervalTime {
+		blockNum = blockNum + 1
+		nextTimeHour, nextHead := sn.lookupBlock(blockNum, prevTime, curBlockTime, lastBlockNum)
+		if nextHead != nil {
+			err := sn.writeSnapshot(nextTimeHour, curSnapshotTime, nextHead.Number.Uint64(), nextHead.Root)
+			if err != nil {
+				log.Error("Failed to write snapshot to disk", "err", err)
+			} else {
+				log.Debug("Sanpshot time", "time", nextTimeHour, "number", nextHead.Number.Uint64(), "hash", nextHead.Root.String())
+			}
+		} else {
+			return false
+		}
+	}
+
+	return false
+}
+
+const (
+	// chainHeadChanSize is the size of channel listening to ChainHeadEvent.
+	chainHeadChanSize = 10
+)
+
+func (sn *SnapshotSt) SnapShotblk() {
+	chainHeadCh := make(chan *event.Event, chainHeadChanSize)
+	chainHeadSub := event.Subscribe(nil, chainHeadCh, event.ChainHeadEv, &types.Block{})
+	defer chainHeadSub.Unsubscribe()
 
 	for {
 		select {
-		case <-futureTimer.C:
-			for {
-				snapshotTimeLast := rawdb.ReadSnapshotLast(db)
-				if len(snapshotTimeLast) == 0 {
-					blockNum = 0
-					prevHash = rawdb.ReadCanonicalHash(db, blockNum)
-					prevHead := rawdb.ReadHeader(db, prevHash, blockNum)
-					prevTime := prevHead.Time.Uint64()
-					curSnapshotTime = (prevTime / (snapshotTime * 1000000000)) * (snapshotTime * 1000000000)
-
-					curBlockHash := rawdb.ReadHeadBlockHash(db)
-					number := rawdb.ReadHeaderNumber(db, curBlockHash)
-					curBlockHeader := rawdb.ReadHeader(db, curBlockHash, *number)
-					curBlockTime := curBlockHeader.Time.Uint64()
-
-					if curBlockTime-curSnapshotTime > 2*(snapshotTime*1000000000) {
-						for {
-							blockNum = blockNum + 1
-
-							nextHash = rawdb.ReadCanonicalHash(db, blockNum)
-							nextHead := rawdb.ReadHeader(db, nextHash, blockNum)
-
-							prevTimeHour = (prevTime / (snapshotTime * 1000000000)) * (snapshotTime * 1000000000)
-							nextTime := nextHead.Time.Uint64()
-							nextTimeHour = (nextTime / (snapshotTime * 1000000000)) * (snapshotTime * 1000000000)
-
-							if prevTimeHour == nextTimeHour {
-								prevTime = nextTime
-								continue
-							} else {
-								if curBlockTime-nextTimeHour < (snapshotTime*1000000000) || curBlockTime-nextTime < (snapshotTime*1000000000) {
-									break
-								}
-
-								snapshotInfo.Time = 0
-								snapshotInfo.Number = nextHead.Number.Uint64()
-								snapshotInfo.Root = nextHead.Root
-
-								batch := db.NewBatch()
-								rawdb.WriteBlockSnapshotTime(batch, nextTimeHour, snapshotInfo)
-								rawdb.WriteBlockSnapshotLast(batch, nextTimeHour)
-								if err := batch.Write(); err != nil {
-									log.Error("Failed to write snapshot to disk", "err", err)
-								}
-								log.Debug("Sanpshot moment", "time=", nextTimeHour)
-								break
-							}
-						}
-
-					}
-				} else {
-					curSnapshotTime = binary.BigEndian.Uint64(snapshotTimeLast)
-					snapshotInfo := rawdb.ReadSnapshotTime(db, curSnapshotTime)
-					blockNum = snapshotInfo.Number
-
-					curBlockHash := rawdb.ReadHeadBlockHash(db)
-					number := rawdb.ReadHeaderNumber(db, curBlockHash)
-					curBlockHeader := rawdb.ReadHeader(db, curBlockHash, *number)
-					curBlockTime := curBlockHeader.Time.Uint64()
-
-					if curBlockTime-curSnapshotTime > 2*(snapshotTime*1000000000) {
-						blockNum = blockNum + 1
-
-						prevHash = rawdb.ReadCanonicalHash(db, blockNum)
-						prevHead := rawdb.ReadHeader(db, prevHash, blockNum)
-						prevTime := prevHead.Time.Uint64()
-
-						for {
-							blockNum = blockNum + 1
-
-							nextHash = rawdb.ReadCanonicalHash(db, blockNum)
-							nextHead := rawdb.ReadHeader(db, nextHash, blockNum)
-
-							prevTimeHour = (prevTime / (snapshotTime * 1000000000)) * (snapshotTime * 1000000000)
-							nextTime := nextHead.Time.Uint64()
-							nextTimeHour = (nextTime / (snapshotTime * 1000000000)) * (snapshotTime * 1000000000)
-
-							if prevTimeHour == nextTimeHour {
-								prevTime = nextTime
-								continue
-							} else {
-								if curBlockTime-nextTimeHour < (snapshotTime * 1000000000) {
-									break
-								}
-
-								snapshotInfo.Time = curSnapshotTime
-								snapshotInfo.Number = nextHead.Number.Uint64()
-								snapshotInfo.Root = nextHead.Root
-								batch := db.NewBatch()
-								rawdb.WriteBlockSnapshotTime(batch, nextTimeHour, *snapshotInfo)
-								rawdb.WriteBlockSnapshotLast(batch, nextTimeHour)
-								if err := batch.Write(); err != nil {
-									log.Error("Failed to write snapshot to disk", "err", err)
-								}
-								log.Debug("Sanpshot moment", "time=", nextTimeHour)
-								break
-							}
-
-						}
-
-					}
-
-					if curBlockTime-nextTimeHour > 2*(snapshotTime*1000000000) {
-						continue
-					} else {
-						break
-					}
-
-				}
+		case ev := <-chainHeadCh:
+			// Handle ChainHeadEvent
+			if sn.checkInterrupt() {
+				return
 			}
+
+			blk := ev.Data.(*types.Block)
+			sn.snapshotRecord(blk)
 		}
 	}
 }
@@ -658,3 +721,75 @@ func (s *StateDB) GetSnapshotPrev(time uint64) (uint64, error) {
 	}
 	return snapshotInfo.Time, nil
 }
+
+func (s *StateDB) StartGetAccountInfo(time uint64) error {
+	var err error
+	if time == 0 {
+		return fmt.Errorf("Not snapshot info")
+	}
+
+	// optKey := acctDataPrefix + linkSymbol + account + linkSymbol + key
+	db := s.db.GetDB()
+	snapshotInfo := rawdb.ReadSnapshotTime(db, time)
+	if snapshotInfo == nil {
+		return fmt.Errorf("Not snapshot info")
+	}
+
+	triedb := trie.NewDatabase(db)
+	s.triehd, err = trie.NewSecure(snapshotInfo.Root, triedb, 1)
+	if err != nil {
+		return err
+	}
+
+	s.iterator = trie.NewIterator(s.triehd.NodeIterator(nil))
+	return nil
+
+}
+
+func (s *StateDB) LookupAccountInfo() ([]types.AccountInfo, bool) {
+	var endFlag bool
+	var count uint64 = 1000
+	var accountInfo []types.AccountInfo
+
+	if s.iterator == nil {
+		return nil, false
+	}
+
+	for !endFlag {
+		flag := s.iterator.Next()
+		if flag == false {
+			return accountInfo, false
+		}
+		acckey := parseAcckey(string(s.triehd.GetKey(s.iterator.Key)))
+		if len(acckey) == 0 {
+			continue
+		}
+		count = count - 1
+		accountInfo = append(accountInfo, types.AccountInfo{
+			Name:  acckey[0],
+			Key:   acckey[1],
+			Value: s.iterator.Value})
+
+		if count == 0 {
+			endFlag = true
+		}
+
+	}
+	return accountInfo, true
+
+}
+
+func (s *StateDB) StopGetAccountInfo() error {
+	s.iterator = nil
+	s.triehd = nil
+	return nil
+}
+
+func parseAcckey(s string) []string {
+	if !strings.HasPrefix(s, acctDataPrefix+linkSymbol) {
+		return nil
+	}
+	tps := strings.TrimPrefix(s, acctDataPrefix+linkSymbol)
+	acckey := strings.SplitN(tps, linkSymbol, 2)
+	return acckey
+}
diff --git a/state/statedb_test.go b/state/statedb_test.go
index 34b28fb1..9e629791 100644
--- a/state/statedb_test.go
+++ b/state/statedb_test.go
@@ -213,6 +213,10 @@ func TestSnapshot(t *testing.T) {
 		Time:       big.NewInt(1548582552502000000),
 	}
 
+	block := &types.Block{
+		Head: head,
+	}
+
 	hash := head.Hash()
 
 	root1, err := state.Commit(batch, hash, 0)
@@ -227,9 +231,12 @@ func TestSnapshot(t *testing.T) {
 	rawdb.WriteHeader(batch, head)
 	rawdb.WriteHeadBlockHash(batch, hash)
 	rawdb.WriteCanonicalHash(batch, hash, 0)
+	// rawdb.WriteBlock(batch, block)
 	batch.Write()
 
-	go SnapShotblk(db, 3, 10)
+	snapshot := NewSnapshot(db, 10)
+
+	snapshot.snapshotRecord(block)
 
 	for i := 1; i < 10; i++ {
 
@@ -243,6 +250,10 @@ func TestSnapshot(t *testing.T) {
 		head.Number = big.NewInt(int64(i))
 		head.Time = big.NewInt(1548582552502000000 + int64(i*5000000000))
 
+		block := &types.Block{
+			Head: head,
+		}
+
 		hash = head.Hash()
 
 		root, err = state.Commit(batch, hash, 0)
@@ -259,9 +270,9 @@ func TestSnapshot(t *testing.T) {
 		rawdb.WriteHeadBlockHash(batch, hash)
 		rawdb.WriteCanonicalHash(batch, hash, uint64(i))
 		batch.Write()
-	}
 
-	time.Sleep(time.Duration(10) * time.Second)
+		snapshot.snapshotRecord(block)
+	}
 
 	time, err := state.GetSnapshotLast()
 	pretime, _ := state.GetSnapshotPrev(time)
@@ -275,4 +286,52 @@ func TestSnapshot(t *testing.T) {
 	if bytes.Equal(value2, []byte(strconv.Itoa(100*4))) == false {
 		t.Error("Test snapshot failed")
 	}
+
+	//
+	err = state.StartGetAccountInfo(time)
+	if err != nil {
+		t.Error("Test snapshot get account failed")
+	}
+
+	var flag bool = true
+	var accountInfo []types.AccountInfo
+	for flag {
+		accountInfo, flag = state.LookupAccountInfo()
+	}
+
+	if bytes.Equal(accountInfo[0].Value, []byte(strconv.Itoa(100*6))) == false {
+		t.Error("Test snapshot get account failed")
+	}
+
+	err = state.StopGetAccountInfo()
+	if err != nil {
+		t.Error("Test snapshot get account failed")
+	}
+
+	err = state.StartGetAccountInfo(time)
+	if err != nil {
+		t.Error("Test snapshot get account failed")
+	}
+
+	//
+	err = state.StartGetAccountInfo(pretime)
+	if err != nil {
+		t.Error("Test snapshot get account failed")
+	}
+
+	flag = true
+	accountInfo = accountInfo[:0]
+	for flag {
+		accountInfo, flag = state.LookupAccountInfo()
+	}
+
+	if bytes.Equal(accountInfo[0].Value, []byte(strconv.Itoa(100*4))) == false {
+		t.Error("Test snapshot get account failed")
+	}
+
+	err = state.StopGetAccountInfo()
+	if err != nil {
+		t.Error("Test snapshot get account failed")
+	}
+
 }
diff --git a/test/common/dpos.go b/test/common/dpos.go
index c215ebb3..f3a34b37 100644
--- a/test/common/dpos.go
+++ b/test/common/dpos.go
@@ -66,7 +66,8 @@ func (acc *Account) CreateAccount(to common.Name, value *big.Int, id uint64, gas
 	}
 
 	tx := types.NewTransaction(acc.feeid, big.NewInt(1e10), []*types.Action{action}...)
-	if err := types.SignAction(action, tx, signer, acc.priv); err != nil {
+	key := types.MakeKeyPair(acc.priv, []uint64{0})
+	if err := types.SignActionWithMultiKey(action, tx, signer, []*types.KeyPair{key}); err != nil {
 		panic(err)
 	}
 	rawtx, err := rlp.EncodeToBytes(tx)
@@ -87,7 +88,8 @@ func (acc *Account) Transfer(to common.Name, value *big.Int, id uint64, gas uint
 	}
 
 	tx := types.NewTransaction(acc.feeid, big.NewInt(1e10), []*types.Action{action}...)
-	if err := types.SignAction(action, tx, signer, acc.priv); err != nil {
+	key := types.MakeKeyPair(acc.priv, []uint64{0})
+	if err := types.SignActionWithMultiKey(action, tx, signer, []*types.KeyPair{key}); err != nil {
 		panic(err)
 	}
 	rawtx, err := rlp.EncodeToBytes(tx)
@@ -97,9 +99,9 @@ func (acc *Account) Transfer(to common.Name, value *big.Int, id uint64, gas uint
 	return rawtx
 }
 
-// RegProducer
-func (acc *Account) RegProducer(to common.Name, value *big.Int, id uint64, gas uint64, url string, state *big.Int) []byte {
-	arg := &args.RegisterProducer{
+// RegCadidate
+func (acc *Account) RegCadidate(to common.Name, value *big.Int, id uint64, gas uint64, url string, state *big.Int) []byte {
+	arg := &args.RegisterCadidate{
 		Url:   url,
 		Stake: state,
 	}
@@ -110,13 +112,14 @@ func (acc *Account) RegProducer(to common.Name, value *big.Int, id uint64, gas u
 	if acc.getnonce != nil {
 		acc.nonce = acc.getnonce(acc.name)
 	}
-	action := types.NewAction(types.RegProducer, acc.name, to, acc.nonce, id, gas, value, payload)
+	action := types.NewAction(types.RegCadidate, acc.name, to, acc.nonce, id, gas, value, payload)
 	if acc.getnonce == nil {
 		acc.nonce++
 	}
 
 	tx := types.NewTransaction(acc.feeid, big.NewInt(1e10), []*types.Action{action}...)
-	if err := types.SignAction(action, tx, signer, acc.priv); err != nil {
+	key := types.MakeKeyPair(acc.priv, []uint64{0})
+	if err := types.SignActionWithMultiKey(action, tx, signer, []*types.KeyPair{key}); err != nil {
 		panic(err)
 	}
 	rawtx, err := rlp.EncodeToBytes(tx)
@@ -126,9 +129,9 @@ func (acc *Account) RegProducer(to common.Name, value *big.Int, id uint64, gas u
 	return rawtx
 }
 
-// UpdateProducer
-func (acc *Account) UpdateProducer(to common.Name, value *big.Int, id uint64, gas uint64, url string, state *big.Int) []byte {
-	arg := &args.UpdateProducer{
+// UpdateCadidate
+func (acc *Account) UpdateCadidate(to common.Name, value *big.Int, id uint64, gas uint64, url string, state *big.Int) []byte {
+	arg := &args.UpdateCadidate{
 		Url:   url,
 		Stake: state,
 	}
@@ -139,13 +142,14 @@ func (acc *Account) UpdateProducer(to common.Name, value *big.Int, id uint64, ga
 	if acc.getnonce != nil {
 		acc.nonce = acc.getnonce(acc.name)
 	}
-	action := types.NewAction(types.UpdateProducer, acc.name, to, acc.nonce, id, gas, value, payload)
+	action := types.NewAction(types.UpdateCadidate, acc.name, to, acc.nonce, id, gas, value, payload)
 	if acc.getnonce == nil {
 		acc.nonce++
 	}
 
 	tx := types.NewTransaction(acc.feeid, big.NewInt(1e10), []*types.Action{action}...)
-	if err := types.SignAction(action, tx, signer, acc.priv); err != nil {
+	key := types.MakeKeyPair(acc.priv, []uint64{0})
+	if err := types.SignActionWithMultiKey(action, tx, signer, []*types.KeyPair{key}); err != nil {
 		panic(err)
 	}
 	rawtx, err := rlp.EncodeToBytes(tx)
@@ -155,18 +159,20 @@ func (acc *Account) UpdateProducer(to common.Name, value *big.Int, id uint64, ga
 	return rawtx
 }
 
-// UnRegProducer
-func (acc *Account) UnRegProducer(to common.Name, value *big.Int, id uint64, gas uint64) []byte {
+// UnRegCadidate
+func (acc *Account) UnRegCadidate(to common.Name, value *big.Int, id uint64, gas uint64) []byte {
 	if acc.getnonce != nil {
 		acc.nonce = acc.getnonce(acc.name)
 	}
-	action := types.NewAction(types.UnregProducer, acc.name, to, acc.nonce, id, gas, value, nil)
+	action := types.NewAction(types.UnregCadidate, acc.name, to, acc.nonce, id, gas, value, nil)
 	if acc.getnonce == nil {
 		acc.nonce++
 	}
 
 	tx := types.NewTransaction(acc.feeid, big.NewInt(1e10), []*types.Action{action}...)
-	if err := types.SignAction(action, tx, signer, acc.priv); err != nil {
+	key := types.MakeKeyPair(acc.priv, []uint64{0})
+
+	if err := types.SignActionWithMultiKey(action, tx, signer, []*types.KeyPair{key}); err != nil {
 		panic(err)
 	}
 	rawtx, err := rlp.EncodeToBytes(tx)
@@ -176,10 +182,10 @@ func (acc *Account) UnRegProducer(to common.Name, value *big.Int, id uint64, gas
 	return rawtx
 }
 
-// VoteProducer
-func (acc *Account) VoteProducer(to common.Name, value *big.Int, id uint64, gas uint64, producer string, state *big.Int) []byte {
-	arg := &args.VoteProducer{
-		Producer: producer,
+// VoteCadidate
+func (acc *Account) VoteCadidate(to common.Name, value *big.Int, id uint64, gas uint64, cadidate string, state *big.Int) []byte {
+	arg := &args.VoteCadidate{
+		Cadidate: cadidate,
 		Stake:    state,
 	}
 	payload, err := rlp.EncodeToBytes(arg)
@@ -189,13 +195,15 @@ func (acc *Account) VoteProducer(to common.Name, value *big.Int, id uint64, gas
 	if acc.getnonce != nil {
 		acc.nonce = acc.getnonce(acc.name)
 	}
-	action := types.NewAction(types.VoteProducer, acc.name, to, acc.nonce, id, gas, value, payload)
+	action := types.NewAction(types.VoteCadidate, acc.name, to, acc.nonce, id, gas, value, payload)
 	if acc.getnonce == nil {
 		acc.nonce++
 	}
 
 	tx := types.NewTransaction(acc.feeid, big.NewInt(1e10), []*types.Action{action}...)
-	if err := types.SignAction(action, tx, signer, acc.priv); err != nil {
+	key := types.MakeKeyPair(acc.priv, []uint64{0})
+
+	if err := types.SignActionWithMultiKey(action, tx, signer, []*types.KeyPair{key}); err != nil {
 		panic(err)
 	}
 	rawtx, err := rlp.EncodeToBytes(tx)
@@ -205,10 +213,10 @@ func (acc *Account) VoteProducer(to common.Name, value *big.Int, id uint64, gas
 	return rawtx
 }
 
-// ChangeProducer
-func (acc *Account) ChangeProducer(to common.Name, value *big.Int, id uint64, gas uint64, producer string) []byte {
-	arg := &args.ChangeProducer{
-		Producer: producer,
+// ChangeCadidate
+func (acc *Account) ChangeCadidate(to common.Name, value *big.Int, id uint64, gas uint64, cadidate string) []byte {
+	arg := &args.ChangeCadidate{
+		Cadidate: cadidate,
 	}
 	payload, err := rlp.EncodeToBytes(arg)
 	if err != nil {
@@ -217,33 +225,15 @@ func (acc *Account) ChangeProducer(to common.Name, value *big.Int, id uint64, ga
 	if acc.getnonce != nil {
 		acc.nonce = acc.getnonce(acc.name)
 	}
-	action := types.NewAction(types.ChangeProducer, acc.name, to, acc.nonce, id, gas, value, payload)
+	action := types.NewAction(types.ChangeCadidate, acc.name, to, acc.nonce, id, gas, value, payload)
 	if acc.getnonce == nil {
 		acc.nonce++
 	}
 
 	tx := types.NewTransaction(acc.feeid, big.NewInt(1e10), []*types.Action{action}...)
-	if err := types.SignAction(action, tx, signer, acc.priv); err != nil {
-		panic(err)
-	}
-	rawtx, err := rlp.EncodeToBytes(tx)
-	if err != nil {
-		panic(err)
-	}
-	return rawtx
-}
-
-func (acc *Account) UnvoteProducer(to common.Name, value *big.Int, id uint64, gas uint64) []byte {
-	if acc.getnonce != nil {
-		acc.nonce = acc.getnonce(acc.name)
-	}
-	action := types.NewAction(types.UnvoteProducer, acc.name, to, acc.nonce, id, gas, value, nil)
-	if acc.getnonce == nil {
-		acc.nonce++
-	}
+	key := types.MakeKeyPair(acc.priv, []uint64{0})
 
-	tx := types.NewTransaction(acc.feeid, big.NewInt(1e10), []*types.Action{action}...)
-	if err := types.SignAction(action, tx, signer, acc.priv); err != nil {
+	if err := types.SignActionWithMultiKey(action, tx, signer, []*types.KeyPair{key}); err != nil {
 		panic(err)
 	}
 	rawtx, err := rlp.EncodeToBytes(tx)
@@ -253,25 +243,19 @@ func (acc *Account) UnvoteProducer(to common.Name, value *big.Int, id uint64, ga
 	return rawtx
 }
 
-// UnvoteVoter
-func (acc *Account) UnvoteVoter(to common.Name, value *big.Int, id uint64, gas uint64, voter string) []byte {
-	arg := &args.RemoveVoter{
-		Voter: voter,
-	}
-	payload, err := rlp.EncodeToBytes(arg)
-	if err != nil {
-		panic(err)
-	}
+func (acc *Account) UnvoteCadidate(to common.Name, value *big.Int, id uint64, gas uint64) []byte {
 	if acc.getnonce != nil {
 		acc.nonce = acc.getnonce(acc.name)
 	}
-	action := types.NewAction(types.RemoveVoter, acc.name, to, acc.nonce, id, gas, value, payload)
+	action := types.NewAction(types.UnvoteCadidate, acc.name, to, acc.nonce, id, gas, value, nil)
 	if acc.getnonce == nil {
 		acc.nonce++
 	}
 
 	tx := types.NewTransaction(acc.feeid, big.NewInt(1e10), []*types.Action{action}...)
-	if err := types.SignAction(action, tx, signer, acc.priv); err != nil {
+	key := types.MakeKeyPair(acc.priv, []uint64{0})
+
+	if err := types.SignActionWithMultiKey(action, tx, signer, []*types.KeyPair{key}); err != nil {
 		panic(err)
 	}
 	rawtx, err := rlp.EncodeToBytes(tx)
diff --git a/test/common/utils.go b/test/common/utils.go
index ccb1c992..7f45e662 100644
--- a/test/common/utils.go
+++ b/test/common/utils.go
@@ -31,6 +31,7 @@ import (
 	"github.com/fractalplatform/fractal/asset"
 	"github.com/fractalplatform/fractal/common"
 	"github.com/fractalplatform/fractal/rpc"
+	"github.com/fractalplatform/fractal/types"
 	jww "github.com/spf13/jwalterweatherman"
 )
 
@@ -86,7 +87,7 @@ func GetNonce(accountname common.Name) (uint64, error) {
 // GetAccountBalanceByID get balance by address ,assetID and number.
 func GetAccountBalanceByID(accountName common.Name, assetID uint64) (*big.Int, error) {
 	balance := big.NewInt(0)
-	err := ClientCall("account_getAccountBalanceByID", balance, accountName, assetID)
+	err := ClientCall("account_getAccountBalanceByID", balance, accountName, assetID, 1)
 	return balance, err
 }
 
@@ -130,6 +131,12 @@ func GetDposAccount(name common.Name) (map[string]interface{}, error) {
 	return fields, err
 }
 
+func GetBlockAndResult(blockNr rpc.BlockNumber) (*types.BlockAndResult, error) {
+	result := &types.BlockAndResult{}
+	err := ClientCall("ft_getBlockAndResultByNumber", result, blockNr)
+	return result, err
+}
+
 // defaultDataDir is the default data directory to use for the databases and other
 // persistence requirements.
 func defaultDataDir() string {
diff --git a/test/contract/MultiAsset/MultiAsset.abi b/test/contract/MultiAsset/MultiAsset.abi
index b50960a3..6f81e3de 100644
--- a/test/contract/MultiAsset/MultiAsset.abi
+++ b/test/contract/MultiAsset/MultiAsset.abi
@@ -1 +1 @@
-[{"constant":false,"inputs":[{"name":"desc","type":"string"}],"name":"reg","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"t","type":"uint256"},{"name":"time","type":"uint256"}],"name":"getSnapshotTime","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"to","type":"address"},{"name":"assetId","type":"address"}],"name":"getBalanceEx","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"assetId","type":"uint256"},{"name":"time","type":"uint256"}],"name":"getAssetAmount","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"to","type":"address"},{"name":"assetId","type":"address"},{"name":"value","type":"uint256"}],"name":"transAsset","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[{"name":"newOwner","type":"address"},{"name":"assetId","type":"address"}],"name":"changeOwner","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"to","type":"address"},{"name":"assetId","type":"uint256"},{"name":"time","type":"uint256"}],"name":"getSnapBalance","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"assetId","type":"address"},{"name":"value","type":"uint256"}],"name":"add","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"payable":true,"stateMutability":"payable","type":"fallback"}]
+[{"constant":false,"inputs":[{"name":"desc","type":"string"}],"name":"reg","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":true,"inputs":[{"name":"a","type":"uint256"}],"name":"balances","outputs":[{"name":"balance","type":"uint256"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":false,"inputs":[{"name":"newOwner","type":"address"},{"name":"assetId","type":"uint256"}],"name":"changeOwner","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"to","type":"address"},{"name":"assetId","type":"uint256"},{"name":"value","type":"uint256"}],"name":"transAsset","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[{"name":"t","type":"uint256"},{"name":"time","type":"uint256"}],"name":"getSnapshotTime","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"to","type":"address"},{"name":"assetId","type":"uint256"}],"name":"getBalanceEx","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"assetId","type":"uint256"},{"name":"value","type":"uint256"}],"name":"setdestroyasset","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"assetId","type":"uint256"},{"name":"to","type":"address"},{"name":"value","type":"uint256"}],"name":"add","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"user","type":"address"},{"name":"t","type":"uint256"}],"name":"getdg","outputs":[{"name":"a","type":"uint256"},{"name":"b","type":"uint256"},{"name":"c","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"to","type":"address"},{"name":"assetId","type":"uint256"},{"name":"time","type":"uint256"},{"name":"typeId","type":"uint256"}],"name":"getSnapBalance","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"assetId","type":"uint256"},{"name":"time","type":"uint256"}],"name":"getAssetAmount","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"inputs":[],"payable":true,"stateMutability":"payable","type":"constructor"}]
\ No newline at end of file
diff --git a/test/contract/MultiAsset/MultiAsset.bin b/test/contract/MultiAsset/MultiAsset.bin
index a1dc2032..b1c22269 100644
--- a/test/contract/MultiAsset/MultiAsset.bin
+++ b/test/contract/MultiAsset/MultiAsset.bin
@@ -1 +1 @@
-608060405234801561001057600080fd5b506105ce806100206000396000f30060806040526004361061008e576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680634708293e146100905780637a727a41146100f9578063925dc8b314610130578063d639ec4214610193578063ef9ba08c146101ca578063f00d4b5d1461022a578063f208415e1461028d578063f5d82b6b146102e4575b005b34801561009c57600080fd5b506100f7600480360381019080803590602001908201803590602001908080601f0160208091040260200160405190810160405280939291908181526020018383808284378201915050505050509192919290505050610331565b005b34801561010557600080fd5b5061012e6004803603810190808035906020019092919080359060200190929190505050610352565b005b34801561013c57600080fd5b50610191600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506103a0565b005b34801561019f57600080fd5b506101c86004803603810190808035906020019092919080359060200190929190505050610414565b005b610228600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610462565b005b34801561023657600080fd5b5061028b600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506104c8565b005b34801561029957600080fd5b506102e2600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291908035906020019092919050505061050d565b005b3480156102f057600080fd5b5061032f600480360381019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610573565b005b8060200160405181900390c015801561034e573d6000803e3d6000fd5b5050565b60008282c690507f676574536e617073686f7454696d6500000000000000000000000000000000008160010260405180826000191660001916815260200191505060405180910390a1505050565b7f67657462616c616e6365657800000000000000000000000000000000000000008273ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16c360010260405180826000191660001916815260200191505060405180910390a15050565b60008282c590507f6765746173736574616d6f756e740000000000000000000000000000000000008160010260405180826000191660001916815260200191505060405180910390a1505050565b8273ffffffffffffffffffffffffffffffffffffffff166108fc8373ffffffffffffffffffffffffffffffffffffffff168391821502919060405160006040518083038186868a8ac49450505050501580156104c2573d6000803e3d6000fd5b50505050565b8073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16c2158015610508573d6000803e3d6000fd5b505050565b60008373ffffffffffffffffffffffffffffffffffffffff168383c790507f676574536e617042616c616e63650000000000000000000000000000000000008160010260405180826000191660001916815260200191505060405180910390a150505050565b8173ffffffffffffffffffffffffffffffffffffffff1681c115801561059d573d6000803e3d6000fd5b5050505600a165627a7a723058203eac0d54e785a391b33757afdb79bfc0adc40010d764de55bb544bf6139cac3e0029
+608060405261075f806100136000396000f3006080604052600436106100af576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680634708293e146100b45780634903b0d11461011057806356df3db11461015157806368669bc81461019e5780637a727a41146101e85780637d3d999b1461021f5780639b0fd0291461026c578063b9955e39146102b7578063bbd6ad6f1461030e578063cf4908761461037d578063d639ec42146103de575b600080fd5b61010e600480360381019080803590602001908201803590602001908080601f0160208091040260200160405190810160405280939291908181526020018383808284378201915050505050509192919290505050610415565b005b34801561011c57600080fd5b5061013b60048036038101908080359060200190929190505050610425565b6040518082815260200191505060405180910390f35b34801561015d57600080fd5b5061019c600480360381019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035906020019092919050505061042f565b005b6101e6600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291908035906020019092919050505061044d565b005b3480156101f457600080fd5b5061021d600480360381019080803590602001909291908035906020019092919050505061049d565b005b34801561022b57600080fd5b5061026a600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291905050506104eb565b005b34801561027857600080fd5b506102a16004803603810190808035906020019092919080359060200190929190505050610549565b6040518082815260200191505060405180910390f35b3480156102c357600080fd5b5061030c60048036038101908080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610556565b005b34801561031a57600080fd5b50610359600480360381019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610576565b60405180848152602001838152602001828152602001935050505060405180910390f35b34801561038957600080fd5b506103dc600480360381019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190803590602001909291908035906020019092919050505061067d565b005b3480156103ea57600080fd5b5061041360048036038101908080359060200190929190803590602001909291905050506106e5565b005b8060200160405181900390c05050565b6000819050919050565b808273ffffffffffffffffffffffffffffffffffffffff16c2505050565b8273ffffffffffffffffffffffffffffffffffffffff166108fc838391821502919060405160006040518083038186868a8ac4945050505050158015610497573d6000803e3d6000fd5b50505050565b60008282c690507f676574536e617073686f7454696d6500000000000000000000000000000000008160010260405180826000191660001916815260200191505060405180910390a1505050565b7f67657462616c616e6365657800000000000000000000000000000000000000008273ffffffffffffffffffffffffffffffffffffffff1682c360010260405180826000191660001916815260200191505060405180910390a15050565b60008282c8905092915050565b828273ffffffffffffffffffffffffffffffffffffffff1682c150505050565b6000806000806000808773ffffffffffffffffffffffffffffffffffffffff1687ca8093508194508295505050507f64656c65676174654e756d0000000000000000000000000000000000000000008360010260405180826000191660001916815260200191505060405180910390a17f566f74654e756d000000000000000000000000000000000000000000000000008260010260405180826000191660001916815260200191505060405180910390a17f426c6f636b4e756d0000000000000000000000000000000000000000000000008160010260405180826000191660001916815260200191505060405180910390a18282829550955095505050509250925092565b60008473ffffffffffffffffffffffffffffffffffffffff16848484c790507f676574536e617042616c616e63650000000000000000000000000000000000008160010260405180826000191660001916815260200191505060405180910390a15050505050565b60008282c590507f6765746173736574616d6f756e740000000000000000000000000000000000008160010260405180826000191660001916815260200191505060405180910390a15050505600a165627a7a72305820c8cac49e526b2d6b1960c43cf1cb84561311d0a5aead78dcbc2fd25c2ecdcdb90029
\ No newline at end of file
diff --git a/test/contract/MultiAsset/MultiAsset.sol b/test/contract/MultiAsset/MultiAsset.sol
old mode 100644
new mode 100755
index 8a19ebfa..a8626efa
--- a/test/contract/MultiAsset/MultiAsset.sol
+++ b/test/contract/MultiAsset/MultiAsset.sol
@@ -1,22 +1,23 @@
 pragma solidity ^0.4.24;
 
 contract MultiAsset {
-    function() public payable {
+    constructor() public payable {
     }
-    function reg(string desc) public {
+    function reg(string desc) public payable{
         issueasset(desc);
     } 
-    function add(address assetId, uint256 value) public {
-        addasset(assetId,value);
+    function add(uint256 assetId, address to, uint256 value ) public {
+        addasset(assetId,to,value);
     }
-    function transAsset(address to, address assetId, uint256 value) public payable {
+    function transAsset(address to, uint256 assetId, uint256 value) public payable {
         to.transferex(assetId, value);
     }
-    function changeOwner(address newOwner, address assetId) public {
+    function changeOwner(address newOwner, uint256 assetId) public {
         setassetowner(assetId, newOwner);
     }
-   function getBalanceEx(address to,address assetId) public {
+   function getBalanceEx(address to,uint256 assetId) public {
         log1(bytes32(to.balanceex(assetId)),"getbalanceex");
+       // return to.balanceex(assetId);
     }
     
    function getAssetAmount(uint256 assetId, uint256 time) public{
@@ -30,10 +31,30 @@ contract MultiAsset {
              x = snapshottime(t,time);
              log1(bytes32(x),"getSnapshotTime" );
 
-     }
-    function getSnapBalance(address to,uint256 assetId,uint256 time) public {
+    }
+
+    function getSnapBalance(address to,uint256 assetId, uint256 time, uint256 typeId) public {
         uint256 x ;
-        x = to.snapbalance(assetId,time);
+        x = to.snapbalance(assetId,time,typeId);
         log1(bytes32(x),"getSnapBalance");
     }
+
+    function balances(uint256 a) public pure returns (uint256 balance) { 
+        balance = a; 
+    }
+
+    function getdg(address user, uint256 t) external returns (uint256 a, uint256 b, uint256 c) {
+        uint256 aa;
+        uint256 bb;
+        uint256 cc;
+        (aa,bb,cc) = getdelegate(user,t);
+        log1(bytes32(aa), "delegateNum");
+        log1(bytes32(bb), "VoteNum");
+        log1(bytes32(cc), "BlockNum");
+        return (aa,bb,cc);
+    }
+
+   function setdestroyasset(uint256 assetId, uint256 value) public returns (uint256) {
+        return destroyasset(assetId, value);
+    }
 }
diff --git a/test/contract/MultiAsset/transaction_contract.go b/test/contract/MultiAsset/transaction_contract.go
index f1630b65..bd8749d7 100644
--- a/test/contract/MultiAsset/transaction_contract.go
+++ b/test/contract/MultiAsset/transaction_contract.go
@@ -18,65 +18,46 @@ package main
 
 import (
 	"bytes"
+	"crypto/ecdsa"
+	"encoding/binary"
 	"fmt"
 	"io/ioutil"
 	"math/big"
 	"strings"
 	"time"
 
+	jww "github.com/spf13/jwalterweatherman"
+
 	"github.com/fractalplatform/fractal/common"
 	"github.com/fractalplatform/fractal/crypto"
-	testcommon "github.com/fractalplatform/fractal/test/common"
+	tc "github.com/fractalplatform/fractal/test/common"
 	"github.com/fractalplatform/fractal/types"
 	"github.com/fractalplatform/fractal/utils/abi"
 	"github.com/fractalplatform/fractal/utils/rlp"
-	jww "github.com/spf13/jwalterweatherman"
 )
 
 var (
-	abifile       = "MultiAsset.abi"
-	binfile       = "MultiAsset.bin"
-	privateKey, _ = crypto.HexToECDSA("289c2857d4598e37fb9647507e47a309d6133539bf21a8b9cb6df88fd5232032")
-	from          = common.Name("ftsystemio")
-	to            = common.Name("toaddrname")
-	newFrom       = common.Name("newfromname")
-
-	contractAddr = common.Name("multiasset")
-	assetID      = uint64(1)
-
-	nonce = uint64(0)
-
-	gasLimit = uint64(2000000)
-)
-
-func generateAccount() {
-	nonce, _ = testcommon.GetNonce(from)
-
-	newPrivateKey, _ := crypto.GenerateKey()
-	pubKey := common.BytesToPubKey(crypto.FromECDSAPub(&newPrivateKey.PublicKey))
+	abifile         = "./MultiAsset.abi"
+	binfile         = "./MultiAsset.bin"
+	systemprikey, _ = crypto.HexToECDSA("289c2857d4598e37fb9647507e47a309d6133539bf21a8b9cb6df88fd5232032")
+	systemname      = common.Name("ftsystemio")
 
-	balance, _ := testcommon.GetAccountBalanceByID(from, assetID)
-	balance.Div(balance, big.NewInt(10))
+	contractAddr = common.Name("testtest11")
+	assetID      = uint64(1)
+	gasLimit     = uint64(2000000)
 
-	newFrom = common.Name(fmt.Sprintf("newfromname%d", nonce))
-	contractAddr = common.Name(fmt.Sprintf("multiasset%d", nonce))
+	pub1 = "0x0468cba7890aae10f3dde57d269cf7c4ba14cc0efc2afee86791b0a22b794820febdb2e5c6c56878a308e7f62ad2d75739de40313a72975c993dd76a5301a03d12"
+	pri1 = "357a2cbdd91686dcbe2c612e9bed85d4415f62446440839466bf7b2f1ab135b7"
 
-	sendTransferTx(types.CreateAccount, from, newFrom, nonce, assetID, balance, pubKey.Bytes())
-	sendTransferTx(types.CreateAccount, from, to, nonce+1, assetID, big.NewInt(0), pubKey.Bytes())
+	pub2 = "0x04fa0b2a9b2d0542bf2912c4c6500ba64a26652e302370ed5645b1c32df50fbe7a5f12da0b278638e1df6753a7c6ac09e68cb748cfe6d45102114f52e95e9ed652"
+	pri2 = "340cde826336f1adb8673ec945819d073af00cffb5c174542e35ff346445e213"
 
-	for {
-		time.Sleep(10 * time.Second)
-		fromexist, _ := testcommon.CheckAccountIsExist(newFrom)
-		toexist, _ := testcommon.CheckAccountIsExist(to)
-		if fromexist && toexist {
-			break
-		}
-	}
+	pubkey1    = common.HexToPubKey(pub1)
+	prikey1, _ = crypto.HexToECDSA(pri1)
 
-	from = newFrom
-	fmt.Println("from ", from)
-	privateKey = newPrivateKey
-}
+	pubkey2    = common.HexToPubKey(pub2)
+	prikey2, _ = crypto.HexToECDSA(pri2)
+)
 
 func input(abifile string, method string, params ...interface{}) (string, error) {
 	var abicode string
@@ -128,8 +109,24 @@ func formIssueAssetInput(abifile string, desc string) ([]byte, error) {
 	}
 	return common.Hex2Bytes(issueAssetInput), nil
 }
+func formIssueAssetInput1(abifile string, assetId *big.Int, to common.Address, value *big.Int) ([]byte, error) {
+	issueAssetInput, err := input(abifile, "add", assetId, to, value)
+	if err != nil {
+		jww.INFO.Println("createInput error ", err)
+		return nil, err
+	}
+	return common.Hex2Bytes(issueAssetInput), nil
+}
+func formSetAssetOwner(abifile string, newOwner common.Address, assetId *big.Int) ([]byte, error) {
+	issueAssetInput, err := input(abifile, "changeOwner", newOwner, assetId)
+	if err != nil {
+		jww.INFO.Println("createInput error ", err)
+		return nil, err
+	}
+	return common.Hex2Bytes(issueAssetInput), nil
+}
 
-func formTransferAssetInput(abifile string, toAddr common.Address, assetId common.Address, value *big.Int) ([]byte, error) {
+func formTransferAssetInput(abifile string, toAddr common.Address, assetId *big.Int, value *big.Int) ([]byte, error) {
 	transferAssetInput, err := input(abifile, "transAsset", toAddr, assetId, value)
 	if err != nil {
 		jww.INFO.Println("transferAssetInput error ", err)
@@ -138,29 +135,19 @@ func formTransferAssetInput(abifile string, toAddr common.Address, assetId commo
 	return common.Hex2Bytes(transferAssetInput), nil
 }
 
+func formGetDelgateInput(abifile string, user common.Address, time *big.Int) ([]byte, error) {
+	issueAssetInput, err := input(abifile, "getdg", user, time)
+	if err != nil {
+		jww.INFO.Println("createInput error ", err)
+		return nil, err
+	}
+	return common.Hex2Bytes(issueAssetInput), nil
+}
+
 func init() {
 	jww.SetLogThreshold(jww.LevelTrace)
 	jww.SetStdoutThreshold(jww.LevelInfo)
 
-	generateAccount()
-}
-
-func main() {
-	jww.INFO.Println("test send sundry transaction...")
-	sendDeployContractTransaction()
-	sendIssueTransaction()
-	for {
-		time.Sleep(10 * time.Second)
-		assetName := "eth" + from.String()
-		asset, _ := testcommon.GetAssetInfoByName(assetName)
-		if asset.AssetId != 0 {
-			assetID = asset.AssetId
-			fmt.Println("assetID ", assetID)
-			break
-		}
-	}
-	sendFulfillContractTransaction()
-	sendTransferTransaction()
 }
 
 func sendDeployContractTransaction() {
@@ -170,49 +157,87 @@ func sendDeployContractTransaction() {
 		jww.INFO.Println("sendDeployContractTransaction formCreateContractInput error ... ", err)
 		return
 	}
-	nonce, _ = testcommon.GetNonce(from)
-	sendTransferTx(types.CreateContract, from, contractAddr, nonce, assetID, big.NewInt(0), input)
+	nonce, _ := tc.GetNonce(systemname)
+	sendTx(types.CreateContract, systemname, contractAddr, nonce, assetID, big.NewInt(100000000000), input, systemprikey)
 }
 
 func sendIssueTransaction() {
 	jww.INFO.Println("test sendIssueTransaction... ")
-	issueStr := "eth" + from.String() + ",ethereum,10000000000,10," + from.String()
+	issueStr := "ft" + contractAddr.String() + ",ft,10000000000,10," + contractAddr.String() + ",9000000000000000," + contractAddr.String()
+	//issueStr := "eth4" + contractAddr.String() + ",ft,10000000000,10," + contractAddr.String() + ",9000000000000000," + contractAddr.String() //25560
 	input, err := formIssueAssetInput(abifile, issueStr)
 	if err != nil {
 		jww.INFO.Println("sendIssueTransaction formIssueAssetInput error ... ", err)
 		return
 	}
-	nonce++
-	sendTransferTx(types.Transfer, from, contractAddr, nonce, assetID, big.NewInt(0), input)
+	nonce, _ := tc.GetNonce(contractAddr)
+	sendTx(types.CallContract, contractAddr, contractAddr, nonce, assetID, big.NewInt(0), input, prikey1)
 }
 
-func sendFulfillContractTransaction() {
-	jww.INFO.Println("test sendFulfillContractTransaction... ")
-	nonce++
-	sendTransferTx(types.Transfer, from, contractAddr, nonce, assetID, big.NewInt(1000000000), nil)
+func sendIncreaseIssueTransaction() {
+	jww.INFO.Println("test sendIssueTransaction... ")
+	input, err := formIssueAssetInput1(abifile, big.NewInt(3), common.BytesToAddress([]byte("testtest12")), big.NewInt(100000)) //21976   21848
+
+	if err != nil {
+		jww.INFO.Println("sendIssueTransaction formIssueAssetInput error ... ", err)
+		return
+	}
+	nonce, _ := tc.GetNonce(contractAddr)
+	sendTx(types.CallContract, contractAddr, contractAddr, nonce, assetID, big.NewInt(0), input, prikey1)
+}
+
+func sendSetOwnerIssueTransaction() {
+	jww.INFO.Println("test sendIssueTransaction... ")
+	input, err := formSetAssetOwner(abifile, common.BytesToAddress([]byte("testtest12")), big.NewInt(3)) //22168
+
+	if err != nil {
+		jww.INFO.Println("sendIssueTransaction formIssueAssetInput error ... ", err)
+		return
+	}
+
+	nonce, _ := tc.GetNonce(contractAddr)
+	sendTx(types.CallContract, contractAddr, contractAddr, nonce, assetID, big.NewInt(0), input, prikey1)
+}
+
+func sendTransferToContractTransaction() {
+	nonce, _ := tc.GetNonce(systemname)
+	sendTx(types.Transfer, systemname, contractAddr, nonce, 1, big.NewInt(100), nil, systemprikey)
 }
 
 func sendTransferTransaction() {
 	jww.INFO.Println("test sendTransferTransaction... ")
-	input, err := formTransferAssetInput(abifile, common.BytesToAddress([]byte(to.String())), common.BigToAddress(big.NewInt(int64(assetID))), big.NewInt(1))
+	input, err := formTransferAssetInput(abifile, common.BytesToAddress([]byte("testtest12")), big.NewInt(1), big.NewInt(10))
 	if err != nil {
 		jww.INFO.Println("sendDeployContractTransaction formCreateContractInput error ... ", err)
 		return
 	}
+	nonce, _ := tc.GetNonce(systemname)
+	sendTx(types.CallContract, systemname, contractAddr, nonce, assetID, big.NewInt(0), input, systemprikey)
+}
+
+func sendGetDelgateContractTransaction() {
+	jww.INFO.Println("test sendGetDelgateContractTransaction... ")
 
-	for {
-		nonce++
-		sendTransferTx(types.Transfer, from, contractAddr, nonce, assetID, big.NewInt(0), input)
+	b := make([]byte, 8)
+	binary.BigEndian.PutUint64(b, 4099)
+
+	input, err := formGetDelgateInput(abifile, common.BytesToAddress(b), big.NewInt(0))
+	if err != nil {
+		jww.INFO.Println("sendGetDelgateContractTransaction formGetDelgateInput error ... ", err)
+		return
 	}
+	nonce, _ := tc.GetNonce(systemname)
+	sendTx(types.CallContract, systemname, contractAddr, nonce, assetID, big.NewInt(0), input, systemprikey)
 }
 
-func sendTransferTx(txType types.ActionType, from, to common.Name, nonce, assetID uint64, value *big.Int, input []byte) {
+func sendTx(txType types.ActionType, from, to common.Name, nonce, assetID uint64, value *big.Int, input []byte, prikey *ecdsa.PrivateKey) {
 	action := types.NewAction(txType, from, to, nonce, assetID, gasLimit, value, input)
-	gasprice, _ := testcommon.GasPrice()
+	gasprice, _ := tc.GasPrice()
 	tx := types.NewTransaction(1, gasprice, action)
 
 	signer := types.MakeSigner(big.NewInt(1))
-	err := types.SignAction(action, tx, signer, privateKey)
+	keypair := types.MakeKeyPair(prikey, []uint64{0})
+	err := types.SignActionWithMultiKey(action, tx, signer, []*types.KeyPair{keypair})
 	if err != nil {
 		jww.ERROR.Fatalln(err)
 	}
@@ -221,7 +246,25 @@ func sendTransferTx(txType types.ActionType, from, to common.Name, nonce, assetI
 	if err != nil {
 		jww.ERROR.Fatalln(err)
 	}
-
-	hash, _ := testcommon.SendRawTx(rawtx)
+	hash, _ := tc.SendRawTx(rawtx)
 	jww.INFO.Println("result hash: ", hash.Hex())
 }
+
+func main() {
+	sendDeployContractTransaction()
+	time.Sleep(time.Duration(3) * time.Second)
+	sendIssueTransaction()
+	time.Sleep(time.Duration(3) * time.Second)
+	asset, _ := tc.GetAssetInfoByName("ft" + contractAddr.String())
+	fmt.Println(asset)
+	sendIncreaseIssueTransaction()
+	time.Sleep(time.Duration(3) * time.Second)
+	sendTransferToContractTransaction()
+	time.Sleep(time.Duration(3) * time.Second)
+	sendTransferTransaction()
+	time.Sleep(time.Duration(3) * time.Second)
+	sendSetOwnerIssueTransaction()
+	time.Sleep(time.Duration(3) * time.Second)
+	sendGetDelgateContractTransaction()
+	time.Sleep(time.Duration(3) * time.Second)
+}
diff --git a/test/contract/VEN/transaction_contract.go b/test/contract/VEN/transaction_contract.go
index 543420c7..786d6dc9 100644
--- a/test/contract/VEN/transaction_contract.go
+++ b/test/contract/VEN/transaction_contract.go
@@ -190,7 +190,8 @@ func sendTransferTx(txType types.ActionType, from, to common.Name, nonce, assetI
 	tx := types.NewTransaction(assetID, gasprice, action)
 
 	signer := types.MakeSigner(big.NewInt(1))
-	err := types.SignAction(action, tx, signer, privateKey)
+	keypair := types.MakeKeyPair(privateKey, []uint64{0})
+	err := types.SignActionWithMultiKey(action, tx, signer, []*types.KeyPair{keypair})
 	if err != nil {
 		jww.ERROR.Fatalln(err)
 	}
diff --git a/test/dpos/dpostx.go b/test/dpos/dpostx.go
deleted file mode 100644
index 919eec2f..00000000
--- a/test/dpos/dpostx.go
+++ /dev/null
@@ -1,295 +0,0 @@
-// Copyright 2018 The Fractal Team Authors
-// This file is part of the fractal project.
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-package main
-
-import (
-	//"bytes"
-	//"io/ioutil"
-	"math/big"
-	//"strings"
-	"fmt"
-	"time"
-
-	"github.com/fractalplatform/fractal/common"
-	"github.com/fractalplatform/fractal/consensus/dpos"
-	"github.com/fractalplatform/fractal/crypto"
-	testcommon "github.com/fractalplatform/fractal/test/common"
-	"github.com/fractalplatform/fractal/types"
-	"github.com/fractalplatform/fractal/utils/rlp"
-	jww "github.com/spf13/jwalterweatherman"
-)
-
-var (
-	minproducerstake = big.NewInt(0).Mul(dpos.DefaultConfig.UnitStake, dpos.DefaultConfig.ProducerMinQuantity)
-	minvoterstake    = big.NewInt(0).Mul(dpos.DefaultConfig.UnitStake, dpos.DefaultConfig.VoterMinQuantity)
-	big1             = big.NewInt(1)
-
-	privateKey, _ = crypto.HexToECDSA("289c2857d4598e37fb9647507e47a309d6133539bf21a8b9cb6df88fd5232032")
-	from          = common.Name("ftsystemio")
-	p1            = common.Name("producer1")
-	p2            = common.Name("producer2")
-	newFrom       = common.Name("newfromname")
-	noNeedUser    = common.Name("")
-	noNeedNum     = big.NewInt(0)
-
-	assetID = uint64(1)
-
-	nonce = uint64(0)
-
-	gasLimit = uint64(2000000)
-)
-
-func generateAccount() {
-	nonce, _ = testcommon.GetNonce(from)
-
-	newPrivateKey, _ := crypto.GenerateKey()
-	pubKey := common.BytesToPubKey(crypto.FromECDSAPub(&newPrivateKey.PublicKey))
-
-	balance, _ := testcommon.GetAccountBalanceByID(from, assetID)
-	balance.Div(balance, big.NewInt(10))
-
-	newFrom = common.Name(fmt.Sprintf("newfromname%d", nonce))
-	//contractAddr = common.Name(fmt.Sprintf("multiasset%d", nonce))
-
-	sendTransferTx(types.CreateAccount, from, newFrom, nonce, assetID, balance, pubKey.Bytes())
-	nonce++
-	sendTransferTx(types.CreateAccount, from, p1, nonce, assetID, balance, pubKey.Bytes())
-	nonce++
-	sendTransferTx(types.CreateAccount, from, p2, nonce, assetID, balance, pubKey.Bytes())
-
-	for {
-		time.Sleep(3 * time.Second)
-		bnf, _ := testcommon.CheckAccountIsExist(newFrom)
-		bp1, _ := testcommon.CheckAccountIsExist(p1)
-		bp2, _ := testcommon.CheckAccountIsExist(p2)
-		if bnf && bp1 && bp2 {
-			jww.INFO.Println("account created... ")
-			break
-		}
-	}
-
-	from = newFrom
-	privateKey = newPrivateKey
-}
-
-func init() {
-	jww.SetLogThreshold(jww.LevelTrace)
-	jww.SetStdoutThreshold(jww.LevelInfo)
-
-	generateAccount()
-}
-
-func main() {
-	jww.INFO.Println("Test dpos votes transactions...")
-
-	commonUnregProducer()
-
-	sendRegProducer()
-	sendUpdateProducer()
-	sendVoteProducer()
-
-	for {
-		// check result
-		time.Sleep(3 * time.Second)
-
-		p1_fields, err := testcommon.GetDposAccount(p1)
-		p2_fields, _ := testcommon.GetDposAccount(p2)
-		if true {
-			jww.INFO.Println("p1:", p1_fields)
-			jww.INFO.Println("p2:", p2_fields)
-			jww.INFO.Println("err", err)
-			break
-		}
-	}
-	sendChangeProducer()
-	//
-	sendUnvoteProducer()
-	//
-	for {
-		// check result
-		time.Sleep(3 * time.Second)
-
-		p1_fields, _ := testcommon.GetDposAccount(p1)
-		p2_fields, _ := testcommon.GetDposAccount(p2)
-		if true {
-			jww.INFO.Println("p1:", p1_fields)
-			jww.INFO.Println("p2:", p2_fields)
-			break
-		}
-	}
-	sendVoteProducer()
-	sendRemoveVoter()
-	//
-	for {
-		// check result
-		time.Sleep(3 * time.Second)
-
-		p1_fields, _ := testcommon.GetDposAccount(p1)
-		p2_fields, _ := testcommon.GetDposAccount(p2)
-		if true {
-			jww.INFO.Println("p1:", p1_fields)
-			jww.INFO.Println("p2:", p2_fields)
-			break
-		}
-	}
-	sendUnregProducer()
-}
-
-func sendRegProducer() {
-	jww.INFO.Println("test sendRegProducer... ")
-
-	rp := dpos.RegisterProducer{
-		Url:   "https://www.test_url.xxx/",
-		Stake: minproducerstake,
-	}
-
-	rawdata, err := rlp.EncodeToBytes(rp)
-	if err != nil {
-		jww.ERROR.Fatalln(err)
-	}
-
-	nonce++
-	sendTransferTx(types.RegProducer, p1, noNeedUser, nonce, assetID, noNeedNum, rawdata)
-	nonce++
-	sendTransferTx(types.RegProducer, p2, noNeedUser, nonce, assetID, noNeedNum, rawdata)
-	jww.INFO.Println("test sendRegProducer... done ")
-}
-
-func sendUnregProducer() {
-	jww.INFO.Println("test sendUnregProducer... ")
-
-	nonce++
-	sendTransferTx(types.UnregProducer, p1, noNeedUser, nonce, assetID, noNeedNum, nil)
-	nonce++
-	sendTransferTx(types.UnregProducer, p2, noNeedUser, nonce, assetID, noNeedNum, nil)
-	jww.INFO.Println("test sendUnregProducer... done ")
-}
-
-func sendUpdateProducer() {
-	jww.INFO.Println("test sendUpdateProducer... ")
-
-	rp := dpos.UpdateProducer{
-		Url:   "https://www.test_url_p1.xxx/",
-		Stake: minproducerstake,
-	}
-
-	rawdata, err := rlp.EncodeToBytes(rp)
-	if err != nil {
-		jww.ERROR.Fatalln(err)
-	}
-	nonce++
-	sendTransferTx(types.UpdateProducer, p1, noNeedUser, nonce, assetID, noNeedNum, rawdata)
-	jww.INFO.Println("test sendUpdateProducer... done ")
-}
-
-func sendRemoveVoter() {
-	jww.INFO.Println("test sendRemoveVoter... ")
-
-	rp := dpos.RemoveVoter{
-		Voter: from.String(),
-	}
-
-	rawdata, err := rlp.EncodeToBytes(rp)
-	if err != nil {
-		jww.ERROR.Fatalln(err)
-	}
-
-	nonce++
-	sendTransferTx(types.RemoveVoter, p1, noNeedUser, nonce, assetID, noNeedNum, rawdata)
-	jww.INFO.Println("test sendRemoveVoter... done ")
-}
-
-func sendVoteProducer() {
-	jww.INFO.Println("test sendVoteProducer... ")
-
-	rp := dpos.VoteProducer{
-		Producer: p1.String(),
-		Stake:    minvoterstake,
-	}
-
-	rawdata, err := rlp.EncodeToBytes(rp)
-	if err != nil {
-		jww.ERROR.Fatalln(err)
-	}
-	nonce++
-	sendTransferTx(types.VoteProducer, from, noNeedUser, nonce, assetID, noNeedNum, rawdata)
-	jww.INFO.Println("test sendVoteProducer... done ")
-}
-
-func sendChangeProducer() {
-	jww.INFO.Println("test sendChangeProducer... ")
-
-	rp := dpos.ChangeProducer{
-		Producer: p2.String(),
-	}
-
-	rawdata, err := rlp.EncodeToBytes(rp)
-	if err != nil {
-		jww.ERROR.Fatalln(err)
-	}
-	nonce++
-	sendTransferTx(types.ChangeProducer, from, noNeedUser, nonce, assetID, noNeedNum, rawdata)
-	jww.INFO.Println("test sendChangeProducer... done")
-}
-
-func sendUnvoteProducer() {
-	jww.INFO.Println("test sendUnvoteProducer... ")
-
-	nonce++
-	sendTransferTx(types.UnvoteProducer, from, noNeedUser, nonce, assetID, noNeedNum, nil)
-	jww.INFO.Println("test sendUnvoteProducer... done ")
-}
-
-// sendTransferTx
-func sendTransferTx(txType types.ActionType, from, to common.Name, nonce, assetID uint64, value *big.Int, input []byte) {
-	action := types.NewAction(txType, from, to, nonce, assetID, gasLimit, value, input)
-	gp, _ := testcommon.GasPrice()
-	tx := types.NewTransaction(assetID, gp, action)
-
-	signer := types.MakeSigner(big.NewInt(1))
-	err := types.SignAction(action, tx, signer, privateKey)
-	if err != nil {
-		jww.ERROR.Fatalln(err)
-	}
-
-	rawtx, err := rlp.EncodeToBytes(tx)
-	if err != nil {
-		jww.ERROR.Fatalln(err)
-	}
-
-	if hash, err := testcommon.SendRawTx(rawtx); err != nil {
-		jww.ERROR.Fatalln("send failed: ", err)
-	} else {
-		jww.INFO.Println("result hash: ", hash.Hex())
-	}
-}
-
-func commonUnregProducer() {
-	jww.INFO.Println("test commonUnregProducer... ")
-
-	acct := testcommon.NewAccount(p1, privateKey, 1, 0, nil)
-
-	rawtx := acct.UnRegProducer(p1, big1, 1, gasLimit)
-
-	if hash, err := testcommon.SendRawTx(rawtx); err != nil {
-		jww.ERROR.Fatalln("send failed: h", err, hash.Hex())
-	} else {
-		jww.INFO.Println("result hash: ", hash.Hex())
-	}
-
-	jww.INFO.Println("test commonUnregProducer... done ")
-}
diff --git a/test/dposstart/main.go b/test/dposstart/main.go
new file mode 100644
index 00000000..a6dc8fb5
--- /dev/null
+++ b/test/dposstart/main.go
@@ -0,0 +1,129 @@
+package main
+
+import (
+	"flag"
+	"fmt"
+	"math"
+	"math/big"
+	"strings"
+
+	"github.com/fractalplatform/fractal/accountmanager"
+	"github.com/fractalplatform/fractal/common"
+	args "github.com/fractalplatform/fractal/consensus/dpos"
+	"github.com/fractalplatform/fractal/crypto"
+	"github.com/fractalplatform/fractal/sdk"
+)
+
+var (
+	gasLimit = uint64(210000)
+	gasPrice = big.NewInt(10000000000)
+)
+
+func main() {
+	rpcHost := flag.String("u", "http://localhost:8545", "RPC host地址")
+	issueHex := flag.String("s", "ftsystemio:289c2857d4598e37fb9647507e47a309d6133539bf21a8b9cb6df88fd5232032", "系统账户私钥")
+	systoken := flag.String("systoken", "ftoken", "系统代币名字")
+	value := flag.Int64("n", 10000000, "生成者代币质押数量(最小单位),1000万")
+	chainID := flag.Int64("chainid", 1, "chain id")
+	flag.Parse()
+
+	cadidates := flag.Args()
+	if len(cadidates) == 0 {
+		cadidates = append(cadidates, "ftcadidate1:289c2857d4598e37fb9647507e47a309d6133539bf21a8b9cb6df88fd5232032")
+		cadidates = append(cadidates, "ftcadidate2:9c22ff5f21f0b81b113e63f7db6da94fedef11b2119b4088b89664fb9a3cb658")
+		cadidates = append(cadidates, "ftcadidate3:8605cf6e76c9fc8ac079d0f841bd5e99bd3ad40fdd56af067993ed14fc5bfca8")
+	}
+
+	fmt.Println("RPC:", rpcHost)
+	fmt.Println("系统账户:", *issueHex)
+	fmt.Println("系统代币:", *systoken)
+	fmt.Println("质押数量:", *value)
+	fmt.Println("生成者数量:", len(cadidates))
+	fmt.Println("生成者列表:", cadidates)
+	api := sdk.NewAPI(*rpcHost)
+
+	sysasset, err := api.AssetInfoByName(*systoken)
+	if err != nil {
+		panic(fmt.Sprintf("get asset info %v err %v", *systoken, err))
+	}
+	systokenid := sysasset.AssetId
+	systokendecimals := big.NewInt(1)
+	for i := uint64(0); i < sysasset.Decimals; i++ {
+		systokendecimals = new(big.Int).Mul(systokendecimals, big.NewInt(10))
+	}
+
+	// issuer
+	splits := strings.Split(*issueHex, ":")
+	if len(splits) != 2 {
+		println("系统账户出错啦~~~", *issueHex)
+		return
+	}
+	if !common.IsValidAccountName(splits[0]) {
+		println("系统账户非法啦~~~", splits[0])
+		return
+	}
+	issuerName := common.StrToName(splits[0])
+	issuerPriv, err := crypto.HexToECDSA(splits[1])
+	if err != nil {
+		println("系统账户私钥出错啦~~~", issueHex)
+		return
+	}
+
+	if len(cadidates) < 3 {
+		println("生产者个数不能小于3~~~", len(cadidates))
+		return
+	}
+	issuerAcct := sdk.NewAccount(api, issuerName, issuerPriv, systokenid, math.MaxUint64, true, big.NewInt(*chainID))
+
+	prods := map[common.Name]*sdk.Account{}
+	for _, privHex := range cadidates {
+		splits := strings.Split(privHex, ":")
+		if len(splits) != 2 {
+			println("生产者账户出错啦~~~", privHex)
+			return
+		}
+		if !common.IsValidAccountName(splits[0]) {
+			println("生产者账户非法啦~~~", splits[0])
+			return
+		}
+		name := common.StrToName(splits[0])
+		priv, err := crypto.HexToECDSA(splits[1])
+		if err != nil {
+			println("生产者账户私钥出错啦~~~", privHex)
+			return
+		}
+		prods[name] = sdk.NewAccount(api, name, priv, systokenid, math.MaxUint64, true, big.NewInt(*chainID))
+	}
+
+	delegateValue := new(big.Int).Mul(big.NewInt(*value), systokendecimals)
+	issueValue := new(big.Int).Mul(big.NewInt(*value+10), systokendecimals)
+
+	fmt.Println("转账金额/人:", issueValue)
+	fmt.Println("质押金额/人:", delegateValue)
+
+	for to, acct := range prods {
+		existed, _ := api.AccountIsExist(to.String())
+		if !existed {
+			hash, err := issuerAcct.CreateAccount(issuerName, issueValue, systokenid, gasLimit, &accountmanager.AccountAction{
+				AccountName: to,
+				PublicKey:   acct.Pubkey(),
+			})
+			fmt.Println(hash.String(), ":", issuerName, "create & transfer", issueValue, fmt.Sprintf("(%v)", systokenid), "to", to, "error", err)
+		} else {
+			hash, err := issuerAcct.Transfer(to, issueValue, systokenid, gasLimit)
+			fmt.Println(hash.String(), ":", issuerName, "transfer", issueValue, fmt.Sprintf("(%v)", systokenid), "to", to, "error", err)
+		}
+	}
+
+	// reg cadidates
+	for name, acct := range prods {
+		value := big.NewInt(1e5)
+		hash, err := acct.RegCadidate(name, big.NewInt(0), systokenid, gasLimit, &args.RegisterCadidate{
+			Url:   "www." + name.String() + ".io",
+			Stake: delegateValue,
+		})
+		fmt.Println(hash.String(), ":", issuerName, "reg", delegateValue, "& transfer", value, "(", systokenid, ")", "to ", name, "error", err)
+	}
+
+	fmt.Println("Dpos启动完成.")
+}
diff --git a/test/multisig/transaction_contract.go b/test/multisig/transaction_contract.go
new file mode 100644
index 00000000..492f86ae
--- /dev/null
+++ b/test/multisig/transaction_contract.go
@@ -0,0 +1,276 @@
+// Copyright 2018 The Fractal Team Authors
+// This file is part of the fractal project.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+package main
+
+import (
+	"crypto/ecdsa"
+	"encoding/hex"
+	"fmt"
+	"math/big"
+	"time"
+
+	"github.com/fractalplatform/fractal/accountmanager"
+	"github.com/fractalplatform/fractal/common"
+	"github.com/fractalplatform/fractal/crypto"
+	testcommon "github.com/fractalplatform/fractal/test/common"
+	"github.com/fractalplatform/fractal/types"
+	"github.com/fractalplatform/fractal/utils/rlp"
+	jww "github.com/spf13/jwalterweatherman"
+)
+
+var (
+	privateKey, _ = crypto.HexToECDSA("289c2857d4598e37fb9647507e47a309d6133539bf21a8b9cb6df88fd5232032")
+	from          = common.Name("ftsystemio")
+	aca           = common.Name("accounta")
+	acb           = common.Name("accountb")
+	acc           = common.Name("accountc")
+
+	a_author_0_priv *ecdsa.PrivateKey
+	a_author_2_priv *ecdsa.PrivateKey
+	a_author_3_priv *ecdsa.PrivateKey
+	b_author_0_priv *ecdsa.PrivateKey
+	b_author_2_priv *ecdsa.PrivateKey
+	c_author_0_priv *ecdsa.PrivateKey
+	c_author_1_priv *ecdsa.PrivateKey
+	c_author_2_priv *ecdsa.PrivateKey
+
+	newPrivateKey_a *ecdsa.PrivateKey
+	newPrivateKey_b *ecdsa.PrivateKey
+	newPrivateKey_c *ecdsa.PrivateKey
+	pubKey_a        common.PubKey
+	pubKey_b        common.PubKey
+	pubKey_c        common.PubKey
+
+	aNonce = uint64(0)
+	bNonce = uint64(0)
+	cNonce = uint64(0)
+
+	assetID  = uint64(1)
+	nonce    = uint64(0)
+	gasLimit = uint64(2000000)
+)
+
+func generateAccount() {
+	nonce, _ = testcommon.GetNonce(from)
+
+	newPrivateKey_a, _ = crypto.GenerateKey()
+	pubKey_a = common.BytesToPubKey(crypto.FromECDSAPub(&newPrivateKey_a.PublicKey))
+	a_author_0_priv = newPrivateKey_a
+	fmt.Println("priv_a ", hex.EncodeToString(crypto.FromECDSA(newPrivateKey_a)), " pubKey_a ", pubKey_a.String())
+
+	newPrivateKey_b, _ = crypto.GenerateKey()
+	pubKey_b = common.BytesToPubKey(crypto.FromECDSAPub(&newPrivateKey_b.PublicKey))
+	b_author_0_priv = newPrivateKey_b
+	fmt.Println("priv_b ", hex.EncodeToString(crypto.FromECDSA(newPrivateKey_b)), " pubKey_b ", pubKey_b.String())
+
+	newPrivateKey_c, _ = crypto.GenerateKey()
+	pubKey_c = common.BytesToPubKey(crypto.FromECDSAPub(&newPrivateKey_c.PublicKey))
+	c_author_0_priv = newPrivateKey_c
+	fmt.Println("priv_c ", hex.EncodeToString(crypto.FromECDSA(newPrivateKey_c)), " pubKey_c ", pubKey_c.String())
+
+	balance, _ := testcommon.GetAccountBalanceByID(from, assetID)
+	balance.Div(balance, big.NewInt(10))
+
+	aca = common.Name(fmt.Sprintf("accounta%d", nonce))
+	acb = common.Name(fmt.Sprintf("accountb%d", nonce))
+	acc = common.Name(fmt.Sprintf("accountc%d", nonce))
+
+	key := types.MakeKeyPair(privateKey, []uint64{0})
+	acct := &accountmanager.AccountAction{
+		AccountName: aca,
+		Founder:     aca,
+		PublicKey:   pubKey_a,
+	}
+	b, _ := rlp.EncodeToBytes(acct)
+	sendTransferTx(types.CreateAccount, from, from, nonce, assetID, balance, b, []*types.KeyPair{key})
+
+	acct = &accountmanager.AccountAction{
+		AccountName: acb,
+		Founder:     acb,
+		PublicKey:   pubKey_b,
+	}
+	b, _ = rlp.EncodeToBytes(acct)
+	sendTransferTx(types.CreateAccount, from, from, nonce+1, assetID, balance, b, []*types.KeyPair{key})
+
+	acct = &accountmanager.AccountAction{
+		AccountName: acc,
+		Founder:     acc,
+		PublicKey:   pubKey_c,
+	}
+	b, _ = rlp.EncodeToBytes(acct)
+	sendTransferTx(types.CreateAccount, from, from, nonce+2, assetID, balance, b, []*types.KeyPair{key})
+
+	for {
+		time.Sleep(10 * time.Second)
+		aexist, _ := testcommon.CheckAccountIsExist(aca)
+		bexist, _ := testcommon.CheckAccountIsExist(acb)
+		cexist, _ := testcommon.CheckAccountIsExist(acc)
+		if aexist && bexist && cexist {
+			break
+		}
+	}
+
+	fmt.Println("aca ", aca, " acb ", acb, " acc ", acc)
+}
+
+func init() {
+	jww.SetLogThreshold(jww.LevelTrace)
+	jww.SetStdoutThreshold(jww.LevelInfo)
+
+	generateAccount()
+}
+
+func addAuthorsForAca() {
+	a_author_0 := common.NewAuthor(pubKey_a, 500)
+	a_authorAct_0 := &accountmanager.AuthorAction{1, a_author_0}
+
+	a_author_1 := common.NewAuthor(acb, 400)
+	a_authorAct_1 := &accountmanager.AuthorAction{0, a_author_1}
+
+	a_author_2_priv, _ = crypto.GenerateKey()
+	a_author_2_addr := crypto.PubkeyToAddress(a_author_2_priv.PublicKey)
+	a_author_2 := common.NewAuthor(a_author_2_addr, 400)
+	a_authorAct_2 := &accountmanager.AuthorAction{0, a_author_2}
+
+	a_author_3_priv, _ = crypto.GenerateKey()
+	a_author_3_pub := common.BytesToPubKey(crypto.FromECDSAPub(&a_author_3_priv.PublicKey))
+	a_author_3 := common.NewAuthor(a_author_3_pub, 400)
+	a_authorAct_3 := &accountmanager.AuthorAction{0, a_author_3}
+
+	action := &accountmanager.AccountAuthorAction{1000, 0, []*accountmanager.AuthorAction{a_authorAct_0, a_authorAct_1, a_authorAct_2, a_authorAct_3}}
+	input, err := rlp.EncodeToBytes(action)
+	if err != nil {
+		jww.INFO.Println("addAuthors for accounta error ... ", err)
+		return
+	}
+	key := types.MakeKeyPair(newPrivateKey_a, []uint64{0})
+	sendTransferTx(types.UpdateAccountAuthor, aca, aca, aNonce, assetID, big.NewInt(0), input, []*types.KeyPair{key})
+}
+
+func addAuthorsForAcb() {
+	b_author_0 := common.NewAuthor(pubKey_b, 50)
+	b_authorAct_0 := &accountmanager.AuthorAction{1, b_author_0}
+
+	b_author_1 := common.NewAuthor(acc, 40)
+	b_authorAct_1 := &accountmanager.AuthorAction{0, b_author_1}
+
+	b_author_2_priv, _ = crypto.GenerateKey()
+	b_author_2_addr := crypto.PubkeyToAddress(b_author_2_priv.PublicKey)
+	b_author_2 := common.NewAuthor(b_author_2_addr, 40)
+	b_authorAct_2 := &accountmanager.AuthorAction{0, b_author_2}
+
+	action := &accountmanager.AccountAuthorAction{100, 0, []*accountmanager.AuthorAction{b_authorAct_0, b_authorAct_1, b_authorAct_2}}
+	input, err := rlp.EncodeToBytes(action)
+	if err != nil {
+		jww.INFO.Println("addAuthors for accountb error ... ", err)
+		return
+	}
+	key := types.MakeKeyPair(newPrivateKey_b, []uint64{0})
+	sendTransferTx(types.UpdateAccountAuthor, acb, acb, bNonce, assetID, big.NewInt(0), input, []*types.KeyPair{key})
+}
+
+func addAuthorsForAcc() {
+	c_author_0 := common.NewAuthor(pubKey_c, 5)
+	c_authorAct_0 := &accountmanager.AuthorAction{1, c_author_0}
+
+	c_author_1_priv, _ = crypto.GenerateKey()
+	c_author_1_addr := crypto.PubkeyToAddress(c_author_1_priv.PublicKey)
+	c_author_1 := common.NewAuthor(c_author_1_addr, 4)
+	c_authorAct_1 := &accountmanager.AuthorAction{0, c_author_1}
+
+	c_author_2_priv, _ = crypto.GenerateKey()
+	c_author_2_pub := common.BytesToPubKey(crypto.FromECDSAPub(&c_author_2_priv.PublicKey))
+	c_author_2 := common.NewAuthor(c_author_2_pub, 4)
+	c_authorAct_2 := &accountmanager.AuthorAction{0, c_author_2}
+
+	action := &accountmanager.AccountAuthorAction{10, 0, []*accountmanager.AuthorAction{c_authorAct_0, c_authorAct_1, c_authorAct_2}}
+	input, err := rlp.EncodeToBytes(action)
+	if err != nil {
+		jww.INFO.Println("addAuthors for accountc error ... ", err)
+		return
+	}
+	key := types.MakeKeyPair(newPrivateKey_c, []uint64{0})
+	sendTransferTx(types.UpdateAccountAuthor, acc, acc, cNonce, assetID, big.NewInt(0), input, []*types.KeyPair{key})
+}
+
+func transferFromA2B() {
+	key_1_0 := types.MakeKeyPair(b_author_0_priv, []uint64{1, 0})
+	key_1_1_0 := types.MakeKeyPair(c_author_0_priv, []uint64{1, 1, 0})
+	key_1_1_1 := types.MakeKeyPair(c_author_1_priv, []uint64{1, 1, 1})
+	key_1_1_2 := types.MakeKeyPair(c_author_2_priv, []uint64{1, 1, 2})
+	key_2 := types.MakeKeyPair(a_author_2_priv, []uint64{2})
+	key_3 := types.MakeKeyPair(a_author_3_priv, []uint64{3})
+	key_1_2 := types.MakeKeyPair(b_author_2_priv, []uint64{1, 2})
+
+	aNonce++
+	sendTransferTx(types.Transfer, aca, acb, aNonce, assetID, big.NewInt(1), nil, []*types.KeyPair{key_1_0, key_1_1_0, key_1_1_1, key_1_1_2, key_2, key_3, key_1_2})
+}
+
+func modifyAUpdateAUthorThreshold() {
+	key_2 := types.MakeKeyPair(a_author_2_priv, []uint64{2})
+	action := &accountmanager.AccountAuthorAction{0, 2, []*accountmanager.AuthorAction{}}
+	input, err := rlp.EncodeToBytes(action)
+	if err != nil {
+		jww.INFO.Println("addAuthors for accountc error ... ", err)
+		return
+	}
+
+	aNonce++
+	sendTransferTx(types.UpdateAccountAuthor, aca, aca, aNonce, assetID, big.NewInt(0), input, []*types.KeyPair{key_2})
+}
+
+func main() {
+	jww.INFO.Println("test send sundry transaction...")
+
+	// d_author_1_priv, _ := crypto.GenerateKey()
+	// d_author_1_pub := common.BytesToPubKey(crypto.FromECDSAPub(&d_author_1_priv.PublicKey))
+	// d_author_1_pub_addr := common.BytesToAddress(crypto.Keccak256(d_author_1_pub.Bytes()[1:])[12:])
+	// d_author_1_addr := crypto.PubkeyToAddress(d_author_1_priv.PublicKey)
+	// fmt.Println(d_author_1_pub_addr.String(), d_author_1_addr.String())
+
+	addAuthorsForAca()
+	addAuthorsForAcb()
+	addAuthorsForAcc()
+	time.Sleep(10 * time.Second)
+
+	transferFromA2B()
+	modifyAUpdateAUthorThreshold()
+}
+
+func sendTransferTx(txType types.ActionType, from, to common.Name, nonce, assetID uint64, value *big.Int, input []byte, keys []*types.KeyPair) {
+	action := types.NewAction(txType, from, to, nonce, assetID, gasLimit, value, input)
+	gasprice, _ := testcommon.GasPrice()
+	tx := types.NewTransaction(1, gasprice, action)
+
+	signer := types.MakeSigner(big.NewInt(1))
+	err := types.SignActionWithMultiKey(action, tx, signer, keys)
+	if err != nil {
+		jww.ERROR.Fatalln(err)
+	}
+
+	rawtx, err := rlp.EncodeToBytes(tx)
+	if err != nil {
+		jww.ERROR.Fatalln(err)
+	}
+
+	hash, err := testcommon.SendRawTx(rawtx)
+	if err != nil {
+		jww.INFO.Println("result err: ", err)
+
+	}
+	jww.INFO.Println("result hash: ", hash.Hex())
+}
diff --git a/test/systemtestcase/account_test.go b/test/systemtestcase/account_test.go
deleted file mode 100644
index 40f27af9..00000000
--- a/test/systemtestcase/account_test.go
+++ /dev/null
@@ -1,122 +0,0 @@
-// Copyright 2018 The Fractal Team Authors
-// This file is part of the fractal project.
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-package main
-
-import (
-	"crypto/ecdsa"
-	"testing"
-
-	. "github.com/fractalplatform/fractal/test/systemtestcase/rpc"
-	. "github.com/smartystreets/goconvey/convey"
-)
-
-func createNewAccount(fromAccount string, fromPriKey *ecdsa.PrivateKey, newAccountName string) error {
-	result, _, _ := CreateNewAccountWithName(fromAccount, fromPriKey, newAccountName)
-	return result
-}
-
-func TestCreateNormalAccount_111(t *testing.T) {
-	Convey("用系统账户创建新账户", t, func() {
-		accountName, err := GenerateValidAccountName("111", 8)
-		So(err, ShouldBeNil)
-		So(createNewAccount(SystemAccount, SystemAccountPriKey, accountName), ShouldBeNil)
-	})
-}
-
-func TestCreateDuplicateAccount_112(t *testing.T) {
-	Convey("用系统账户重复创建账户失败", t, func() {
-		accountName, err := GenerateValidAccountName("112", 8)
-		So(err, ShouldBeNil)
-		So(createNewAccount(SystemAccount, SystemAccountPriKey, accountName), ShouldBeNil)
-		So(createNewAccount(SystemAccount, SystemAccountPriKey, accountName), ShouldNotBeNil)
-	})
-}
-
-func TestCreateErrAccount_113(t *testing.T) {
-	Convey("用系统账户创建新账户失败(账户名不符合规范)", t, func() {
-		So(createNewAccount(SystemAccount, SystemAccountPriKey, "&!@123456"), ShouldNotBeNil)
-	})
-}
-
-func TestGetAccountInfo_131(t *testing.T) {
-	Convey("获取系统账户信息", t, func() {
-		So(GetAccountInfo(SystemAccount), ShouldBeTrue)
-	})
-
-	Convey("获取已创建的普通账户信息", t, func() {
-		accountName, err := GenerateValidAccountName("131", 8)
-		So(err, ShouldBeNil)
-		So(createNewAccount(SystemAccount, SystemAccountPriKey, accountName), ShouldBeNil)
-		So(GetAccountInfo(accountName), ShouldBeTrue)
-	})
-}
-
-func TestGetAccountInfo_132(t *testing.T) {
-	Convey("获取不存在的账户信息失败", t, func() {
-		accountName := GenerateAccountName("132", 8)
-		So(GetAccountInfo(accountName), ShouldBeFalse)
-	})
-}
-
-func TestAccountExist_133(t *testing.T) {
-	Convey("确认已创建的账户存在", t, func() {
-		accountName, err := GenerateValidAccountName("133", 8)
-		So(err, ShouldBeNil)
-
-		So(createNewAccount(SystemAccount, SystemAccountPriKey, accountName), ShouldBeNil)
-
-		bExist, err := AccountIsExist(accountName)
-		So(err, ShouldBeNil)
-		So(bExist, ShouldBeTrue)
-	})
-}
-
-func TestAccountExist_134(t *testing.T) {
-	Convey("确认未创建的账户不存在", t, func() {
-		accountName := GenerateAccountName("134", 8)
-		bExist, err := AccountIsExist(accountName)
-		So(err, ShouldBeNil)
-		So(bExist, ShouldBeFalse)
-	})
-}
-
-//func TestDeleteAccount_121(t *testing.T) {
-//	Convey("删除已存在账号", t, func() {
-//		accountName := GenerateAccountName("121", 8)
-//		So(deleteAccount(SystemAccount, SystemAccountPriKey, accountName), ShouldBeTrue)
-//	})
-//}
-//
-//func TestDeleteAccount_122(t *testing.T) {
-//	Convey("删除不存在账号", t, func() {
-//		accountName := GenerateAccountName("122", 8)
-//		_, prikey := GeneratePubKey()
-//		So(deleteNotExistAcount(accountName, prikey), ShouldBeFalse)
-//	})
-//}
-
-//func deleteAccount(fromname string, fromprikey *ecdsa.PrivateKey, newname string) bool {
-//	result, _, prikey := CreateNewAccountWithName(fromname, fromprikey, newname)
-//	if !result {
-//		return false
-//	}
-//	return DeleteAcountWithResult(common.Name(newname), prikey)
-//}
-//
-//func deleteNotExistAcount(fromname string, fromprikey *ecdsa.PrivateKey) bool {
-//	return DeleteAcountWithResult(common.Name(fromname), fromprikey)
-//}
diff --git a/test/systemtestcase/asset_test.go b/test/systemtestcase/asset_test.go
deleted file mode 100644
index 25bdd4f6..00000000
--- a/test/systemtestcase/asset_test.go
+++ /dev/null
@@ -1,252 +0,0 @@
-// Copyright 2018 The Fractal Team Authors
-// This file is part of the fractal project.
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-package main
-
-import (
-	"math/big"
-	"testing"
-
-	. "github.com/fractalplatform/fractal/test/systemtestcase/rpc"
-	. "github.com/smartystreets/goconvey/convey"
-)
-
-func TestIssueAsset_211_1(t *testing.T) {
-	amount := new(big.Int).SetUint64(1000000000)
-	decimals := uint64(18)
-
-	Convey("系统账户创建资产,无收款方", t, func() {
-		assetName := GenerateAssetName("211", 8)
-		symbol := assetName
-		fromAccount := SystemAccount
-		ownerAccount := SystemAccount
-		fromPriKey := SystemAccountPriKey
-		So(IssueAsset(fromAccount, ownerAccount, fromPriKey, "", assetName, symbol, amount, decimals), ShouldBeNil)
-	})
-}
-
-func TestIssueAsset_211_2(t *testing.T) {
-
-	Convey("普通账户创建资产,无收款方", t, func() {
-		newAccount, err := GenerateValidAccountName("211", 8)
-		So(err, ShouldBeNil)
-
-		assetName := GenerateAssetName("211", 8)
-		symbol := assetName
-		amount := new(big.Int).SetUint64(1000000000)
-		decimals := uint64(18)
-		_, err = IssueAssetWithValidAccount(newAccount, newAccount, "", assetName, symbol, amount, decimals)
-		So(err, ShouldBeNil)
-	})
-}
-
-func TestIssueAsset_212(t *testing.T) {
-	Convey("系统账户创建资产,带收款方", t, func() {
-		assetName := GenerateAssetName("211", 8)
-		symbol := assetName
-		amount := new(big.Int).SetUint64(1000000000)
-		decimals := uint64(18)
-		So(IssueAsset(SystemAccount, SystemAccount, SystemAccountPriKey, "toaccount", assetName, symbol, amount, decimals), ShouldNotBeNil)
-	})
-}
-
-func TestIssueAsset_213(t *testing.T) {
-	Convey("系统账户重复创建资产,无收款方", t, func() {
-		assetName := GenerateAssetName("213", 8)
-		symbol := assetName
-		amount := new(big.Int).SetUint64(1000000000)
-		decimals := uint64(18)
-		So(IssueAsset(SystemAccount, SystemAccount, SystemAccountPriKey, "", assetName, symbol, amount, decimals), ShouldBeNil)
-		So(IssueAsset(SystemAccount, SystemAccount, SystemAccountPriKey, "", assetName, symbol, amount, decimals), ShouldNotBeNil)
-	})
-}
-
-func TestIncreaseAsset_221(t *testing.T) {
-	Convey("普通账户创建资产后,增发一定数量的资产", t, func() {
-		newAccount, err := GenerateValidAccountName("221", 8)
-		So(err, ShouldBeNil)
-
-		assetName := GenerateAssetName("221", 8)
-		symbol := assetName
-		amount := new(big.Int).SetUint64(1000000000)
-		decimals := uint64(18)
-		newPriKey, err := IssueAssetWithValidAccount(newAccount, newAccount, "", assetName, symbol, amount, decimals)
-		So(err, ShouldBeNil)
-		So(IncreaseAsset(newAccount, newPriKey, assetName, amount), ShouldBeNil)
-	})
-}
-
-func TestIncreaseAsset_222(t *testing.T) {
-
-}
-
-func TestModifyAssetOwner_231(t *testing.T) {
-	Convey("普通账户创建资产后,将资产Owner设置为新的账户", t, func() {
-		accountName, err := GenerateValidAccountName("231", 8)
-		So(err, ShouldBeNil)
-
-		assetName := GenerateAssetName("231", 8)
-		symbol := assetName
-		amount := new(big.Int).SetUint64(1000000000)
-		decimals := uint64(18)
-		newPriKey, err := IssueAssetWithValidAccount(accountName, accountName, "", assetName, symbol, amount, decimals)
-		So(err, ShouldBeNil)
-
-		newAccountName, err := GenerateValidAccountName("231", 8)
-		So(err, ShouldBeNil)
-		So(createNewAccount(SystemAccount, SystemAccountPriKey, newAccountName), ShouldBeNil)
-
-		So(SetAssetNewOwner(accountName, assetName, newAccountName, newPriKey), ShouldBeNil)
-	})
-}
-
-func TestModifyAssetOwner_232(t *testing.T) {
-	Convey("普通账户创建资产后,将资产Owner设置为新的账户", t, func() {
-		accountName, err := GenerateValidAccountName("231", 8)
-		So(err, ShouldBeNil)
-
-		assetName := GenerateAssetName("231", 8)
-		symbol := assetName
-		amount := new(big.Int).SetUint64(1000000000)
-		decimals := uint64(18)
-		newPriKey, err := IssueAssetWithValidAccount(accountName, accountName, "", assetName, symbol, amount, decimals)
-		So(err, ShouldBeNil)
-
-		newAccountName := GenerateAccountName("231", 8)
-
-		So(SetAssetNewOwner(accountName, assetName, newAccountName, newPriKey), ShouldNotBeNil)
-	})
-}
-
-func TestTransferAsset_241(t *testing.T) {
-	Convey("系统账户向普通账户转其已有的资产,", t, func() {
-		newAccountName, err := GenerateValidAccountName("241", 8)
-		So(err, ShouldBeNil)
-		So(createNewAccount(SystemAccount, SystemAccountPriKey, newAccountName), ShouldBeNil)
-
-		So(TransferAsset(SystemAccount, newAccountName, 1, 10000000, SystemAccountPriKey), ShouldBeNil)
-		So(TransferAsset(SystemAccount, newAccountName, 1, 10000000, SystemAccountPriKey), ShouldBeNil)
-	})
-}
-
-func TestTransferAsset_242(t *testing.T) {
-	Convey("系统账户向普通账户转其未曾有过的的资产,", t, func() {
-		newAccountName, err := GenerateValidAccountName("241", 8)
-		So(err, ShouldBeNil)
-		So(createNewAccount(SystemAccount, SystemAccountPriKey, newAccountName), ShouldBeNil)
-
-		So(TransferAsset(SystemAccount, newAccountName, 1, 10000000, SystemAccountPriKey), ShouldBeNil)
-	})
-}
-
-func TestTransferAsset_243(t *testing.T) {
-	Convey("系统账户向不存在的账户转资产,", t, func() {
-		newAccountName, err := GenerateValidAccountName("242", 8)
-		So(err, ShouldBeNil)
-
-		So(TransferAsset(SystemAccount, newAccountName, 1, 10000000, SystemAccountPriKey), ShouldNotBeNil)
-	})
-}
-
-func TestTransferAsset_244(t *testing.T) {
-	Convey("系统账户向普通账户转未曾创建过的的资产,", t, func() {
-		newAccountName, err := GenerateValidAccountName("241", 8)
-		So(err, ShouldBeNil)
-		So(createNewAccount(SystemAccount, SystemAccountPriKey, newAccountName), ShouldBeNil)
-
-		notExistAssetId := GetNextAssetIdFrom(1)
-		So(TransferAsset(SystemAccount, newAccountName, notExistAssetId, 10000000, SystemAccountPriKey), ShouldNotBeNil)
-	})
-}
-
-func TestTransferAsset_245(t *testing.T) {
-	Convey("系统账户将其未拥有过的资产转给其它账号", t, func() {
-		newAccountName, err := GenerateValidAccountName("241", 8)
-		So(err, ShouldBeNil)
-		So(createNewAccount(SystemAccount, SystemAccountPriKey, newAccountName), ShouldBeNil)
-		notOwnedAssetId := GetNextAssetIdFrom(1) - 1
-
-		for notOwnedAssetId > 0 {
-			balance, _ := GetAssetBalanceByID(SystemAccount, notOwnedAssetId)
-			if balance.Cmp(big.NewInt(0)) == 0 {
-				break
-			}
-			notOwnedAssetId--
-		}
-
-		So(TransferAsset(SystemAccount, newAccountName, notOwnedAssetId, 1, SystemAccountPriKey), ShouldNotBeNil)
-	})
-}
-
-func TestTransferAsset_246(t *testing.T) {
-	Convey("系统账户向普通账户转账金额超过其余额", t, func() {
-		newAccountName, err := GenerateValidAccountName("241", 8)
-		So(err, ShouldBeNil)
-		So(createNewAccount(SystemAccount, SystemAccountPriKey, newAccountName), ShouldBeNil)
-
-		balance, _ := GetAssetBalanceByID(SystemAccount, 1)
-		So(TransferAsset(SystemAccount, newAccountName, 1, balance.Int64()+1, SystemAccountPriKey), ShouldNotBeNil)
-	})
-}
-
-func TestTransferAsset_247(t *testing.T) {
-	Convey("给自己转账", t, func() {
-
-	})
-}
-
-func TestTransferAsset_25_1to5(t *testing.T) {
-
-	Convey("查询资产相关信息", t, func() {
-
-		amount := new(big.Int).SetUint64(1000000000)
-		decimals := uint64(18)
-		assetName := GenerateAssetName("211", 8)
-		symbol := assetName
-		assetId := uint64(0)
-		oldAccount := GetAccountByName(SystemAccount)
-		So(len(oldAccount.Balances) > 0, ShouldBeTrue)
-
-		So(IssueAsset(SystemAccount, SystemAccount, SystemAccountPriKey, "", assetName, symbol, amount, decimals), ShouldBeNil)
-		Convey("1:通过资产名称查询资产id", func() {
-			assetInfo, err := GetAssetInfoByName(assetName)
-			So(err, ShouldBeNil)
-			assetId = assetInfo.AssetId
-			So(assetId > 0, ShouldBeTrue)
-
-			Convey("2:通过资产ID查询资产对象", func() {
-				assetInfo, err := GetAssetInfoById(assetId)
-				So(err, ShouldBeNil)
-				So(assetInfo.AssetId == assetId, ShouldBeTrue)
-				So(assetInfo.AssetName == assetName, ShouldBeTrue)
-			})
-			Convey("3:查询某账户拥有的资产数量", func() {
-				newAccount := GetAccountByName(SystemAccount)
-				So(len(newAccount.Balances)-len(oldAccount.Balances) == 1, ShouldBeTrue)
-			})
-			Convey("4:查询所有资产数量", func() {
-				maxAssetId := GetNextAssetIdFrom(1) - 1
-				So(assetId == maxAssetId, ShouldBeTrue)
-			})
-			Convey("5:通过资产名称查询资产对象", func() {
-				assetInfo, err := GetAssetInfoByName(assetName)
-				So(err, ShouldBeNil)
-				So(assetInfo.AssetId == assetId, ShouldBeTrue)
-				So(assetInfo.AssetName == assetName, ShouldBeTrue)
-			})
-		})
-	})
-}
diff --git a/test/systemtestcase/dpos_test.go b/test/systemtestcase/dpos_test.go
deleted file mode 100644
index a735128b..00000000
--- a/test/systemtestcase/dpos_test.go
+++ /dev/null
@@ -1,110 +0,0 @@
-// Copyright 2018 The Fractal Team Authors
-// This file is part of the fractal project.
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-package main
-
-import (
-	"testing"
-
-	. "github.com/smartystreets/goconvey/convey"
-)
-
-func TestRegProducer(t *testing.T) {
-	Convey("注册生成者", t, func() {
-		Convey("生产者", func() {
-			Convey("已是投票者", func() {
-
-			})
-			Convey("已是生产者", func() {
-
-			})
-		})
-		Convey("URL长度", func() {
-			Convey("不满足", func() {
-
-			})
-			Convey("满足", func() {
-
-			})
-		})
-		Convey("最低数量要求", func() {
-			Convey("不满足", func() {
-
-			})
-			Convey("满足", func() {
-
-			})
-		})
-	})
-}
-
-func TestUpdateProducer(t *testing.T) {
-	Convey("更新生成者", t, func() {
-		Convey("生产者", func() {
-			Convey("已是投票者", func() {
-
-			})
-			Convey("不是生产者", func() {
-
-			})
-		})
-		Convey("URL长度", func() {
-			Convey("不满足", func() {
-
-			})
-			Convey("满足", func() {
-
-			})
-		})
-		Convey("最低数量要求", func() {
-			Convey("不满足", func() {
-
-			})
-			Convey("满足", func() {
-
-			})
-		})
-	})
-}
-
-func TestUnRegProducer(t *testing.T) {
-	Convey("注销生成者", t, func() {
-		Convey("生产者", func() {
-			Convey("已是投票者", func() {
-
-			})
-			Convey("不是生产者", func() {
-
-			})
-		})
-		Convey("URL长度", func() {
-			Convey("不满足", func() {
-
-			})
-			Convey("满足", func() {
-
-			})
-		})
-		Convey("最低数量要求", func() {
-			Convey("不满足", func() {
-
-			})
-			Convey("满足", func() {
-
-			})
-		})
-	})
-}
diff --git a/test/systemtestcase/rpc/accountAPI.go b/test/systemtestcase/rpc/accountAPI.go
deleted file mode 100644
index 8017d958..00000000
--- a/test/systemtestcase/rpc/accountAPI.go
+++ /dev/null
@@ -1,147 +0,0 @@
-// Copyright 2018 The Fractal Team Authors
-// This file is part of the fractal project.
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-package rpc
-
-import (
-	"crypto/ecdsa"
-	"errors"
-	"strconv"
-
-	"github.com/fractalplatform/fractal/accountmanager"
-	"github.com/fractalplatform/fractal/common"
-	"github.com/fractalplatform/fractal/types"
-)
-
-func createAccount(fromAccount string, fromPriKey *ecdsa.PrivateKey, newAccountName string) (common.Hash, common.PubKey, *ecdsa.PrivateKey, error) {
-	accountName := common.Name(fromAccount)
-	nonce, err := GetNonce(accountName)
-	if err != nil {
-		return common.Hash{}, common.PubKey{}, nil, err
-	}
-	createdAccountName := common.Name(newAccountName)
-	pubkey, priKey := GeneratePubKey()
-	gc := NewGeAction(types.CreateAccount, accountName, createdAccountName, nonce, 1, Gaslimit, nil, pubkey[:], fromPriKey)
-	var gcs []*GenAction
-	gcs = append(gcs, gc)
-	txHash, err := SendTxTest(gcs)
-	return txHash, pubkey, priKey, err
-}
-
-func AccountIsExist(accountName string) (bool, error) {
-	isExist := new(bool)
-	err := ClientCall("account_accountIsExist", isExist, accountName)
-	if err != nil {
-		return false, err
-	}
-	return *isExist, nil
-}
-
-func GetAccountInfo(accountName string) bool {
-	account := &accountmanager.Account{}
-	ClientCall("account_getAccountByName", account, accountName)
-	return len(account.AcctName.String()) > 0
-}
-
-func GetAccountByName(accountName string) accountmanager.Account {
-	account := &accountmanager.Account{}
-	ClientCall("account_getAccountByName", account, accountName)
-	return *account
-}
-
-func CreateNewAccountWithName(fromAccount string, fromPriKey *ecdsa.PrivateKey, newAccountName string) (error, common.PubKey, *ecdsa.PrivateKey) {
-	txHash, pubKey, priKey, err := createAccount(fromAccount, fromPriKey, newAccountName)
-	if err != nil {
-		return errors.New("创建账户交易失败:" + err.Error()), pubKey, priKey
-	}
-	maxTime := uint(60)
-	receipt, outOfTime, err := DelayGetReceiptByTxHash(txHash, maxTime)
-	if err != nil {
-		return errors.New("获取交易receipt失败:" + err.Error()), pubKey, priKey
-	}
-	if outOfTime {
-		return errors.New("无法在" + strconv.Itoa(int(maxTime)) + "秒内获取交易receipt"), pubKey, priKey
-	}
-	if len(receipt.ActionResults) == 0 || receipt.ActionResults[0].Status == 0 {
-		return errors.New("创建账户失败"), pubKey, priKey
-	}
-
-	bExist, err := AccountIsExist(newAccountName)
-	if err != nil {
-		return errors.New("无法查询到创建的账户:" + err.Error()), pubKey, priKey
-	}
-	if !bExist {
-		return errors.New("无法查询到创建的账户"), pubKey, priKey
-	}
-
-	return nil, pubKey, priKey
-
-}
-
-//
-//func deleteAcount(fromName common.Name, fromprikey *ecdsa.PrivateKey) (common.Hash, error) {
-//	nonce, err := GetNonce(fromName)
-//	if err != nil {
-//		return common.Hash{}, err
-//	}
-//	gc := NewGeAction(types.DeleteAccount, fromName, "", nonce, 1, Gaslimit, nil, nil, fromprikey)
-//	var gcs []*GenAction
-//	gcs = append(gcs, gc)
-//	hash, err := SendTxTest(gcs)
-//	if err != nil {
-//		return common.Hash{}, err
-//	}
-//	return hash, nil
-//}
-
-//func DeleteAcountWithResult(fromName common.Name, fromprikey *ecdsa.PrivateKey) bool {
-//	txHash, err := deleteAcount(fromName, fromprikey)
-//	if err != nil {
-//		return false
-//	}
-//	receipt, outOfTime := DelayGetReceiptByTxHash(txHash, 60)
-//
-//	if outOfTime || len(receipt.ActionResults) == 0 || receipt.ActionResults[0].Status == 0 {
-//		return false
-//	}
-//	return AccountIsExist(string(fromName))
-//}
-
-func GenerateAccountName(namePrefix string, addStrLen int) string {
-	return GenerateRandomName(namePrefix, addStrLen)
-}
-
-func GenerateValidAccountName(namePrefix string, suffixStrLen int) (string, error) {
-	maxTime := 10
-	for maxTime > 0 {
-		newAccountName := GenerateAccountName(namePrefix, suffixStrLen)
-		bExist, err := AccountIsExist(newAccountName)
-		if err != nil {
-			return "", errors.New("判断账号是否存在的RPC接口调用失败:" + err.Error())
-		}
-		if !bExist {
-			return newAccountName, nil
-		}
-		maxTime--
-	}
-	return "", errors.New("难以获得有效的账户名")
-}
-
-func GenerateValidAccountNameAndKey(namePrefix string, suffixStrLen int) (string, common.PubKey, *ecdsa.PrivateKey, error) {
-	pubKey, priKey := GeneratePubKey()
-	accountName, err := GenerateValidAccountName(namePrefix, suffixStrLen)
-	return accountName, pubKey, priKey, err
-}
diff --git a/test/systemtestcase/rpc/assetAPI.go b/test/systemtestcase/rpc/assetAPI.go
deleted file mode 100644
index 00912909..00000000
--- a/test/systemtestcase/rpc/assetAPI.go
+++ /dev/null
@@ -1,313 +0,0 @@
-// Copyright 2018 The Fractal Team Authors
-// This file is part of the fractal project.
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-package rpc
-
-import (
-	"crypto/ecdsa"
-	"errors"
-	"github.com/fractalplatform/fractal/utils/rlp"
-	"math/big"
-	"strconv"
-
-	"github.com/fractalplatform/fractal/asset"
-	"github.com/fractalplatform/fractal/common"
-	"github.com/fractalplatform/fractal/types"
-)
-
-func transfer(from, to string, assetId uint64, amount *big.Int, prikey *ecdsa.PrivateKey) (common.Hash, error) {
-	nonce, err := GetNonce(common.Name(from))
-	if err != nil {
-		return common.Hash{}, err
-	}
-	gc := NewGeAction(types.Transfer, common.Name(from), common.Name(to), nonce, assetId, Gaslimit, amount, nil, prikey)
-	var gcs []*GenAction
-	gcs = append(gcs, gc)
-	return SendTxTest(gcs)
-}
-
-// GetAccountBalanceByID get balance by address ,assetID and number.
-func GetAssetBalanceByID(accountName string, assetID uint64) (*big.Int, error) {
-	balance := big.NewInt(0)
-	err := ClientCall("account_getAccountBalanceByID", balance, common.Name(accountName), assetID)
-	return balance, err
-}
-
-//GetAssetInfoByName get assetINfo by accountName
-func GetAssetInfoByName(assetName string) (*asset.AssetObject, error) {
-	assetInfo := &asset.AssetObject{}
-	err := ClientCall("account_getAssetInfoByName", assetInfo, assetName)
-	return assetInfo, err
-}
-
-func GetAssetInfoById(assetID uint64) (*asset.AssetObject, error) {
-	assetInfo := &asset.AssetObject{}
-	err := ClientCall("account_getAssetInfoByID", assetInfo, assetID)
-	return assetInfo, err
-}
-
-func IsAssetExist(assetName string) (bool, error) {
-	assetObj, err := GetAssetInfoByName(assetName)
-	return assetObj.AssetName == assetName, err
-}
-
-func TransferAsset(fromAccountName, toAccountName string, assetId uint64, amount int64, prikey *ecdsa.PrivateKey) error {
-	oldAssetAmount, _ := GetAssetBalanceByID(toAccountName, assetId)
-
-	hash, err := transfer(fromAccountName, toAccountName, assetId, big.NewInt(amount), prikey)
-	if err != nil {
-		return errors.New("转账交易失败(未进txpool):" + err.Error())
-	}
-	maxTime := uint(60)
-	receipt, outOfTime, err := DelayGetReceiptByTxHash(hash, maxTime)
-	if err != nil {
-		return errors.New("获取交易receipt失败:" + err.Error())
-	}
-	if outOfTime {
-		return errors.New("无法在" + strconv.Itoa(int(maxTime)) + "秒内获取交易receipt")
-	}
-	if len(receipt.ActionResults) == 0 || receipt.ActionResults[0].Status == 0 {
-		return errors.New("转账失败")
-	}
-	//str, _  := json.Marshal(receipt)
-	//fmt.Println(string(str))
-
-	newAssetAmount, err := GetAssetBalanceByID(toAccountName, assetId)
-	if err != nil {
-		return errors.New("转账后无法获取目标账户的资产余额:" + err.Error())
-	}
-
-	if newAssetAmount.Sub(newAssetAmount, oldAssetAmount).Cmp(big.NewInt(amount)) != 0 {
-		return errors.New("转账后资产余额差不等于转账金额")
-	}
-	return nil
-}
-
-func IssueAssetWithValidAccount(fromAccount string, owner string, toAccount string, assetName string, symbol string, amount *big.Int, decimals uint64) (*ecdsa.PrivateKey, error) {
-	err, _, priKey := CreateNewAccountWithName(SystemAccount, SystemAccountPriKey, fromAccount)
-	if err != nil {
-		return nil, errors.New("创建新账号失败:" + err.Error())
-	}
-	err = TransferAsset(SystemAccount, fromAccount, 1, 1000000000000000, SystemAccountPriKey)
-	if err != nil {
-		return nil, errors.New("创建新账号成功,但用系统账户给新账号转账出错:" + err.Error())
-	}
-
-	err = IssueAsset(fromAccount, owner, priKey, toAccount, assetName, symbol, amount, decimals)
-	if err != nil {
-		return nil, errors.New("有足够余额的新账号无法创建资产:" + err.Error())
-	}
-	return priKey, nil
-}
-
-func IssueAsset(fromAccount string, owner string, fromPrikey *ecdsa.PrivateKey, toAccount string, assetName string, symbol string, amount *big.Int, decimals uint64) error {
-	nonce, err := GetNonce(common.Name(fromAccount))
-	if err != nil {
-		return errors.New("获取nonce失败:" + err.Error())
-	}
-
-	txHash, err := issueAsset(common.Name(fromAccount), common.Name(owner), amount, assetName, symbol, nonce, decimals, fromPrikey)
-	if err != nil {
-		return errors.New("发布资产的交易失败:" + err.Error())
-	}
-
-	maxTime := uint(60)
-	receipt, outOfTime, err := DelayGetReceiptByTxHash(txHash, maxTime)
-	if err != nil {
-		return errors.New("获取交易receipt失败:" + err.Error())
-	}
-	if outOfTime {
-		return errors.New("无法在" + strconv.Itoa(int(maxTime)) + "秒内获取交易receipt")
-	}
-	if len(receipt.ActionResults) == 0 || receipt.ActionResults[0].Status == 0 {
-		return errors.New("发布资产失败")
-	}
-
-	bExist, err := IsAssetExist(assetName)
-	if err != nil {
-		return errors.New("判断资产是否存在的RPC接口调用失败:" + err.Error())
-	}
-	if bExist {
-		return nil
-	} else {
-		return errors.New("无法查到新发行的资产")
-	}
-}
-
-func IncreaseAsset(fromAccount string, fromPrikey *ecdsa.PrivateKey, assetName string, increasedAmount *big.Int) error {
-	assetObj, err := GetAssetInfoByName(assetName)
-	if err != nil {
-		return errors.New("通过资产名获取资产信息失败(增发前):" + err.Error())
-	}
-
-	nonce, err := GetNonce(common.Name(fromAccount))
-	if err != nil {
-		return errors.New("获取账户nonce失败:" + err.Error())
-	}
-
-	txhash, err := increaseAsset(common.Name(fromAccount), "", assetObj.AssetId, increasedAmount, nonce, fromPrikey)
-	if err != nil {
-		return errors.New("发送增发资产的交易失败:" + err.Error())
-	}
-
-	maxTime := uint(60)
-	receipt, outOfTime, err := DelayGetReceiptByTxHash(txhash, maxTime)
-	if err != nil {
-		return errors.New("获取交易receipt失败:" + err.Error())
-	}
-	if outOfTime {
-		return errors.New("无法在" + strconv.Itoa(int(maxTime)) + "秒内获取交易receipt")
-	}
-	if len(receipt.ActionResults) == 0 || receipt.ActionResults[0].Status == 0 {
-		return errors.New("增发资产的交易执行失败")
-	}
-
-	newAssetObj, err := GetAssetInfoByName(assetName)
-	if err != nil {
-		return errors.New("通过资产名获取资产信息失败(增发成功后):" + err.Error())
-	}
-	if new(big.Int).Sub(newAssetObj.Amount, assetObj.Amount).Cmp(increasedAmount) != 0 {
-		return errors.New("增发的资产数额不对")
-	}
-	return nil
-}
-
-// just send a tx
-func issueAsset(from, owner common.Name, amount *big.Int, assetName string, symbol string, nonce uint64, decimals uint64, prikey *ecdsa.PrivateKey) (common.Hash, error) {
-	asset := &asset.AssetObject{
-		AssetName: assetName,
-		Symbol:    symbol,
-		Amount:    amount,
-		Decimals:  decimals,
-		Owner:     owner,
-	}
-	payload, err := rlp.EncodeToBytes(asset)
-	if err != nil {
-		return common.Hash{}, err
-	}
-	gc := NewGeAction(types.IssueAsset, from, "", nonce, 1, Gaslimit, nil, payload, prikey)
-	var gcs []*GenAction
-	gcs = append(gcs, gc)
-	return SendTxTest(gcs)
-}
-
-// just send a tx
-func increaseAsset(from common.Name, to common.Name, assetId uint64, increasedAmount *big.Int, nonce uint64, prikey *ecdsa.PrivateKey) (common.Hash, error) {
-	ast := &asset.AssetObject{
-		AssetId:   assetId,
-		AssetName: "",
-		Symbol:    "",
-		Amount:    increasedAmount,
-	}
-	payload, err := rlp.EncodeToBytes(ast)
-	if err != nil {
-		return common.Hash{}, err
-	}
-	gc := NewGeAction(types.IncreaseAsset, from, to, nonce, assetId, Gaslimit, nil, payload, prikey)
-	var gcs []*GenAction
-	gcs = append(gcs, gc)
-	return SendTxTest(gcs)
-}
-
-func SetAssetNewOwner(fromAccount string, assetName string, newOwner string, priKey *ecdsa.PrivateKey) error {
-	assetObj, err := GetAssetInfoByName(assetName)
-	if err != nil {
-		return errors.New("无法通过资产名获取资产信息:" + err.Error())
-	}
-	txHash, err := setAssetOwner(common.Name(fromAccount), common.Name(newOwner), assetObj.AssetId, priKey)
-	if err != nil {
-		return errors.New("发送修改资产Owner的交易失败:" + err.Error())
-	}
-
-	maxTime := uint(60)
-	receipt, outOfTime, err := DelayGetReceiptByTxHash(txHash, maxTime)
-	if err != nil {
-		return errors.New("获取交易receipt失败:" + err.Error())
-	}
-	if outOfTime {
-		return errors.New("无法在" + strconv.Itoa(int(maxTime)) + "秒内获取交易receipt")
-	}
-	if len(receipt.ActionResults) == 0 || receipt.ActionResults[0].Status == 0 {
-		return errors.New("发送修改资产Owner的交易执行失败")
-	}
-
-	newAssetObj, err := GetAssetInfoByName(assetName)
-	if err != nil {
-		return errors.New("通过资产名获取资产信息失败(修改Owner成功后):" + err.Error())
-	}
-	if newAssetObj.Owner.String() != newOwner {
-		return errors.New("资产Owner跟预期设置的Owner不一致")
-	}
-	return nil
-}
-
-func setAssetOwner(from, newOwner common.Name, assetId uint64, prikey *ecdsa.PrivateKey) (common.Hash, error) {
-	ast := &asset.AssetObject{
-		AssetId: assetId,
-		Owner:   newOwner,
-	}
-	payload, err := rlp.EncodeToBytes(ast)
-	if err != nil {
-		return common.Hash{}, err
-	}
-	nonce, err := GetNonce(common.Name(from))
-	if err != nil {
-		return common.Hash{}, err
-	}
-
-	gc := NewGeAction(types.SetAssetOwner, from, "", nonce, assetId, Gaslimit, nil, payload, prikey)
-	var gcs []*GenAction
-	gcs = append(gcs, gc)
-	return SendTxTest(gcs)
-}
-
-func GenerateAssetName(namePrefix string, addStrLen int) string {
-	return GenerateRandomName(namePrefix, addStrLen)
-}
-
-func GetNextAssetIdFrom(fromAssetId uint64) uint64 {
-	if fromAssetId == 0 {
-		fromAssetId = 1
-	}
-	for {
-		assetInfo, err := GetAssetInfoById(fromAssetId)
-		if err != nil {
-			return 0
-		}
-		if assetInfo.AssetId > 0 {
-			fromAssetId++
-		} else {
-			return fromAssetId
-		}
-	}
-}
-
-func GenerateValidAssetName(namePrefix string, suffixStrLen int) (string, error) {
-	maxTime := 10
-	for maxTime > 0 {
-		newAssetName := GenerateAssetName(namePrefix, suffixStrLen)
-		bExist, err := IsAssetExist(newAssetName)
-		if err != nil {
-			return "", errors.New("判断资产是否存在的RPC接口调用失败:" + err.Error())
-		}
-		if !bExist {
-			return newAssetName, nil
-		}
-		maxTime--
-	}
-	return "", errors.New("难以获得有效的资产名")
-
-}
diff --git a/test/systemtestcase/rpc/transactionAPI.go b/test/systemtestcase/rpc/transactionAPI.go
deleted file mode 100644
index cd562fec..00000000
--- a/test/systemtestcase/rpc/transactionAPI.go
+++ /dev/null
@@ -1,62 +0,0 @@
-// Copyright 2018 The Fractal Team Authors
-// This file is part of the fractal project.
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-package rpc
-
-import (
-	"fmt"
-	"time"
-
-	"github.com/fractalplatform/fractal/common"
-	"github.com/fractalplatform/fractal/types"
-)
-
-func GetReceiptByTxHash(hash common.Hash) (*types.RPCReceipt, error) {
-	receipt := &types.RPCReceipt{}
-	err := ClientCall("ft_getTransactionReceipt", receipt, hash.Hex())
-
-	return receipt, err
-}
-
-func DelayGetReceiptByTxHash(txHash common.Hash, maxTime uint) (*types.RPCReceipt, bool, error) {
-	for maxTime > 0 {
-		time.Sleep(time.Duration(1) * time.Second)
-		receipt, err := GetReceiptByTxHash(txHash)
-		if err != nil {
-			fmt.Println("DelayGetReceiptByTxHash:" + err.Error())
-			return nil, false, err
-		}
-
-		//json, _ := json.Marshal(receipt)
-		//fmt.Println("DelayGetReceiptByTxHash:" + string(json))
-		if receipt.BlockNumber > 0 {
-			return receipt, false, nil
-		}
-		maxTime--
-	}
-	return &types.RPCReceipt{}, maxTime == 0, nil
-}
-
-func GetTxpoolStatus() (int, int) {
-	result := map[string]int{}
-	ClientCall("txpool_status", result)
-	return result["pending"], result["queue"]
-}
-
-func IsTxpoolFull() bool {
-	pendingTxNum, _ := GetTxpoolStatus()
-	return pendingTxNum >= MaxTxNumInTxpool
-}
diff --git a/test/systemtestcase/rpc/utils.go b/test/systemtestcase/rpc/utils.go
deleted file mode 100644
index 67166ec4..00000000
--- a/test/systemtestcase/rpc/utils.go
+++ /dev/null
@@ -1,178 +0,0 @@
-// Copyright 2018 The Fractal Team Authors
-// This file is part of the fractal project.
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-package rpc
-
-import (
-	"context"
-	"crypto/ecdsa"
-	"fmt"
-	"math/big"
-	"math/rand"
-	"os"
-	"os/user"
-	"path/filepath"
-	"runtime"
-	"sync"
-	"time"
-
-	"github.com/ethereum/go-ethereum/common/hexutil"
-	"github.com/fractalplatform/fractal/common"
-	"github.com/fractalplatform/fractal/crypto"
-	"github.com/fractalplatform/fractal/params"
-	"github.com/fractalplatform/fractal/types"
-	"github.com/fractalplatform/fractal/utils/rlp"
-)
-
-import (
-	"github.com/fractalplatform/fractal/rpc"
-)
-
-var (
-	once           sync.Once
-	clientInstance *rpc.Client
-	hostIp         = "192.168.2.13" // "127.0.0.1" //
-	port           = 8090           // 8545 //
-	gasPrice       = big.NewInt(2000000)
-)
-
-type GenAction struct {
-	*types.Action
-	PrivateKey *ecdsa.PrivateKey
-}
-
-// DefultURL default rpc url
-func DefultURL() string {
-	return fmt.Sprintf("http://%s:%d", hostIp, port)
-}
-
-func GeneratePubKey() (common.PubKey, *ecdsa.PrivateKey) {
-	prikey, _ := crypto.GenerateKey()
-	return common.BytesToPubKey(crypto.FromECDSAPub(&prikey.PublicKey)), prikey
-}
-
-func NewGeAction(at types.ActionType, from, to common.Name, nonce uint64, assetid uint64, gaslimit uint64, amount *big.Int, payload []byte, prikey *ecdsa.PrivateKey) *GenAction {
-	action := types.NewAction(at, from, to, nonce, assetid, gaslimit, amount, payload)
-	return &GenAction{
-		Action:     action,
-		PrivateKey: prikey,
-	}
-}
-func SendTxTest(gcs []*GenAction) (common.Hash, error) {
-	//nonce := GetNonce(sendaddr, "latest")
-	signer := types.NewSigner(params.DefaultChainconfig.ChainID)
-	var actions []*types.Action
-	for _, v := range gcs {
-		actions = append(actions, v.Action)
-	}
-	tx := types.NewTransaction(uint64(1), gasPrice, actions...)
-	for _, v := range gcs {
-		err := types.SignAction(v.Action, tx, signer, v.PrivateKey)
-		if err != nil {
-			return common.Hash{}, err
-		}
-	}
-	rawtx, _ := rlp.EncodeToBytes(tx)
-	hash, err := SendRawTx(rawtx)
-	return hash, err
-}
-
-//SendRawTx send raw transaction
-func SendRawTx(rawTx []byte) (common.Hash, error) {
-	hash := new(common.Hash)
-	err := ClientCall("ft_sendRawTransaction", hash, hexutil.Bytes(rawTx))
-	return *hash, err
-}
-
-// MustRPCClient Wraper rpc's client
-func MustRPCClient() (*rpc.Client, error) {
-	once.Do(func() {
-		client, err := rpc.DialHTTP(DefultURL())
-		if err != nil {
-			return
-		}
-		clientInstance = client
-	})
-
-	return clientInstance, nil
-}
-
-// ClientCall Wrapper rpc call api.
-func ClientCall(method string, result interface{}, args ...interface{}) error {
-	client, err := MustRPCClient()
-	if err != nil {
-		return err
-	}
-	err = client.CallContext(context.Background(), result, method, args...)
-	if err != nil {
-		return err
-	}
-	return nil
-}
-
-// GasPrice suggest gas price
-func GasPrice() (*big.Int, error) {
-	gp := big.NewInt(0)
-	err := ClientCall("ft_gasPrice", gp)
-	return gp, err
-}
-
-// GetNonce get nonce by address and block number.
-func GetNonce(accountname common.Name) (uint64, error) {
-	nonce := new(uint64)
-	err := ClientCall("account_getNonce", nonce, accountname)
-	return *nonce, err
-}
-
-// defaultDataDir is the default data directory to use for the databases and other
-// persistence requirements.
-func DefaultDataDir() string {
-	// Try to place the data folder in the user's home dir
-	home := HomeDir()
-	if home != "" {
-		if runtime.GOOS == "darwin" {
-			return filepath.Join(home, "Library", "pi_ledger")
-		} else if runtime.GOOS == "windows" {
-			return filepath.Join(home, "AppData", "Roaming", "pi_ledger")
-		} else {
-			return filepath.Join(home, ".pi_ledger")
-		}
-	}
-	// As we cannot guess a stable location, return empty and handle later
-	return ""
-}
-
-func HomeDir() string {
-	if home := os.Getenv("HOME"); home != "" {
-		return home
-	}
-	if usr, err := user.Current(); err == nil {
-		return usr.HomeDir
-	}
-	return ""
-}
-
-func GenerateRandomName(namePrefix string, addStrLen int) string {
-	newRandomName := namePrefix
-	var str string = "abcdefghijklmnopqrstuvwxyz0123456789"
-	size := len(str)
-	rand.Seed(time.Now().Unix())
-	for i := 0; i < addStrLen; i++ {
-		index := rand.Intn(10000) % size
-		newRandomName += string(str[index])
-	}
-	return newRandomName
-}
diff --git a/test/systemtestcase/transfer_test.go b/test/systemtestcase/transfer_test.go
deleted file mode 100644
index 06ab7d0f..00000000
--- a/test/systemtestcase/transfer_test.go
+++ /dev/null
@@ -1 +0,0 @@
-package main
diff --git a/test/transaction/sendtransaction.go b/test/transaction/sendtransaction.go
new file mode 100644
index 00000000..5daf9b97
--- /dev/null
+++ b/test/transaction/sendtransaction.go
@@ -0,0 +1,267 @@
+// Copyright 2018 The Fractal Team Authors
+// This file is part of the fractal project.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+package main
+
+import (
+	"crypto/ecdsa"
+	"fmt"
+	"math/big"
+	"time"
+
+	"github.com/fractalplatform/fractal/accountmanager"
+	"github.com/fractalplatform/fractal/asset"
+	"github.com/fractalplatform/fractal/common"
+	"github.com/fractalplatform/fractal/crypto"
+	"github.com/fractalplatform/fractal/types"
+	"github.com/fractalplatform/fractal/utils/rlp"
+	jww "github.com/spf13/jwalterweatherman"
+
+	tc "github.com/fractalplatform/fractal/test/common"
+)
+
+var (
+	minerprikey, _   = crypto.HexToECDSA("289c2857d4598e37fb9647507e47a309d6133539bf21a8b9cb6df88fd5232032")
+	minerpubkey      = common.HexToPubKey("0x047db227d7094ce215c3a0f57e1bcc732551fe351f94249471934567e0f5dc1bf795962b8cccb87a2eb56b29fbe37d614e2f4c3c45b789ae4f1f51f4cb21972ffd")
+	newPrivateKey, _ = crypto.HexToECDSA("8ee847ae5974a13ce9df66083e453ea1e0f7995379ed027a98e827aa8b6bc211")
+	gaslimit         = uint64(2000000)
+	minername        = common.Name("ftsystemio")
+	toname           = common.Name("testtest11")
+	issueAmount      = new(big.Int).Mul(big.NewInt(10), big.NewInt(1e10))
+	inCreateAmount   = big.NewInt(100000000)
+	indexstr         = "abcdefghijklmnopqrstuvwxyz0123456789"
+	basefrom         = "newnamefrom%s"
+	baseto           = "newnameto%s"
+	testbase         = "testtest"
+	testname1        = ""
+)
+
+type GenAction struct {
+	*types.Action
+	PrivateKey *ecdsa.PrivateKey
+}
+
+func init() {
+	jww.SetLogThreshold(jww.LevelTrace)
+	jww.SetStdoutThreshold(jww.LevelInfo)
+}
+
+func GeneragePubKey() (common.PubKey, *ecdsa.PrivateKey) {
+	prikey, _ := crypto.GenerateKey()
+	return common.BytesToPubKey(crypto.FromECDSAPub(&prikey.PublicKey)), prikey
+}
+
+func createAccount(accountName common.Name, founder common.Name, from, newname common.Name, nonce uint64, publickey common.PubKey, prikey *ecdsa.PrivateKey) {
+	account := &accountmanager.AccountAction{
+		AccountName: accountName,
+		Founder:     founder,
+		ChargeRatio: 80,
+		PublicKey:   publickey,
+	}
+	payload, err := rlp.EncodeToBytes(account)
+	if err != nil {
+		panic("rlp payload err")
+	}
+	to := newname
+	gc := newGeAction(types.CreateAccount, from, to, nonce, 1, gaslimit, nil, payload, prikey)
+	var gcs []*GenAction
+	gcs = append(gcs, gc)
+	sendTxTest(gcs)
+}
+
+func updateAccount(from, founder common.Name, nonce uint64, privatekey *ecdsa.PrivateKey) {
+	account := &accountmanager.AccountAction{
+		AccountName: from,
+		Founder:     founder,
+		ChargeRatio: 80,
+	}
+	payload, err := rlp.EncodeToBytes(account)
+	if err != nil {
+		panic("rlp payload err")
+	}
+	gc := newGeAction(types.UpdateAccount, from, "", nonce, 1, gaslimit, nil, payload, privatekey)
+	var gcs []*GenAction
+	gcs = append(gcs, gc)
+	sendTxTest(gcs)
+}
+
+func updateAccountAuthor(from common.Name, oldpubkey, newpubkey common.PubKey, nonce uint64, privatekey *ecdsa.PrivateKey) {
+	oldauthor := &common.Author{
+		Owner: oldpubkey,
+	}
+	oldauthoraction := &accountmanager.AuthorAction{accountmanager.DeleteAuthor, oldauthor}
+	newauthor := &common.Author{
+		Owner:  newpubkey,
+		Weight: 1,
+	}
+	newauthoraction := &accountmanager.AuthorAction{accountmanager.AddAuthor, newauthor}
+	accountauthor := &accountmanager.AccountAuthorAction{
+		AuthorActions: []*accountmanager.AuthorAction{oldauthoraction, newauthoraction},
+	}
+	payload, err := rlp.EncodeToBytes(accountauthor)
+	if err != nil {
+		panic("rlp payload err")
+	}
+	gc := newGeAction(types.UpdateAccountAuthor, from, "", nonce, 1, gaslimit, nil, payload, privatekey)
+	var gcs []*GenAction
+	gcs = append(gcs, gc)
+	sendTxTest(gcs)
+}
+
+func issueAsset(atype types.ActionType, assetid uint64, from, Owner, founder common.Name, amount *big.Int, assetname string, nonce uint64, prikey *ecdsa.PrivateKey) {
+	ast := &asset.AssetObject{
+		AssetId:    assetid,
+		AssetName:  assetname,
+		Symbol:     fmt.Sprintf("symbol%d", nonce),
+		Amount:     amount,
+		Decimals:   2,
+		Founder:    founder,
+		AddIssue:   nil,
+		Owner:      Owner,
+		UpperLimit: big.NewInt(100000000000000000),
+	}
+	payload, err := rlp.EncodeToBytes(ast)
+	if err != nil {
+		panic("rlp payload err")
+	}
+	gc := newGeAction(atype, from, "", nonce, 1, gaslimit, nil, payload, prikey)
+	var gcs []*GenAction
+	gcs = append(gcs, gc)
+	sendTxTest(gcs)
+}
+
+func increaseAsset(from, to common.Name, assetid uint64, nonce uint64, prikey *ecdsa.PrivateKey) {
+	ast := &accountmanager.IncAsset{
+		AssetId: assetid,
+		To:      to,
+		Amount:  inCreateAmount,
+	}
+	payload, err := rlp.EncodeToBytes(ast)
+	if err != nil {
+		panic("rlp payload err")
+	}
+	gc := newGeAction(types.IncreaseAsset, from, "", nonce, 1, gaslimit, nil, payload, prikey)
+	var gcs []*GenAction
+	gcs = append(gcs, gc)
+	sendTxTest(gcs)
+}
+
+func transfer(from, to common.Name, amount *big.Int, nonce uint64, prikey *ecdsa.PrivateKey) {
+	gc := newGeAction(types.Transfer, from, to, nonce, 1, gaslimit, amount, nil, prikey)
+	var gcs []*GenAction
+	gcs = append(gcs, gc)
+	sendTxTest(gcs)
+}
+
+func newGeAction(at types.ActionType, from, to common.Name, nonce uint64, assetid uint64, gaslimit uint64, amount *big.Int, payload []byte, prikey *ecdsa.PrivateKey) *GenAction {
+	action := types.NewAction(at, from, to, nonce, assetid, gaslimit, amount, payload)
+
+	return &GenAction{
+		Action:     action,
+		PrivateKey: prikey,
+	}
+}
+
+func sendTxTest(gcs []*GenAction) {
+	signer := types.NewSigner(big.NewInt(1))
+	var actions []*types.Action
+	for _, v := range gcs {
+		actions = append(actions, v.Action)
+	}
+	tx := types.NewTransaction(uint64(1), big.NewInt(1), actions...)
+	for _, v := range gcs {
+		keypair := types.MakeKeyPair(v.PrivateKey, []uint64{0})
+		err := types.SignActionWithMultiKey(v.Action, tx, signer, []*types.KeyPair{keypair})
+		if err != nil {
+			panic(fmt.Sprintf("SignAction err %v", err))
+		}
+
+	}
+	rawtx, err := rlp.EncodeToBytes(tx)
+	if err != nil {
+		jww.ERROR.Fatalln(err)
+	}
+	hash, err := tc.SendRawTx(rawtx)
+	if err != nil {
+		panic(err)
+	}
+	jww.INFO.Printf("hash: %x", hash)
+}
+
+var (
+	pub1 = "0x0468cba7890aae10f3dde57d269cf7c4ba14cc0efc2afee86791b0a22b794820febdb2e5c6c56878a308e7f62ad2d75739de40313a72975c993dd76a5301a03d12"
+	pri1 = "357a2cbdd91686dcbe2c612e9bed85d4415f62446440839466bf7b2f1ab135b7"
+
+	pub2 = "0x04fa0b2a9b2d0542bf2912c4c6500ba64a26652e302370ed5645b1c32df50fbe7a5f12da0b278638e1df6753a7c6ac09e68cb748cfe6d45102114f52e95e9ed652"
+	pri2 = "340cde826336f1adb8673ec945819d073af00cffb5c174542e35ff346445e213"
+
+	pubkey1    = common.HexToPubKey(pub1)
+	prikey1, _ = crypto.HexToECDSA(pri1)
+
+	pubkey2    = common.HexToPubKey(pub2)
+	prikey2, _ = crypto.HexToECDSA(pri2)
+)
+
+func main() {
+	nonce, _ := tc.GetNonce(minername)
+	//pub, pri := GeneragePubKey()
+	createAccount(toname, "", minername, toname, nonce, pubkey1, minerprikey)
+	nonce++
+	transfer(minername, toname, issueAmount, nonce, minerprikey)
+	nonce++
+
+	newname2 := common.Name("testtest12")
+	//pub1, _ := GeneragePubKey()
+	createAccount(newname2, "", minername, newname2, nonce, pubkey2, minerprikey)
+	nonce++
+
+	transfer(minername, newname2, issueAmount, nonce, minerprikey)
+	nonce++
+
+	pubkey3, prikey3 := GeneragePubKey()
+	newname3 := common.Name("testtest13")
+	createAccount(newname3, "", minername, newname3, nonce, pubkey3, minerprikey)
+	nonce++
+
+	transfer(minername, newname3, issueAmount, nonce, minerprikey)
+	nonce++
+
+	time.Sleep(time.Duration(3) * time.Second)
+
+	t3nonce, _ := tc.GetNonce(newname3)
+	updateAccount(newname3, newname2, t3nonce, prikey3)
+	time.Sleep(time.Duration(3) * time.Second)
+
+	t3nonce, _ = tc.GetNonce(newname3)
+	updateAccountAuthor(newname3, pubkey3, pubkey2, t3nonce, prikey3)
+	time.Sleep(time.Duration(3) * time.Second)
+
+	t3nonce, _ = tc.GetNonce(newname3)
+	issueAsset(types.IssueAsset, 0, newname3, newname3, newname3, big.NewInt(10000000000000), "testnewasset", t3nonce, prikey2)
+	time.Sleep(time.Duration(3) * time.Second)
+
+	t3nonce++
+	increaseAsset(newname3, newname3, 2, t3nonce, prikey2)
+	time.Sleep(time.Duration(3) * time.Second)
+
+	t3nonce++
+	issueAsset(types.SetAssetOwner, 2, newname3, toname, "", big.NewInt(100000), "testnewasset", t3nonce, prikey2)
+	time.Sleep(time.Duration(3) * time.Second)
+
+	t3nonce++
+	issueAsset(types.DestroyAsset, 2, toname, "", "", big.NewInt(100000), "testnewasset", t3nonce, prikey1)
+
+}
diff --git a/test/tx/main.go b/test/tx/main.go
deleted file mode 100644
index 150833ad..00000000
--- a/test/tx/main.go
+++ /dev/null
@@ -1,354 +0,0 @@
-// Copyright 2018 The Fractal Team Authors
-// This file is part of the fractal project.
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-package main
-
-import (
-	"crypto/ecdsa"
-	"fmt"
-	"math/big"
-	"time"
-
-	"os"
-	"strconv"
-	"sync"
-
-	"github.com/fractalplatform/fractal/asset"
-	"github.com/fractalplatform/fractal/common"
-	"github.com/fractalplatform/fractal/crypto"
-	"github.com/fractalplatform/fractal/params"
-	tc "github.com/fractalplatform/fractal/test/common"
-	"github.com/fractalplatform/fractal/types"
-	"github.com/fractalplatform/fractal/utils/rlp"
-	jww "github.com/spf13/jwalterweatherman"
-)
-
-var (
-	minerprikey []*ecdsa.PrivateKey
-	minername   []common.Name
-	ipc         []string
-	index       int
-
-	basefrom []string
-	baseto   []string
-
-	ftproducer1key, _ = crypto.HexToECDSA("289c2857d4598e37fb9647507e47a309d6133539bf21a8b9cb6df88fd5232032")
-	ftproducer1name   = common.Name("ftproducer1")
-
-	ftproducer2key, _ = crypto.HexToECDSA("9c22ff5f21f0b81b113e63f7db6da94fedef11b2119b4088b89664fb9a3cb658")
-	ftproducer2name   = common.Name("ftproducer2")
-
-	ftproducer3key, _ = crypto.HexToECDSA("8605cf6e76c9fc8ac079d0f841bd5e99bd3ad40fdd56af067993ed14fc5bfca8")
-	ftproducer3name   = common.Name("ftproducer3")
-
-	gaslimit       = uint64(200000)
-	issueAmount    = big.NewInt(100000000000000)
-	inCreateAmount = big.NewInt(100000000)
-	indexstr       = "abcdefghijklmnopqrstuvwxyz0123456789"
-)
-
-type GenAction struct {
-	*types.Action
-	PrivateKey *ecdsa.PrivateKey
-}
-
-func init() {
-	jww.SetLogThreshold(jww.LevelTrace)
-	jww.SetStdoutThreshold(jww.LevelInfo)
-
-	sysprikey, _ := crypto.HexToECDSA("289c2857d4598e37fb9647507e47a309d6133539bf21a8b9cb6df88fd5232032")
-	//syspubkey := common.HexToPubKey("0x047db227d7094ce215c3a0f57e1bcc732551fe351f94249471934567e0f5dc1bf795962b8cccb87a2eb56b29fbe37d614e2f4c3c45b789ae4f1f51f4cb21972ffd")
-	minerprikey = append(minerprikey, sysprikey)
-	minername = append(minername, params.DefaultChainconfig.SysName)
-	minerprikey = append(minerprikey, ftproducer1key, ftproducer2key, ftproducer3key)
-	minername = append(minername, ftproducer1name, ftproducer2name, ftproducer3name)
-	ipc = append(ipc, "/home/Fractal/piTest/node_01/data/ft.ipc", "/home/Fractal/piTest/node_02/data/ft.ipc", "/home/Fractal/piTest/node_03/data/ft.ipc")
-
-	basefrom = append(basefrom, "newnamefrom1%s", "newnamefrom2%s", "newnamefrom3%s")
-	baseto = append(baseto, "newnameto1%s", "newnameto2%s", "newnameto3%s")
-}
-
-func GeneragePubKey() (common.PubKey, *ecdsa.PrivateKey) {
-	prikey, _ := crypto.GenerateKey()
-	return common.BytesToPubKey(crypto.FromECDSAPub(&prikey.PublicKey)), prikey
-}
-
-func createAccount(from, newname common.Name, nonce uint64, prikey *ecdsa.PrivateKey, pubkey common.PubKey) (common.Hash, error) {
-	to := newname
-	gc := newGeAction(types.CreateAccount, from, to, nonce, 1, gaslimit, nil, pubkey[:], prikey)
-	var gcs []*GenAction
-	gcs = append(gcs, gc)
-	return sendTxTest(gcs)
-}
-
-func issueAsset(from, Owner common.Name, amount *big.Int, assetname string, nonce uint64, prikey *ecdsa.PrivateKey) (common.Hash, error) {
-	ast := &asset.AssetObject{
-		AssetName:  assetname,
-		Symbol:     fmt.Sprintf("symbol%d", nonce),
-		Amount:     amount,
-		Decimals:   2,
-		Owner:      Owner,
-		Founder:    from,
-		UpperLimit: big.NewInt(500000000000000000),
-	}
-	payload, err := rlp.EncodeToBytes(ast)
-	if err != nil {
-		panic("rlp payload err")
-	}
-	gc := newGeAction(types.IssueAsset, from, "", nonce, 1, gaslimit, nil, payload, prikey)
-	var gcs []*GenAction
-	gcs = append(gcs, gc)
-	return sendTxTest(gcs)
-}
-
-func transfer(from, to common.Name, amount *big.Int, nonce uint64, prikey *ecdsa.PrivateKey) (common.Hash, error) {
-	gc := newGeAction(types.Transfer, from, to, nonce, 1, gaslimit, amount, nil, prikey)
-	var gcs []*GenAction
-	gcs = append(gcs, gc)
-	return sendTxTest(gcs)
-}
-
-func newGeAction(at types.ActionType, from, to common.Name, nonce uint64, assetid uint64, gaslimit uint64, amount *big.Int, payload []byte, prikey *ecdsa.PrivateKey) *GenAction {
-	action := types.NewAction(at, from, to, nonce, assetid, gaslimit, amount, payload)
-	return &GenAction{
-		Action:     action,
-		PrivateKey: prikey,
-	}
-}
-
-func sendTxTest(gcs []*GenAction) (common.Hash, error) {
-	//nonce := GetNonce(sendaddr, "latest")
-	signer := types.NewSigner(params.DefaultChainconfig.ChainID)
-	var actions []*types.Action
-	for _, v := range gcs {
-		actions = append(actions, v.Action)
-	}
-	tx := types.NewTransaction(uint64(1), big.NewInt(2), actions...)
-	for _, v := range gcs {
-		err := types.SignAction(v.Action, tx, signer, v.PrivateKey)
-		if err != nil {
-			panic(fmt.Sprintf("SignAction err %v", err))
-		}
-	}
-	rawtx, err := rlp.EncodeToBytes(tx)
-	if err != nil {
-		jww.ERROR.Fatalln(err)
-	}
-	return tc.SendRawTx(rawtx)
-}
-
-func stressTest() {
-	if len(os.Args) < 3 {
-		panic("argument not enough")
-	}
-	threadsize, err := strconv.Atoi(os.Args[1])
-	if err != nil {
-		panic("argument err")
-	}
-
-	index, err = strconv.Atoi(os.Args[2])
-	if err != nil {
-		panic("argument err")
-	}
-
-	if threadsize >= len(indexstr) {
-		panic("first argument over")
-	}
-	type UserInfo struct {
-		name   common.Name
-		pubkey common.PubKey
-		prikey *ecdsa.PrivateKey
-	}
-
-	//tc.SetDefultURL(ipc[index])
-	newusersfrom := make([]UserInfo, threadsize)
-	newusersto := make([]UserInfo, threadsize)
-	for i := 0; i < threadsize; i++ {
-		newusersfrom[i].name = common.Name(fmt.Sprintf(basefrom[index], string(indexstr[i])))
-		newusersfrom[i].pubkey, newusersfrom[i].prikey = GeneragePubKey()
-		newusersto[i].name = common.Name(fmt.Sprintf(baseto[index], string(indexstr[i])))
-		newusersto[i].pubkey, newusersto[i].prikey = GeneragePubKey()
-	}
-	nonce, _ := tc.GetNonce(minername[index])
-	for i := 0; i < threadsize; i++ {
-		h, err := createAccount(minername[index], newusersfrom[i].name, nonce, minerprikey[index], newusersfrom[i].pubkey)
-		fmt.Println("create account from :", h.String(), "err:", err)
-		nonce += 1
-		h, err = createAccount(minername[index], newusersto[i].name, nonce, minerprikey[index], newusersto[i].pubkey)
-		fmt.Println("create account to :", h.String(), "err:", err)
-		nonce += 1
-	}
-	flag := true
-	for {
-		flag = true
-		jww.INFO.Printf("check createAccount \n")
-		time.Sleep(time.Duration(7) * time.Second)
-		for i := 0; i < threadsize; i++ {
-			act, _ := tc.GetAccountByName(newusersfrom[i].name)
-			jww.INFO.Println("name", act.AcctName, "check createAccount 1", newusersfrom[i].name)
-			if act.AcctName != newusersfrom[i].name {
-				flag = false
-			}
-			act, _ = tc.GetAccountByName(newusersto[i].name)
-			jww.INFO.Println("name", act.AcctName, "check createAccount 2", newusersto[i].name)
-			if act.AcctName != newusersto[i].name {
-				flag = false
-			}
-		}
-		if flag {
-			break
-		}
-	}
-	jww.INFO.Printf("all account create success \n")
-	nonce, _ = tc.GetNonce(minername[index])
-	for i := 0; i < threadsize; i++ {
-		h, err := transfer(minername[index], newusersfrom[i].name, big.NewInt(10000000000000), nonce, minerprikey[index])
-		fmt.Println("transfer to prodcer :", h.String(), "err:", err)
-		nonce += 1
-	}
-	for {
-		flag = true
-		jww.INFO.Printf("check transfer \n")
-		time.Sleep(time.Duration(7) * time.Second)
-		for i := 0; i < len(newusersfrom); i++ {
-			balance, _ := tc.GetAccountBalanceByID(newusersfrom[i].name, 1)
-			fmt.Println("name", newusersfrom[i].name, "balance:", balance.Int64())
-			if balance.Int64() < 10000000000000 {
-				flag = false
-			}
-		}
-		if flag {
-			break
-		}
-	}
-	jww.INFO.Printf("all account transfer success \n")
-	if len(os.Args) < 2 {
-		panic("argument not enough")
-	}
-	type tmpasset struct {
-		from    common.Name
-		to      common.Name
-		assetid uint64
-	}
-	ch := make(chan tmpasset, 100)
-	txsnumber := make([]*uint64, threadsize)
-	for i := 0; i < threadsize; i++ {
-		txsnumber[i] = new(uint64)
-	}
-	var wg sync.WaitGroup
-	for i := 0; i < threadsize; i++ {
-		wg.Add(1)
-		go func(from, to common.Name, prikey *ecdsa.PrivateKey, c chan tmpasset, txnumber *uint64) {
-			defer wg.Add(-1)
-			assetname := "na" + from.String()
-			innonce, _ := tc.GetNonce(from)
-			h, err := issueAsset(from, from, big.NewInt(100000000000000), assetname, innonce, prikey)
-			fmt.Println("issueAsset :", h.String(), "err:", err)
-			innonce += 1
-			var astInfo *asset.AssetObject
-			for {
-				jww.INFO.Printf("check issueAsset %v\n", from)
-				time.Sleep(time.Duration(7) * time.Second)
-				astInfo, err = tc.GetAssetInfoByName(assetname)
-				jww.INFO.Println(astInfo, err)
-				fmt.Printf("astInfo.AssetName:[%s] assetname:[%s]\n", astInfo.AssetName, assetname)
-				if astInfo != nil && astInfo.AssetName == assetname {
-					//jww.INFO.Println("issueasset success ", assetname, astInfo.AssetId)
-					jww.INFO.Println("assetid ", astInfo.AssetId)
-					break
-				}
-			}
-			jww.INFO.Println("start sent transfer forevery \n")
-			flag := true
-			for {
-				gc := newGeAction(types.Transfer, from, to, innonce, astInfo.AssetId, gaslimit, big.NewInt(1), nil, prikey)
-				var gcs []*GenAction
-				gcs = append(gcs, gc)
-				sendTxTest(gcs)
-				innonce += 1
-				if flag {
-					for {
-						jww.INFO.Printf("check balance %v\n", to)
-						time.Sleep(time.Duration(7) * time.Second)
-						balance, _ := tc.GetAccountBalanceByID(to, astInfo.AssetId)
-						if balance.Int64() >= 1 {
-							jww.INFO.Printf("Transfer to %v success\n", to)
-							flag = false
-							c <- tmpasset{from, to, astInfo.AssetId}
-							break
-						}
-					}
-				}
-				*txnumber += 1
-			}
-		}(newusersfrom[i].name, newusersto[i].name, newusersfrom[i].prikey, ch, txsnumber[i])
-	}
-	total := 0
-	var toassets []tmpasset
-	for {
-		tmp := <-ch
-		toassets = append(toassets, tmp)
-		total += 1
-		if total >= threadsize {
-			break
-		}
-	}
-	type calculatetps struct {
-		tm      int64
-		balance int64
-	}
-	caltps := make(map[common.Name]*calculatetps, len(toassets))
-	tm := time.Now().Unix()
-	for i := 0; i < len(toassets); i++ {
-		caltps[toassets[i].to] = &calculatetps{tm, 0}
-	}
-
-	go func() {
-		defer wg.Add(-1)
-		nonce, _ := tc.GetNonce(minername[index])
-		for {
-			time.Sleep(time.Duration(20) * time.Second)
-			for i := 0; i < threadsize; i++ {
-				h, err := transfer(minername[index], toassets[i].from, big.NewInt(100000), nonce, minerprikey[index])
-				jww.INFO.Println("transfer to custom :", h.String(), "err:", err)
-				nonce += 1
-			}
-		}
-	}()
-	lastnumber := uint64(0)
-	lasttime := time.Now().Unix()
-	for {
-		time.Sleep(time.Duration(10) * time.Second)
-		tmpnumber := uint64(0)
-		actualnumber := uint64(0)
-		tmptime := time.Now().Unix()
-		for i := 0; i < threadsize; i++ {
-			tmpnumber += *txsnumber[i]
-			balance, _ := tc.GetAccountBalanceByID(toassets[i].to, toassets[i].assetid)
-			actualnumber += balance.Uint64()
-		}
-		jww.INFO.Printf(" send tx number: %d\t succes num: %d\t tps: %d/s",
-			tmpnumber, actualnumber, (actualnumber-lastnumber)/uint64(tmptime-lasttime))
-		lasttime = tmptime
-		lastnumber = actualnumber
-	}
-
-	wg.Wait()
-}
-
-func main() {
-	stressTest()
-}
diff --git a/txpool/config.go b/txpool/config.go
index dc597173..2fda4145 100644
--- a/txpool/config.go
+++ b/txpool/config.go
@@ -16,29 +16,80 @@
 
 package txpool
 
-import "time"
+import (
+	"time"
+
+	"github.com/ethereum/go-ethereum/log"
+)
 
 // Config  are the configuration parameters of the transaction pool.
 type Config struct {
-	NoLocals  bool          `mapstructure:"txpool-nolocals"`  // Whether local transaction handling should be disabled
-	Journal   string        `mapstructure:"txpool-journal"`   // Journal of local transactions to survive node restarts
-	Rejournal time.Duration `mapstructure:"txpool-rejournal"` // Time interval to regenerate the local transaction journal
+	NoLocals  bool          `mapstructure:"nolocals"`  // Whether local transaction handling should be disabled
+	Journal   string        `mapstructure:"journal"`   // Journal of local transactions to survive node restarts
+	Rejournal time.Duration `mapstructure:"rejournal"` // Time interval to regenerate the local transaction journal
 
-	PriceLimit uint64 `mapstructure:"txpool-pricelimit"` // Minimum gas price to enforce for acceptance into the pool
-	PriceBump  uint64 `mapstructure:"txpool-pricebump"`  // Minimum price bump percentage to replace an already existing transaction (nonce)
+	PriceLimit uint64 `mapstructure:"pricelimit"` // Minimum gas price to enforce for acceptance into the pool
+	PriceBump  uint64 `mapstructure:"pricebump"`  // Minimum price bump percentage to replace an already existing transaction (nonce)
 
-	AccountSlots uint64 `mapstructure:"txpool-accountslots"` // Minimum number of executable transaction slots guaranteed per account
-	GlobalSlots  uint64 `mapstructure:"txpool-globalslots"`  // Maximum number of executable transaction slots for all accounts
-	AccountQueue uint64 `mapstructure:"txpool-accountqueue"` // Maximum number of non-executable transaction slots permitted per account
-	GlobalQueue  uint64 `mapstructure:"txpool-globalqueue"`  // Maximum number of non-executable transaction slots for all accounts
+	AccountSlots uint64 `mapstructure:"accountslots"` // Minimum number of executable transaction slots guaranteed per account
+	GlobalSlots  uint64 `mapstructure:"globalslots"`  // Maximum number of executable transaction slots for all accounts
+	AccountQueue uint64 `mapstructure:"accountqueue"` // Maximum number of non-executable transaction slots permitted per account
+	GlobalQueue  uint64 `mapstructure:"globalqueue"`  // Maximum number of non-executable transaction slots for all accounts
 
-	Lifetime time.Duration `mapstructure:"txpool-lifetime"` // Maximum amount of time non-executable transaction are queued
+	Lifetime time.Duration `mapstructure:"lifetime"` // Maximum amount of time non-executable transaction are queued
 
 	GasAssetID uint64
 }
 
-func (c *Config) check() Config {
-	conf := *c
-	//todo check config
+// DefaultTxPoolConfig default txpool config
+var DefaultTxPoolConfig = &Config{
+	Journal:      "transactions.rlp",
+	Rejournal:    time.Hour,
+	PriceLimit:   1,
+	PriceBump:    10,
+	AccountSlots: 128,
+	GlobalSlots:  4096,
+	AccountQueue: 1280,
+	GlobalQueue:  4096,
+	Lifetime:     3 * time.Hour,
+	GasAssetID:   1,
+}
+
+// check checks the provided user configurations and changes anything that's
+// unreasonable or unworkable.
+func (config *Config) check() Config {
+	conf := *config
+	if conf.Rejournal < time.Second {
+		log.Warn("Sanitizing invalid txpool journal time", "provided", conf.Rejournal, "updated", time.Second)
+		conf.Rejournal = time.Second
+	}
+	if conf.PriceLimit < 1 {
+		log.Warn("Sanitizing invalid txpool price limit", "provided", conf.PriceLimit, "updated", DefaultTxPoolConfig.PriceLimit)
+		conf.PriceLimit = DefaultTxPoolConfig.PriceLimit
+	}
+	if conf.PriceBump < 1 {
+		log.Warn("Sanitizing invalid txpool price bump", "provided", conf.PriceBump, "updated", DefaultTxPoolConfig.PriceBump)
+		conf.PriceBump = DefaultTxPoolConfig.PriceBump
+	}
+	if conf.AccountSlots < 1 {
+		log.Warn("Sanitizing invalid txpool account slots", "provided", conf.AccountSlots, "updated", DefaultTxPoolConfig.AccountSlots)
+		conf.AccountSlots = DefaultTxPoolConfig.AccountSlots
+	}
+	if conf.GlobalSlots < 1 {
+		log.Warn("Sanitizing invalid txpool global slots", "provided", conf.GlobalSlots, "updated", DefaultTxPoolConfig.GlobalSlots)
+		conf.GlobalSlots = DefaultTxPoolConfig.GlobalSlots
+	}
+	if conf.AccountQueue < 1 {
+		log.Warn("Sanitizing invalid txpool account queue", "provided", conf.AccountQueue, "updated", DefaultTxPoolConfig.AccountQueue)
+		conf.AccountQueue = DefaultTxPoolConfig.AccountQueue
+	}
+	if conf.GlobalQueue < 1 {
+		log.Warn("Sanitizing invalid txpool global queue", "provided", conf.GlobalQueue, "updated", DefaultTxPoolConfig.GlobalQueue)
+		conf.GlobalQueue = DefaultTxPoolConfig.GlobalQueue
+	}
+	if conf.Lifetime < 1 {
+		log.Warn("Sanitizing invalid txpool lifetime", "provided", conf.Lifetime, "updated", DefaultTxPoolConfig.Lifetime)
+		conf.Lifetime = DefaultTxPoolConfig.Lifetime
+	}
 	return conf
 }
diff --git a/txpool/error.go b/txpool/error.go
index 2f0405da..be8bbdb9 100644
--- a/txpool/error.go
+++ b/txpool/error.go
@@ -60,4 +60,10 @@ var (
 	// than some meaningful limit a user might use. This is not a consensus error
 	// making the transaction invalid, rather a DOS protection.
 	ErrOversizedData = errors.New("oversized data")
+
+	// ErrEmptyActions transaction no actions
+	ErrEmptyActions = errors.New("transaction no actions")
+
+	// ErrInvalidValue action value invalid
+	ErrInvalidValue = errors.New("action value invalid")
 )
diff --git a/txpool/list.go b/txpool/list.go
index cbb22716..78989269 100644
--- a/txpool/list.go
+++ b/txpool/list.go
@@ -93,7 +93,7 @@ func (l *txList) Forward(threshold uint64) []*types.Transaction {
 // than the provided thresholds. Every removed transaction is returned for any
 // post-removal maintenance. Strict-mode invalidated transactions are also
 // returned.
-func (l *txList) Filter(costLimit *big.Int, gasLimit uint64, getBalance func(name common.Name, assetID uint64) (*big.Int, error)) ([]*types.Transaction, []*types.Transaction) {
+func (l *txList) Filter(costLimit *big.Int, gasLimit uint64, getBalance func(name common.Name, assetID uint64, typeID uint64) (*big.Int, error)) ([]*types.Transaction, []*types.Transaction) {
 	// If all transactions are below the threshold, short circuit
 	if l.gascostcap.Cmp(costLimit) > 0 {
 		l.gascostcap = new(big.Int).Set(costLimit) // Lower the caps to the thresholds
@@ -105,7 +105,7 @@ func (l *txList) Filter(costLimit *big.Int, gasLimit uint64, getBalance func(nam
 	// Filter out all the transactions above the account's funds
 	removed := l.txs.Filter(func(tx *types.Transaction) bool {
 		act := tx.GetActions()[0]
-		balance, _ := getBalance(act.Sender(), act.AssetID())
+		balance, _ := getBalance(act.Sender(), act.AssetID(), 0)
 		// todo change action
 		return act.Value().Cmp(balance) > 0 || tx.Cost().Cmp(costLimit) > 0 || act.Gas() > gasLimit
 	})
diff --git a/txpool/list_test.go b/txpool/list_test.go
index 8e6a6974..12be3276 100644
--- a/txpool/list_test.go
+++ b/txpool/list_test.go
@@ -31,7 +31,7 @@ func TestStrictTxListAdd(t *testing.T) {
 
 	txs := make([]*types.Transaction, 1024)
 	for i := 0; i < len(txs); i++ {
-		txs[i] = transaction(uint64(i), "from", "to", 0, key)
+		txs[i] = transaction(uint64(i), "fromtest", "tototest", 0, key)
 	}
 
 	// Insert the transactions in a random order
@@ -39,6 +39,7 @@ func TestStrictTxListAdd(t *testing.T) {
 	for _, v := range rand.Perm(len(txs)) {
 		list.Add(txs[v], 10)
 	}
+
 	// Verify internal state
 	assert.Equal(t, len(list.txs.items), len(txs))
 
diff --git a/txpool/priceheap_test.go b/txpool/priceheap_test.go
index e644e173..9d8112ec 100644
--- a/txpool/priceheap_test.go
+++ b/txpool/priceheap_test.go
@@ -29,8 +29,8 @@ import (
 func getPriceTx(price *big.Int, nonce uint64) *types.Transaction {
 	return types.NewTransaction(0, price, types.NewAction(
 		types.Transfer,
-		common.Name("from"),
-		common.Name("to"),
+		common.Name("fromtest"),
+		common.Name("tototest"),
 		nonce,
 		uint64(3),
 		uint64(2000),
diff --git a/txpool/sendercacher.go b/txpool/sendercacher.go
index da9d6f85..5b8de46a 100644
--- a/txpool/sendercacher.go
+++ b/txpool/sendercacher.go
@@ -63,7 +63,7 @@ func (cacher *txSenderCacher) cache() {
 	for task := range cacher.tasks {
 		for i := 0; i < len(task.txs); i += task.inc {
 			for _, a := range task.txs[i].GetActions() {
-				types.Recover(task.signer, a, task.txs[i])
+				types.RecoverMultiKey(task.signer, a, task.txs[i])
 			}
 		}
 	}
diff --git a/txpool/test_utils.go b/txpool/test_utils.go
index 5eeb4956..63d99247 100644
--- a/txpool/test_utils.go
+++ b/txpool/test_utils.go
@@ -79,7 +79,8 @@ func transaction(nonce uint64, from, to common.Name, gaslimit uint64, key *ecdsa
 
 func pricedTransaction(nonce uint64, from, to common.Name, gaslimit uint64, gasprice *big.Int, key *ecdsa.PrivateKey) *types.Transaction {
 	tx := newTx(gasprice, newAction(nonce, from, to, big.NewInt(100), gaslimit, nil))
-	if err := types.SignAction(tx.GetActions()[0], tx, types.NewSigner(params.DefaultChainconfig.ChainID), key); err != nil {
+	keyPair := types.MakeKeyPair(key, []uint64{0})
+	if err := types.SignActionWithMultiKey(tx.GetActions()[0], tx, types.NewSigner(params.DefaultChainconfig.ChainID), []*types.KeyPair{keyPair}); err != nil {
 		panic(err)
 	}
 	return tx
@@ -92,7 +93,7 @@ func generateAccount(t *testing.T, name common.Name, managers ...*am.AccountMana
 	}
 	pubkeyBytes := crypto.FromECDSAPub(&key.PublicKey)
 	for _, m := range managers {
-		if err := m.CreateAccount(name, common.Name(""), 80, common.BytesToPubKey(pubkeyBytes)); err != nil {
+		if err := m.CreateAccount(name, common.Name(""), 0, 80, common.BytesToPubKey(pubkeyBytes)); err != nil {
 			t.Fatal(err)
 		}
 	}
@@ -103,7 +104,7 @@ func setupTxPool(assetOwner common.Name) (*TxPool, *am.AccountManager) {
 
 	statedb, _ := state.New(common.Hash{}, state.NewDatabase(memdb.NewMemDatabase()))
 	asset := asset.NewAsset(statedb)
-	asset.IssueAsset("ft", "zz", new(big.Int).SetUint64(params.Fractal), 10, assetOwner, assetOwner, big.NewInt(1000000))
+	asset.IssueAsset("ft", 0, "zz", new(big.Int).SetUint64(params.Fractal), 10, assetOwner, assetOwner, big.NewInt(1000000), common.Name(""))
 	blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)}
 	manager, _ := am.NewAccountManager(statedb)
 	return New(testTxPoolConfig, params.DefaultChainconfig, blockchain), manager
@@ -173,18 +174,6 @@ func validateEvents(events chan *event.Event, count int) error {
 	return nil
 }
 
-func deriveSender(tx *types.Transaction) ([]common.PubKey, error) {
-	var pubkeys []common.PubKey
-	for _, a := range tx.GetActions() {
-		pubkey, err := types.Recover(types.NewSigner(params.DefaultChainconfig.ChainID), a, tx)
-		if err != nil {
-			return nil, err
-		}
-		pubkeys = append(pubkeys, pubkey)
-	}
-	return pubkeys, nil
-}
-
 type testChain struct {
 	*testBlockChain
 
diff --git a/txpool/txpool.go b/txpool/txpool.go
index 0a04959e..451e413c 100644
--- a/txpool/txpool.go
+++ b/txpool/txpool.go
@@ -88,10 +88,12 @@ type TxPool struct {
 // New creates a new transaction pool to gather, sort and filter inbound
 // transactions from the network.
 func New(config Config, chainconfig *params.ChainConfig, bc blockChain) *TxPool {
+	//  check the input to ensure no vulnerable gas prices are set
+	config = (&config).check()
 	signer := types.NewSigner(chainconfig.ChainID)
 	all := newTxLookup()
 	tp := &TxPool{
-		config:      config.check(),
+		config:      config,
 		chain:       bc,
 		signer:      signer,
 		locals:      newAccountSet(signer),
@@ -190,7 +192,6 @@ func (tp *TxPool) loop() {
 				}
 			}
 			tp.mu.Unlock()
-
 			// Handle local transaction journal rotation
 		case <-journal.C:
 			if tp.journal != nil {
@@ -302,13 +303,11 @@ func (tp *TxPool) reset(oldHead, newHead *types.Header) {
 			if err != am.ErrAccountIsDestroy {
 				log.Error("Failed to pendingAccountManager SetNonce", "err", err)
 				return
-			} else {
-				delete(tp.pending, name)
-				delete(tp.beats, name)
-				delete(tp.queue, name)
-				log.Debug("Remove all destory account ", "name", name)
 			}
-
+			delete(tp.pending, name)
+			delete(tp.beats, name)
+			delete(tp.queue, name)
+			log.Debug("Remove all destory account ", "name", name)
 		}
 	}
 	// Check the queue and move transactions over to the pending if possible
@@ -447,7 +446,7 @@ func (tp *TxPool) validateTx(tx *types.Transaction, local bool) error {
 		}
 
 		// Transactor should have enough funds to cover the gas costs
-		balance, err := tp.curAccountManager.GetAccountBalanceByID(from, tx.GasAssetID())
+		balance, err := tp.curAccountManager.GetAccountBalanceByID(from, tx.GasAssetID(), 0)
 		if err != nil {
 			return err
 		}
@@ -458,7 +457,7 @@ func (tp *TxPool) validateTx(tx *types.Transaction, local bool) error {
 		}
 
 		// Transactor should have enough funds to cover the value costs
-		balance, err = tp.curAccountManager.GetAccountBalanceByID(from, action.AssetID())
+		balance, err = tp.curAccountManager.GetAccountBalanceByID(from, action.AssetID(), 0)
 		if err != nil {
 			return err
 		}
@@ -472,6 +471,10 @@ func (tp *TxPool) validateTx(tx *types.Transaction, local bool) error {
 			return ErrInsufficientFundsForValue
 		}
 
+		if action.CheckValue() != true {
+			return ErrInvalidValue
+		}
+
 		intrGas, err := IntrinsicGas(action)
 		if err != nil {
 			return err
@@ -641,7 +644,6 @@ func (tp *TxPool) promoteTx(name common.Name, hash common.Hash, tx *types.Transa
 		// An older transaction was better, discard this
 		tp.all.Remove(hash)
 		tp.priced.Removed()
-
 		return false
 	}
 	// Otherwise discard any previous transaction and mark this
@@ -657,7 +659,6 @@ func (tp *TxPool) promoteTx(name common.Name, hash common.Hash, tx *types.Transa
 	}
 	// Set the potentially new pending nonce and notify any subsystems of the new tx
 	tp.beats[name] = time.Now()
-
 	// todo action
 	tp.pendingAccountManager.SetNonce(name, tx.GetActions()[0].Nonce()+1)
 	return true
@@ -693,6 +694,18 @@ func (tp *TxPool) AddRemotes(txs []*types.Transaction) []error {
 
 // addTx enqueues a single transaction into the pool if it is valid.
 func (tp *TxPool) addTx(tx *types.Transaction, local bool) error {
+	if len(tx.GetActions()) == 0 {
+		return ErrEmptyActions
+	}
+
+	// Cache senders in transactions before obtaining lock
+	for _, action := range tx.GetActions() {
+		_, err := types.RecoverMultiKey(tp.signer, action, tx)
+		if err != nil {
+			return err
+		}
+	}
+
 	tp.mu.Lock()
 	defer tp.mu.Unlock()
 
@@ -712,6 +725,29 @@ func (tp *TxPool) addTx(tx *types.Transaction, local bool) error {
 
 // addTxs attempts to queue a batch of transactions if they are valid.
 func (tp *TxPool) addTxs(txs []*types.Transaction, local bool) []error {
+	// Cache senders in transactions before obtaining lock
+	var (
+		errs  []error
+		isErr bool
+	)
+	for _, tx := range txs {
+		if len(tx.GetActions()) == 0 {
+			errs = append(errs, fmt.Errorf(ErrEmptyActions.Error()+" hash %v", tx.Hash()))
+			isErr = true
+			continue
+		}
+		for _, action := range tx.GetActions() {
+			_, err := types.RecoverMultiKey(tp.signer, action, tx)
+			if err != nil {
+				log.Error("RecoverMultiKey reocver faild ", "err", err, "hash", tx.Hash())
+				errs = append(errs, err)
+				isErr = true
+			}
+		}
+	}
+	if isErr {
+		return errs
+	}
 	tp.mu.Lock()
 	defer tp.mu.Unlock()
 
@@ -855,7 +891,7 @@ func (tp *TxPool) promoteExecutables(accounts []common.Name) {
 		}
 		// Drop all transactions that are too costly (low balance or out of gas)
 		// todo assetID
-		balance, err := tp.curAccountManager.GetAccountBalanceByID(addr, tp.config.GasAssetID)
+		balance, err := tp.curAccountManager.GetAccountBalanceByID(addr, tp.config.GasAssetID, 0)
 		if err != nil {
 			log.Error("promoteExecutables current account manager get balance err ", "name", addr, "assetID", tp.config.GasAssetID, "err", err)
 		}
@@ -1042,7 +1078,7 @@ func (tp *TxPool) demoteUnexecutables() {
 		}
 
 		// Drop all transactions that are too costly (low balance or out of gas), and queue any invalids back for later
-		gasBalance, err := tp.curAccountManager.GetAccountBalanceByID(addr, tp.config.GasAssetID)
+		gasBalance, err := tp.curAccountManager.GetAccountBalanceByID(addr, tp.config.GasAssetID, 0)
 		if err != nil && err != am.ErrAccountNotExist {
 			log.Error("promoteExecutables current account manager get balance err ", "name", addr, "assetID", tp.config.GasAssetID, "err", err)
 		}
diff --git a/txpool/txpool_test.go b/txpool/txpool_test.go
index 3ebf9505..4d9c67e6 100644
--- a/txpool/txpool_test.go
+++ b/txpool/txpool_test.go
@@ -41,7 +41,6 @@ import (
 // state reset and tests whether the pending state is in sync with the
 // block head event that initiated the resetState().
 func TestStateChangeDuringTransactionPoolReset(t *testing.T) {
-
 	var (
 		statedb, _ = state.New(common.Hash{}, state.NewDatabase(mdb.NewMemDatabase()))
 		manager, _ = am.NewAccountManager(statedb)
@@ -54,7 +53,7 @@ func TestStateChangeDuringTransactionPoolReset(t *testing.T) {
 	)
 
 	// issue asset
-	if err := asset.IssueAsset("ft", "zz", new(big.Int).SetUint64(params.Fractal), 10, common.Name(""), fname, new(big.Int).SetUint64(params.Fractal)); err != nil {
+	if err := asset.IssueAsset("ft", 0, "zz", new(big.Int).SetUint64(params.Fractal), 10, common.Name(""), fname, new(big.Int).SetUint64(params.Fractal), common.Name("")); err != nil {
 		t.Fatal(err)
 	}
 
@@ -216,27 +215,6 @@ func TestTransactionQueue(t *testing.T) {
 	}
 }
 
-func TestTransactionNegativeValue(t *testing.T) {
-
-	var (
-		fname = common.Name("fromname")
-		tname = common.Name("totestname")
-	)
-	pool, manager := setupTxPool(fname)
-	defer pool.Stop()
-	fkey := generateAccount(t, fname, manager)
-	generateAccount(t, tname, manager)
-
-	tx := newTx(big.NewInt(1), newAction(0, fname, tname, big.NewInt(-1), 100, nil))
-	if err := types.SignAction(tx.GetActions()[0], tx, types.NewSigner(params.DefaultChainconfig.ChainID), fkey); err != nil {
-		panic(err)
-	}
-
-	if err := pool.AddRemote(tx); err != ErrNegativeValue {
-		t.Fatal("expected", ErrNegativeValue, "got", err)
-	}
-}
-
 func TestTransactionChainFork(t *testing.T) {
 
 	var (
@@ -253,15 +231,15 @@ func TestTransactionChainFork(t *testing.T) {
 		statedb, _ := state.New(common.Hash{}, state.NewDatabase(mdb.NewMemDatabase()))
 		newmanager, _ := am.NewAccountManager(statedb)
 
-		if err := newmanager.CreateAccount(fname, common.Name(""), 0, common.BytesToPubKey(crypto.FromECDSAPub(&fkey.PublicKey))); err != nil {
+		if err := newmanager.CreateAccount(fname, common.Name(""), 0, 0, common.BytesToPubKey(crypto.FromECDSAPub(&fkey.PublicKey))); err != nil {
 			t.Fatal(err)
 		}
-		if err := newmanager.CreateAccount(tname, common.Name(""), 0, common.BytesToPubKey(crypto.FromECDSAPub(&tkey.PublicKey))); err != nil {
+		if err := newmanager.CreateAccount(tname, common.Name(""), 0, 0, common.BytesToPubKey(crypto.FromECDSAPub(&tkey.PublicKey))); err != nil {
 			t.Fatal(err)
 		}
 		asset := asset.NewAsset(statedb)
 
-		asset.IssueAsset("ft", "zz", new(big.Int).SetUint64(params.Fractal), 10, fname, fname, big.NewInt(1000000))
+		asset.IssueAsset("ft", 0, "zz", new(big.Int).SetUint64(params.Fractal), 10, fname, fname, big.NewInt(1000000), common.Name(""))
 		newmanager.AddAccountBalanceByID(fname, assetID, big.NewInt(100000000000000))
 
 		pool.chain = &testBlockChain{statedb, 1000000, new(event.Feed)}
@@ -299,15 +277,15 @@ func TestTransactionDoubleNonce(t *testing.T) {
 		statedb, _ := state.New(common.Hash{}, state.NewDatabase(mdb.NewMemDatabase()))
 		newmanager, _ := am.NewAccountManager(statedb)
 
-		if err := newmanager.CreateAccount(fname, common.Name(""), 0, common.BytesToPubKey(crypto.FromECDSAPub(&fkey.PublicKey))); err != nil {
+		if err := newmanager.CreateAccount(fname, common.Name(""), 0, 0, common.BytesToPubKey(crypto.FromECDSAPub(&fkey.PublicKey))); err != nil {
 			t.Fatal(err)
 		}
-		if err := newmanager.CreateAccount(tname, common.Name(""), 0, common.BytesToPubKey(crypto.FromECDSAPub(&tkey.PublicKey))); err != nil {
+		if err := newmanager.CreateAccount(tname, common.Name(""), 0, 0, common.BytesToPubKey(crypto.FromECDSAPub(&tkey.PublicKey))); err != nil {
 			t.Fatal(err)
 		}
 		asset := asset.NewAsset(statedb)
 
-		asset.IssueAsset("ft", "zz", new(big.Int).SetUint64(params.Fractal), 10, fname, fname, big.NewInt(1000000))
+		asset.IssueAsset("ft", 0, "zz", new(big.Int).SetUint64(params.Fractal), 10, fname, fname, big.NewInt(1000000), common.Name(""))
 		newmanager.AddAccountBalanceByID(fname, assetID, big.NewInt(100000000000000))
 
 		pool.chain = &testBlockChain{statedb, 1000000, new(event.Feed)}
@@ -316,18 +294,19 @@ func TestTransactionDoubleNonce(t *testing.T) {
 	}
 	resetAsset()
 
+	keyPair := types.MakeKeyPair(fkey, []uint64{0})
 	tx1 := newTx(big.NewInt(1), newAction(0, fname, tname, big.NewInt(100), 100000, nil))
-	if err := types.SignAction(tx1.GetActions()[0], tx1, types.NewSigner(params.DefaultChainconfig.ChainID), fkey); err != nil {
+	if err := types.SignActionWithMultiKey(tx1.GetActions()[0], tx1, types.NewSigner(params.DefaultChainconfig.ChainID), []*types.KeyPair{keyPair}); err != nil {
 		panic(err)
 	}
 
 	tx2 := newTx(big.NewInt(2), newAction(0, fname, tname, big.NewInt(100), 1000000, nil))
-	if err := types.SignAction(tx2.GetActions()[0], tx2, types.NewSigner(params.DefaultChainconfig.ChainID), fkey); err != nil {
+	if err := types.SignActionWithMultiKey(tx2.GetActions()[0], tx2, types.NewSigner(params.DefaultChainconfig.ChainID), []*types.KeyPair{keyPair}); err != nil {
 		panic(err)
 	}
 
 	tx3 := newTx(big.NewInt(1), newAction(0, fname, tname, big.NewInt(100), 1000000, nil))
-	if err := types.SignAction(tx3.GetActions()[0], tx3, types.NewSigner(params.DefaultChainconfig.ChainID), fkey); err != nil {
+	if err := types.SignActionWithMultiKey(tx3.GetActions()[0], tx3, types.NewSigner(params.DefaultChainconfig.ChainID), []*types.KeyPair{keyPair}); err != nil {
 		panic(err)
 	}
 
@@ -1449,12 +1428,12 @@ func TestTransactionQueueLimitingEquivalency(t *testing.T)   { testTransactionLi
 func TestTransactionPendingLimitingEquivalency(t *testing.T) { testTransactionLimitingEquivalency(t, 0) }
 
 func testTransactionLimitingEquivalency(t *testing.T, origin uint64) {
-
 	var (
 		fname   = common.Name("fromname")
 		tname   = common.Name("totestname")
 		assetID = uint64(1)
 	)
+	event.Reset()
 	pool, manager := setupTxPool(fname)
 	defer pool.Stop()
 	fkey := generateAccount(t, fname, manager, pool.pendingAccountManager)
@@ -1609,10 +1588,9 @@ func TestTransactionPendingMinimumAllowance(t *testing.T) {
 
 	blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)}
 
-	config := testTxPoolConfig
-	config.GlobalSlots = 0
-
-	pool := New(config, params.DefaultChainconfig, blockchain)
+	event.Reset()
+	pool := New(testTxPoolConfig, params.DefaultChainconfig, blockchain)
+	pool.config.GlobalSlots = 0
 	defer pool.Stop()
 
 	manager, _ := am.NewAccountManager(statedb)
@@ -1637,7 +1615,7 @@ func TestTransactionPendingMinimumAllowance(t *testing.T) {
 
 	txs := []*types.Transaction{}
 	for i, key := range keys {
-		for j := 0; j < int(config.AccountSlots)*2; j++ {
+		for j := 0; j < int(testTxPoolConfig.AccountSlots)*2; j++ {
 			txs = append(txs, transaction(nonces[accs[i]], accs[i], tname, 100000, key))
 			nonces[accs[i]]++
 		}
@@ -1645,9 +1623,9 @@ func TestTransactionPendingMinimumAllowance(t *testing.T) {
 	// Import the batch and verify that limits have been enforced
 	pool.AddRemotes(txs)
 
-	for addr, list := range pool.pending {
-		if list.Len() != int(config.AccountSlots) {
-			t.Fatalf("addr %x: total pending transactions mismatch: have %d, want %d", addr, list.Len(), config.AccountSlots)
+	for name, list := range pool.pending {
+		if list.Len() != int(testTxPoolConfig.AccountSlots) {
+			t.Fatalf("addr %s: total pending transactions mismatch: have %d, want %d", name, list.Len(), testTxPoolConfig.AccountSlots)
 		}
 	}
 	if err := validateTxPoolInternals(pool); err != nil {
@@ -1661,7 +1639,6 @@ func TestTransactionJournaling(t *testing.T)         { testTransactionJournaling
 func TestTransactionJournalingNoLocals(t *testing.T) { testTransactionJournaling(t, true) }
 
 func testTransactionJournaling(t *testing.T, nolocals bool) {
-	event.Reset()
 	// Create a temporary file for the journal
 	file, err := ioutil.TempFile("", "")
 	if err != nil {
@@ -1683,6 +1660,7 @@ func testTransactionJournaling(t *testing.T, nolocals bool) {
 	config.Journal = journal
 	config.Rejournal = time.Second
 
+	event.Reset()
 	pool := New(config, params.DefaultChainconfig, blockchain)
 
 	var (
@@ -1757,6 +1735,7 @@ func testTransactionJournaling(t *testing.T, nolocals bool) {
 
 	manager.SetNonce(localName, 1)
 	blockchain = &testBlockChain{statedb, 1000000, new(event.Feed)}
+	event.Reset()
 	pool = New(config, params.DefaultChainconfig, blockchain)
 
 	pending, queued = pool.Stats()
@@ -1785,7 +1764,7 @@ func TestTransactionStatusCheck(t *testing.T) {
 	// Create the pool to test the status retrievals with
 	statedb, _ := state.New(common.Hash{}, state.NewDatabase(mdb.NewMemDatabase()))
 	blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)}
-
+	event.Reset()
 	pool := New(testTxPoolConfig, params.DefaultChainconfig, blockchain)
 	defer pool.Stop()
 
@@ -1920,7 +1899,7 @@ func BenchmarkPoolInsert(b *testing.B) {
 	fkey := generateAccount(nil, fname, manager)
 	generateAccount(nil, tname, manager)
 
-	pool.curAccountManager.AddAccountBalanceByID(fname, assetID, big.NewInt(1000000))
+	pool.curAccountManager.AddAccountBalanceByID(fname, assetID, big.NewInt(100000))
 
 	txs := make([]*types.Transaction, b.N)
 	for i := 0; i < b.N; i++ {
diff --git a/txpool/utils.go b/txpool/utils.go
index 2f6bdb42..43312ba4 100644
--- a/txpool/utils.go
+++ b/txpool/utils.go
@@ -65,5 +65,9 @@ func IntrinsicGas(action *types.Action) (uint64, error) {
 	}
 	gas += dataGas
 
+	if signLen := len(action.GetSign()); signLen > 1 {
+		gas += (uint64(len(action.GetSign()) - 1)) * params.ActionGas
+	}
+
 	return gas, nil
 }
diff --git a/cmd/ftkey/ftkey.go b/types/accountmanage.go
similarity index 90%
rename from cmd/ftkey/ftkey.go
rename to types/accountmanage.go
index d011754c..e1535bf8 100644
--- a/cmd/ftkey/ftkey.go
+++ b/types/accountmanage.go
@@ -14,8 +14,9 @@
 // You should have received a copy of the GNU General Public License
 // along with this program. If not, see <http://www.gnu.org/licenses/>.
 
-package main
+package types
 
-func main() {
-	Execute()
+type AccountManagerContext struct {
+	Action *Action
+	Number uint64
 }
diff --git a/types/action.go b/types/action.go
index 1f3d7b35..abfa7251 100644
--- a/types/action.go
+++ b/types/action.go
@@ -34,19 +34,22 @@ var ErrInvalidSig = errors.New("invalid action v, r, s values")
 type ActionType uint64
 
 const (
-	// Transfer represents the ordinary and contract transfer action.
-	Transfer ActionType = iota
+
+	// CallContract represents the call contract action.
+	CallContract ActionType = iota
 	// CreateContract repesents the create contract action.
 	CreateContract
 )
 
 const (
-	// CreateAccount repesents the create account.
+	//CreateAccount repesents the create account.
 	CreateAccount ActionType = 0x100 + iota
-	// UpdateAccount repesents the update account action.
+	//UpdateAccount repesents update account.
 	UpdateAccount
 	// DeleteAccount repesents the delete account action.
 	DeleteAccount
+	//UpdateAccountAuthor represents the update account author.
+	UpdateAccountAuthor
 )
 
 const (
@@ -54,31 +57,48 @@ const (
 	IncreaseAsset ActionType = 0x200 + iota
 	// IssueAsset repesents Issue asset action.
 	IssueAsset
-	//destory asset
-	DestoryAsset
+	//DestroyAsset destroy asset
+	DestroyAsset
 	// SetAssetOwner repesents set asset new owner action.
 	SetAssetOwner
-	//set asset founder
-	SetAssetFounder
+	//SetAssetFounder set asset founder
+	//SetAssetFounder
+	UpdateAsset
+	//Transfer repesents transfer asset action.
+	Transfer
 )
 
 const (
-	// RegProducer repesents register producer action.
-	RegProducer ActionType = 0x300 + iota
-	// UpdateProducer repesents update producer action.
-	UpdateProducer
-	// UnregProducer repesents unregister producer action.
-	UnregProducer
-	// RemoveVoter repesents producer remove voter action.
+	// RegCadidate repesents register cadidate action.
+	RegCadidate ActionType = 0x300 + iota
+	// UpdateCadidate repesents update cadidate action.
+	UpdateCadidate
+	// UnregCadidate repesents unregister cadidate action.
+	UnregCadidate
+	// RemoveVoter repesents cadidate remove voter action.
 	RemoveVoter
-	// VoteProducer repesents voter vote producer action.
-	VoteProducer
-	// ChangeProducer repesents voter change producer action.
-	ChangeProducer
-	// UnvoteProducer repesents voter cancel vote some producer action.
-	UnvoteProducer
+	// VoteCadidate repesents voter vote cadidate action.
+	VoteCadidate
+	// ChangeCadidate repesents voter change cadidate action.
+	ChangeCadidate
+	// UnvoteCadidate repesents voter cancel vote some cadidate action.
+	UnvoteCadidate
+)
+
+const (
+	// KickedCadidate
+	KickedCadidate ActionType = 0x400 + iota
+	// exit
+	ExitTakeOver
 )
 
+type SignData struct {
+	V     *big.Int
+	R     *big.Int
+	S     *big.Int
+	Index []uint64
+}
+
 type actionData struct {
 	AType    ActionType
 	Nonce    uint64
@@ -89,10 +109,7 @@ type actionData struct {
 	Amount   *big.Int
 	Payload  []byte
 
-	// Signature values
-	V *big.Int
-	R *big.Int
-	S *big.Int
+	Sign []*SignData
 }
 
 // Action represents an entire action in the transaction.
@@ -101,6 +118,7 @@ type Action struct {
 	// cache
 	hash   atomic.Value
 	sender atomic.Value
+	author atomic.Value
 }
 
 // NewAction initialize transaction's action.
@@ -117,9 +135,7 @@ func NewAction(actionType ActionType, from, to common.Name, nonce, assetID, gasL
 		GasLimit: gasLimit,
 		Amount:   new(big.Int),
 		Payload:  payload,
-		V:        new(big.Int),
-		R:        new(big.Int),
-		S:        new(big.Int),
+		Sign:     make([]*SignData, 0),
 	}
 	if amount != nil {
 		data.Amount.Set(amount)
@@ -127,6 +143,38 @@ func NewAction(actionType ActionType, from, to common.Name, nonce, assetID, gasL
 	return &Action{data: data}
 }
 
+func (a *Action) GetSignIndex(i uint64) []uint64 {
+	return a.data.Sign[i].Index
+}
+
+func (a *Action) GetSign() []*SignData {
+	return a.data.Sign
+}
+
+//CheckValue check action type and value
+func (a *Action) CheckValue() bool {
+	switch a.Type() {
+	case CreateContract:
+		fallthrough
+	case CallContract:
+		fallthrough
+	case Transfer:
+		fallthrough
+	case CreateAccount:
+		fallthrough
+	case DestroyAsset:
+		fallthrough
+	case RegCadidate:
+		fallthrough
+	case UpdateCadidate:
+		fallthrough
+	case VoteCadidate:
+		return true
+	default:
+	}
+	return a.Value().Cmp(big.NewInt(0)) == 0
+}
+
 // Type returns action's type.
 func (a *Action) Type() ActionType { return a.data.AType }
 
@@ -163,7 +211,7 @@ func (a *Action) DecodeRLP(s *rlp.Stream) error {
 
 // ChainID returns which chain id this action was signed for (if at all)
 func (a *Action) ChainID() *big.Int {
-	return deriveChainID(a.data.V)
+	return deriveChainID(a.data.Sign[0].V)
 }
 
 // Hash hashes the RLP encoding of action.
@@ -177,20 +225,15 @@ func (a *Action) Hash() common.Hash {
 }
 
 // WithSignature returns a new transaction with the given signature.
-func (a *Action) WithSignature(signer Signer, sig []byte) error {
+func (a *Action) WithSignature(signer Signer, sig []byte, index []uint64) error {
 	r, s, v, err := signer.SignatureValues(sig)
 	if err != nil {
 		return err
 	}
-	a.data.R, a.data.S, a.data.V = r, s, v
+	a.data.Sign = append(a.data.Sign, &SignData{R: r, S: s, V: v, Index: index})
 	return nil
 }
 
-// RawSignatureValues return raw signature values.
-func (a *Action) RawSignatureValues() (*big.Int, *big.Int, *big.Int) {
-	return a.data.V, a.data.R, a.data.S
-}
-
 // RPCAction represents a action that will serialize to the RPC representation of a action.
 type RPCAction struct {
 	Type       uint64        `json:"type"`
@@ -201,16 +244,12 @@ type RPCAction struct {
 	GasLimit   uint64        `json:"gas"`
 	Amount     *big.Int      `json:"value"`
 	Payload    hexutil.Bytes `json:"payload"`
-	V          *hexutil.Big  `json:"v"`
-	R          *hexutil.Big  `json:"r"`
-	S          *hexutil.Big  `json:"s"`
 	Hash       common.Hash   `json:"actionHash"`
 	ActionIdex uint64        `json:"actionIndex"`
 }
 
 // NewRPCAction returns a action that will serialize to the RPC.
 func (a *Action) NewRPCAction(index uint64) *RPCAction {
-	v, r, s := a.RawSignatureValues()
 	return &RPCAction{
 		Type:       uint64(a.Type()),
 		Nonce:      a.Nonce(),
@@ -221,9 +260,6 @@ func (a *Action) NewRPCAction(index uint64) *RPCAction {
 		Amount:     a.Value(),
 		Payload:    hexutil.Bytes(a.Data()),
 		Hash:       a.Hash(),
-		V:          (*hexutil.Big)(v),
-		R:          (*hexutil.Big)(r),
-		S:          (*hexutil.Big)(s),
 		ActionIdex: index,
 	}
 }
diff --git a/types/action_test.go b/types/action_test.go
index af161624..f932109f 100644
--- a/types/action_test.go
+++ b/types/action_test.go
@@ -37,6 +37,28 @@ var (
 		big.NewInt(1000),
 		[]byte("test action"),
 	)
+
+	testAction2 = NewAction(
+		UpdateAccount,
+		common.Name("fromname"),
+		common.Name("totoname"),
+		uint64(1),
+		uint64(3),
+		uint64(2000),
+		big.NewInt(1000),
+		[]byte("test action"),
+	)
+
+	testAction3 = NewAction(
+		UpdateAccount,
+		common.Name("fromname"),
+		common.Name("totoname"),
+		uint64(1),
+		uint64(3),
+		uint64(2000),
+		big.NewInt(0),
+		[]byte("test action"),
+	)
 )
 
 func TestActionEncodeAndDecode(t *testing.T) {
@@ -50,5 +72,53 @@ func TestActionEncodeAndDecode(t *testing.T) {
 		t.Fatal(err)
 	}
 
+	t.Log(rlpHash(actAction).Hex())
+
 	assert.Equal(t, testAction, actAction)
 }
+
+func TestAction_CheckValue(t *testing.T) {
+	actionBytes, err := rlp.EncodeToBytes(testAction)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	actAction := &Action{}
+	if err := rlp.Decode(bytes.NewReader(actionBytes), &actAction); err != nil {
+		t.Fatal(err)
+	}
+
+	if actAction.CheckValue() == false {
+		t.Errorf("TestAction_CheckValue err, wantErr %v", true)
+	}
+
+	//test2
+	actionBytes2, err := rlp.EncodeToBytes(testAction2)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	actAction2 := &Action{}
+	if err := rlp.Decode(bytes.NewReader(actionBytes2), &actAction2); err != nil {
+		t.Fatal(err)
+	}
+
+	if actAction2.CheckValue() == true {
+		t.Errorf("TestAction2_CheckValue err, wantErr %v", false)
+	}
+
+	//test3
+	actionBytes3, err := rlp.EncodeToBytes(testAction3)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	actAction3 := &Action{}
+	if err := rlp.Decode(bytes.NewReader(actionBytes3), &actAction3); err != nil {
+		t.Fatal(err)
+	}
+
+	if actAction3.CheckValue() == false {
+		t.Errorf("TestAction3_CheckValue err, wantErr %v", false)
+	}
+}
diff --git a/types/block.go b/types/block.go
index 789a68a0..d4e323ff 100644
--- a/types/block.go
+++ b/types/block.go
@@ -20,6 +20,7 @@ package types
 import (
 	"bytes"
 	"fmt"
+	"io"
 	"math/big"
 	"sort"
 	"sync/atomic"
@@ -37,24 +38,20 @@ type ForkID struct {
 
 // Header represents a block header in the blockchain.
 type Header struct {
-	ParentHash   common.Hash `json:"parentHash"`
-	Coinbase     common.Name `json:"miner"`
-	Root         common.Hash `json:"stateRoot"`
-	TxsRoot      common.Hash `json:"transactionsRoot"`
-	ReceiptsRoot common.Hash `json:"receiptsRoot"`
-	Bloom        Bloom       `json:"logsBloom"`
-	Difficulty   *big.Int    `json:"difficulty"`
-	Number       *big.Int    `json:"number"`
-	GasLimit     uint64      `json:"gasLimit"`
-	GasUsed      uint64      `json:"gasUsed"`
-	Time         *big.Int    `json:"timestamp"`
-	Extra        []byte      `json:"extraData"`
-
-	// cache
-	forkID atomic.Value
-
-	// additional fields (for forward compatibility).
-	AdditionalFields []rlp.RawValue `rlp:"tail"`
+	ParentHash           common.Hash `json:"parentHash"`
+	Coinbase             common.Name `json:"miner"`
+	ProposedIrreversible uint64      `json:"proposedIrreversible"`
+	Root                 common.Hash `json:"stateRoot"`
+	TxsRoot              common.Hash `json:"transactionsRoot"`
+	ReceiptsRoot         common.Hash `json:"receiptsRoot"`
+	Bloom                Bloom       `json:"logsBloom"`
+	Difficulty           *big.Int    `json:"difficulty"`
+	Number               *big.Int    `json:"number"`
+	GasLimit             uint64      `json:"gasLimit"`
+	GasUsed              uint64      `json:"gasUsed"`
+	Time                 *big.Int    `json:"timestamp"`
+	Extra                []byte      `json:"extraData"`
+	ForkID               ForkID      `json:"forkID"`
 }
 
 // Hash returns the block hash of the header, which is simply the keccak256 hash of its
@@ -63,29 +60,14 @@ func (h *Header) Hash() common.Hash { return rlpHash(h) }
 
 // WithForkID store fork id
 func (h *Header) WithForkID(cur, next uint64) {
-	forkID := ForkID{Cur: cur, Next: next}
-	bytes, _ := rlp.EncodeToBytes(forkID)
-	h.AdditionalFields = append(h.AdditionalFields, rlp.RawValue(bytes))
-	h.forkID.Store(forkID)
+	h.ForkID = ForkID{Cur: cur, Next: next}
 }
 
 // CurForkID returns the header's current fork ID.
-func (h *Header) CurForkID() uint64 { return h.getForkID().Cur }
+func (h *Header) CurForkID() uint64 { return h.ForkID.Cur }
 
 // NextForkID returns the header's next fork ID.
-func (h *Header) NextForkID() uint64 { return h.getForkID().Next }
-
-func (h *Header) getForkID() ForkID {
-	if forkID := h.forkID.Load(); forkID != nil {
-		return forkID.(ForkID)
-	}
-	forkID := ForkID{}
-	if len(h.AdditionalFields) > 0 {
-		rlp.DecodeBytes(h.AdditionalFields[0], &forkID)
-		h.forkID.Store(forkID)
-	}
-	return forkID
-}
+func (h *Header) NextForkID() uint64 { return h.ForkID.Next }
 
 // Block represents an entire block in the blockchain.
 type Block struct {
@@ -97,6 +79,12 @@ type Block struct {
 	size atomic.Value
 }
 
+// "external" block encoding. used protocol, etc.
+type extblock struct {
+	Header *Header
+	Txs    []*Transaction
+}
+
 // NewBlock creates a new block. The input data is copied,
 // changes to header and to the field values will not affect the
 // block.
@@ -191,6 +179,14 @@ func (b *Block) EncodeRLP() ([]byte, error) {
 	return rlp.EncodeToBytes(b)
 }
 
+// EncodeRLP serializes b into RLP block format.
+func (b *Block) ExtEncodeRLP(w io.Writer) error {
+	return rlp.Encode(w, extblock{
+		Header: b.Head,
+		Txs:    b.Txs,
+	})
+}
+
 // DecodeRLP decodes the block
 func (b *Block) DecodeRLP(input []byte) error {
 	err := rlp.Decode(bytes.NewReader(input), &b)
@@ -303,7 +299,10 @@ func DeriveReceiptsMerkleRoot(receipts []*Receipt) common.Hash {
 
 func rlpHash(x interface{}) (h common.Hash) {
 	hw := sha3.NewLegacyKeccak256()
-	rlp.Encode(hw, x)
+	err := rlp.Encode(hw, x)
+	if err != nil {
+		panic(fmt.Sprintf("rlp hash encode err: %v", err))
+	}
 	hw.Sum(h[:0])
 	return h
 }
diff --git a/types/block_test.go b/types/block_test.go
index d8baf514..472b7e66 100644
--- a/types/block_test.go
+++ b/types/block_test.go
@@ -68,7 +68,6 @@ func TestBlockForkID(t *testing.T) {
 
 	newBlock := &Block{}
 	assert.NoError(t, newBlock.DecodeRLP(bytes))
-
 	assert.Equal(t, testBlock.CurForkID(), newBlock.CurForkID())
 	assert.Equal(t, testBlock.NextForkID(), newBlock.NextForkID())
 }
diff --git a/types/internal.go b/types/internal.go
new file mode 100644
index 00000000..363ec9e3
--- /dev/null
+++ b/types/internal.go
@@ -0,0 +1,43 @@
+// Copyright 2018 The Fractal Team Authors
+// This file is part of the fractal project.
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+package types
+
+import "github.com/fractalplatform/fractal/common"
+
+type DetailTx struct {
+	TxHash  common.Hash     `json:"txhash"`
+	Actions []*DetailAction `json:"actions"`
+}
+
+type DetailAction struct {
+	InternalActions []*InternalAction `json:"internalActions"`
+}
+
+type InternalAction struct {
+	Action     *RPCAction `json:"action"`
+	ActionType string     `json:"actionType"`
+	GasUsed    uint64     `json:"gasUsed"`
+	GasLimit   uint64     `json:"gasLimit"`
+	Depth      uint64     `json:"depth"`
+	Error      string     `json:"error"`
+}
+
+type BlockAndResult struct {
+	Block     map[string]interface{} `json:"block"`
+	Receipts  []*Receipt             `json:"receipts"`
+	DetailTxs []*DetailTx            `json:"detailTxs"`
+}
diff --git a/types/optinfo.go b/types/optinfo.go
index 234e7e32..87d554cf 100644
--- a/types/optinfo.go
+++ b/types/optinfo.go
@@ -49,3 +49,9 @@ type SnapshotMsg struct {
 	Number uint64
 	Root   common.Hash
 }
+
+type AccountInfo struct {
+	Name  string
+	Key   string
+	Value []byte
+}
diff --git a/types/receipt.go b/types/receipt.go
index ed8cf86d..20780c99 100644
--- a/types/receipt.go
+++ b/types/receipt.go
@@ -31,20 +31,28 @@ const (
 )
 
 // ActionResult represents the results the transaction action.
+type GasDistribution struct {
+	Account string `json:"name"`
+	Gas     uint64 `json:"gas"`
+	TypeID  uint64 `json:"typeId"`
+}
+
 type ActionResult struct {
-	Status  uint64
-	Index   uint64
-	GasUsed uint64
-	Error   string
+	Status   uint64
+	Index    uint64
+	GasUsed  uint64
+	GasAllot []*GasDistribution
+	Error    string
 }
 
 // RPCActionResult that will serialize to the RPC representation of a ActionResult.
 type RPCActionResult struct {
-	ActionType uint64 `json:"actionType"`
-	Status     uint64 `json:"status"`
-	Index      uint64 `json:"index"`
-	GasUsed    uint64 `json:"gasUsed"`
-	Error      string `json:"error"`
+	ActionType uint64             `json:"actionType"`
+	Status     uint64             `json:"status"`
+	Index      uint64             `json:"index"`
+	GasUsed    uint64             `json:"gasUsed"`
+	GasAllot   []*GasDistribution `json:"gasAllot"`
+	Error      string             `json:"error"`
 }
 
 // NewRPCActionResult returns a ActionResult that will serialize to the RPC.
@@ -54,6 +62,7 @@ func (a *ActionResult) NewRPCActionResult(aType ActionType) *RPCActionResult {
 		Status:     a.Status,
 		Index:      a.Index,
 		GasUsed:    a.GasUsed,
+		GasAllot:   a.GasAllot,
 		Error:      a.Error,
 	}
 }
@@ -67,6 +76,7 @@ type Receipt struct {
 	Logs              []*Log
 	TxHash            common.Hash
 	TotalGasUsed      uint64
+	internalTxsLog    *DetailTx
 }
 
 // NewReceipt creates a barebone transaction receipt, copying the init fields.
@@ -162,3 +172,11 @@ func (r *Receipt) ConsensusReceipt() *Receipt {
 	result.Logs = logs
 	return result
 }
+
+func (r *Receipt) GetInternalTxsLog() *DetailTx {
+	return r.internalTxsLog
+}
+
+func (r *Receipt) SetInternalTxsLog(dtxs *DetailTx) {
+	r.internalTxsLog = dtxs
+}
diff --git a/types/receipt_test.go b/types/receipt_test.go
index 41ebad63..d1e20512 100644
--- a/types/receipt_test.go
+++ b/types/receipt_test.go
@@ -27,7 +27,8 @@ import (
 func TestReceiptEncodeAndDecode(t *testing.T) {
 	testR := NewReceipt([]byte("root"), 1000, 1000)
 	testR.Logs = make([]*Log, 0)
-	testR.ActionResults = append(testR.ActionResults, &ActionResult{Status: ReceiptStatusFailed, Index: uint64(0), GasUsed: uint64(100)})
+	gasAllot := make([]*GasDistribution, 0)
+	testR.ActionResults = append(testR.ActionResults, &ActionResult{Status: ReceiptStatusFailed, Index: uint64(0), GasAllot: gasAllot, GasUsed: uint64(100)})
 	bytes, err := rlp.EncodeToBytes(testR)
 	if err != nil {
 		t.Fatal(err)
diff --git a/types/signer.go b/types/signer.go
index 6e7a8be0..a928f278 100644
--- a/types/signer.go
+++ b/types/signer.go
@@ -31,12 +31,23 @@ var (
 	ErrInvalidchainID = errors.New("invalid chain id for signer")
 	//ErrSigUnprotected signature is considered unprotected
 	ErrSigUnprotected = errors.New("signature is considered unprotected")
+	//ErrSignEmpty signature is considered unprotected
+	ErrSignEmpty = errors.New("signature is nil")
 )
 
 // sigCache is used to cache the derived sender and contains the signer used to derive it.
 type sigCache struct {
-	signer Signer
-	pubKey []byte
+	signer  Signer
+	pubKeys []common.PubKey
+}
+
+type KeyPair struct {
+	priv  *ecdsa.PrivateKey
+	index []uint64
+}
+
+func MakeKeyPair(priv *ecdsa.PrivateKey, index []uint64) *KeyPair {
+	return &KeyPair{priv, index}
 }
 
 // MakeSigner returns a Signer based on the given chainID .
@@ -44,35 +55,51 @@ func MakeSigner(chainID *big.Int) Signer {
 	return NewSigner(chainID)
 }
 
-// SignAction signs the action using the given signer and private key
-func SignAction(a *Action, tx *Transaction, s Signer, prv *ecdsa.PrivateKey) error {
+func SignActionWithMultiKey(a *Action, tx *Transaction, s Signer, keys []*KeyPair) error {
 	h := s.Hash(tx)
-	sig, err := crypto.Sign(h[:], prv)
-	if err != nil {
-		return err
+	for _, key := range keys {
+		sig, err := crypto.Sign(h[:], key.priv)
+		if err != nil {
+			return err
+		}
+
+		err = a.WithSignature(s, sig, key.index)
+		if err != nil {
+			return err
+		}
 	}
-	return a.WithSignature(s, sig)
+	return nil
 }
 
-// Recover returns the pubkey derived from the signature (V, R, S) using secp256k1
-// elliptic curve and an error if it failed deriving or upon an incorrect
-// signature.
-func Recover(signer Signer, a *Action, tx *Transaction) (common.PubKey, error) {
+func RecoverMultiKey(signer Signer, a *Action, tx *Transaction) ([]common.PubKey, error) {
 	if sc := a.sender.Load(); sc != nil {
 		sigCache := sc.(sigCache)
 		if sigCache.signer.Equal(signer) {
-			pk := new(common.PubKey)
-			pk.SetBytes(sigCache.pubKey)
-			return *pk, nil
+			return sigCache.pubKeys, nil
 		}
 	}
 
-	pubKey, err := signer.PubKey(a, tx)
+	pubKeys, err := signer.PubKeys(a, tx)
 	if err != nil {
-		return common.PubKey{}, err
+		return []common.PubKey{}, err
 	}
-	a.sender.Store(sigCache{signer: signer, pubKey: pubKey})
-	return common.BytesToPubKey(pubKey), nil
+	a.sender.Store(sigCache{signer: signer, pubKeys: pubKeys})
+	return pubKeys, nil
+}
+
+func StoreAuthorCache(a *Action, authorVersion map[common.Name]uint64) {
+	a.author.Store(authorVersion)
+}
+
+func GetAuthorCache(a *Action) map[common.Name]uint64 {
+	authorVersion := make(map[common.Name]uint64, 0)
+	if ac := a.author.Load(); ac != nil {
+		aCache := ac.(map[common.Name]uint64)
+		for name, version := range aCache {
+			authorVersion[name] = version
+		}
+	}
+	return authorVersion
 }
 
 // Signer implements Signer .
@@ -98,14 +125,25 @@ func (s Signer) Equal(s2 Signer) bool {
 
 var big8 = big.NewInt(8)
 
-// PubKey return Action sender
-func (s Signer) PubKey(a *Action, tx *Transaction) ([]byte, error) {
+func (s Signer) PubKeys(a *Action, tx *Transaction) ([]common.PubKey, error) {
+	if len(a.GetSign()) == 0 {
+		return nil, ErrSignEmpty
+	}
 	if a.ChainID().Cmp(s.chainID) != 0 {
 		return nil, ErrInvalidchainID
 	}
-	V := new(big.Int).Sub(a.data.V, s.chainIDMul)
-	V.Sub(V, big8)
-	return recoverPlain(s.Hash(tx), a.data.R, a.data.S, V, true)
+	var pubKeys []common.PubKey
+	for _, sign := range a.data.Sign {
+		V := new(big.Int).Sub(sign.V, s.chainIDMul)
+		V.Sub(V, big8)
+		data, err := recoverPlain(s.Hash(tx), sign.R, sign.S, V, true)
+		if err != nil {
+			return nil, err
+		}
+		pubKey := common.BytesToPubKey(data)
+		pubKeys = append(pubKeys, pubKey)
+	}
+	return pubKeys, nil
 }
 
 // SignatureValues returns a new transaction with the given signature. This signature
@@ -128,7 +166,7 @@ func (s Signer) SignatureValues(sig []byte) (R, S, V *big.Int, err error) {
 // Hash returns the hash to be signed by the sender.
 func (s Signer) Hash(tx *Transaction) common.Hash {
 	actionHashs := make([]common.Hash, len(tx.GetActions()))
-	for _, a := range tx.GetActions() {
+	for i, a := range tx.GetActions() {
 		hash := rlpHash([]interface{}{
 			a.data.From,
 			a.data.AType,
@@ -139,7 +177,7 @@ func (s Signer) Hash(tx *Transaction) common.Hash {
 			a.data.Payload,
 			s.chainID, uint(0), uint(0),
 		})
-		actionHashs = append(actionHashs, hash)
+		actionHashs[i] = hash
 	}
 
 	return rlpHash([]interface{}{
diff --git a/types/signer_test.go b/types/signer_test.go
index c96ca9dd..9e4acf93 100644
--- a/types/signer_test.go
+++ b/types/signer_test.go
@@ -17,28 +17,66 @@
 package types
 
 import (
-	"bytes"
 	"math/big"
 	"testing"
 
+	"github.com/fractalplatform/fractal/common"
 	"github.com/fractalplatform/fractal/crypto"
 )
 
-func TestSigning(t *testing.T) {
-	key, _ := crypto.GenerateKey()
-	exp := crypto.FromECDSAPub(&key.PublicKey)
-	signer := NewSigner(big.NewInt(18))
-	if err := SignAction(testTx.GetActions()[0], testTx, signer, key); err != nil {
+// func TestSigning(t *testing.T) {
+// 	key, _ := crypto.GenerateKey()
+// 	exp := crypto.FromECDSAPub(&key.PublicKey)
+// 	signer := NewSigner(big.NewInt(18))
+// 	if err := SignAction(testTx.GetActions()[0], testTx, signer, key); err != nil {
+// 		t.Fatal(err)
+// 	}
+
+// 	pubkey, err := Recover(signer, testTx.GetActions()[0], testTx)
+// 	if err != nil {
+// 		t.Fatal(err)
+// 	}
+
+// 	if bytes.Compare(pubkey.Bytes(), exp) != 0 {
+// 		t.Errorf("exected from and address to be equal. Got %x want %x", pubkey, exp)
+// 	}
+// }
+
+func TestSigningMultiKey(t *testing.T) {
+	keys := make([]*KeyPair, 0)
+	pubs := make([]common.PubKey, 0)
+	for i := 0; i < 4; i++ {
+		key, _ := crypto.GenerateKey()
+		exp := crypto.FromECDSAPub(&key.PublicKey)
+		keys = append(keys, &KeyPair{priv: key, index: []uint64{uint64(i)}})
+		pubs = append(pubs, common.BytesToPubKey(exp))
+	}
+	signer := NewSigner(big.NewInt(1))
+	if err := SignActionWithMultiKey(testTx.GetActions()[0], testTx, signer, keys); err != nil {
+		t.Fatal(err)
+	}
+
+	pubkeys, err := RecoverMultiKey(signer, testTx.GetActions()[0], testTx)
+	if err != nil {
 		t.Fatal(err)
 	}
 
-	pubkey, err := Recover(signer, testTx.GetActions()[0], testTx)
+	for i, pubkey := range pubkeys {
+		if pubkey.Compare(pubs[i]) != 0 {
+			t.Errorf("exected from and address to be equal. Got %x want %x", pubkey, pubs[i])
+		}
+	}
+
+	//test cache
+	pubkeys, err = RecoverMultiKey(signer, testTx.GetActions()[0], testTx)
 	if err != nil {
 		t.Fatal(err)
 	}
 
-	if bytes.Compare(pubkey.Bytes(), exp) != 0 {
-		t.Errorf("exected from and address to be equal. Got %x want %x", pubkey, exp)
+	for i, pubkey := range pubkeys {
+		if pubkey.Compare(pubs[i]) != 0 {
+			t.Errorf("exected from and address to be equal. Got %x want %x", pubkey, pubs[i])
+		}
 	}
 }
 
@@ -46,7 +84,8 @@ func TestChainID(t *testing.T) {
 	key, _ := crypto.GenerateKey()
 
 	signer := NewSigner(big.NewInt(1))
-	if err := SignAction(testAction, testTx, signer, key); err != nil {
+	keyPair := MakeKeyPair(key, []uint64{0})
+	if err := SignActionWithMultiKey(testAction, testTx, signer, []*KeyPair{keyPair}); err != nil {
 		t.Fatal(err)
 	}
 
@@ -54,3 +93,17 @@ func TestChainID(t *testing.T) {
 		t.Error("expected chainId to be", signer.chainID, "got", testTx.GetActions()[0].ChainID())
 	}
 }
+
+func TestAuthorCache(t *testing.T) {
+	authorVersion := make(map[common.Name]uint64, 0)
+	authorVersion[common.Name("fromname")] = 1
+	authorVersion[common.Name("toname")] = 10
+	StoreAuthorCache(testAction, authorVersion)
+
+	loadAuthorVeriosn := GetAuthorCache(testAction)
+	for name, version := range loadAuthorVeriosn {
+		if authorVersion[name] != version {
+			t.Error("expected version to be", authorVersion[name], "got", version)
+		}
+	}
+}
diff --git a/vendor/golang.org/x/crypto/pbkdf2/pbkdf2.go b/vendor/golang.org/x/crypto/pbkdf2/pbkdf2.go
deleted file mode 100644
index 593f6530..00000000
--- a/vendor/golang.org/x/crypto/pbkdf2/pbkdf2.go
+++ /dev/null
@@ -1,77 +0,0 @@
-// Copyright 2012 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-/*
-Package pbkdf2 implements the key derivation function PBKDF2 as defined in RFC
-2898 / PKCS #5 v2.0.
-
-A key derivation function is useful when encrypting data based on a password
-or any other not-fully-random data. It uses a pseudorandom function to derive
-a secure encryption key based on the password.
-
-While v2.0 of the standard defines only one pseudorandom function to use,
-HMAC-SHA1, the drafted v2.1 specification allows use of all five FIPS Approved
-Hash Functions SHA-1, SHA-224, SHA-256, SHA-384 and SHA-512 for HMAC. To
-choose, you can pass the `New` functions from the different SHA packages to
-pbkdf2.Key.
-*/
-package pbkdf2 // import "golang.org/x/crypto/pbkdf2"
-
-import (
-	"crypto/hmac"
-	"hash"
-)
-
-// Key derives a key from the password, salt and iteration count, returning a
-// []byte of length keylen that can be used as cryptographic key. The key is
-// derived based on the method described as PBKDF2 with the HMAC variant using
-// the supplied hash function.
-//
-// For example, to use a HMAC-SHA-1 based PBKDF2 key derivation function, you
-// can get a derived key for e.g. AES-256 (which needs a 32-byte key) by
-// doing:
-//
-// 	dk := pbkdf2.Key([]byte("some password"), salt, 4096, 32, sha1.New)
-//
-// Remember to get a good random salt. At least 8 bytes is recommended by the
-// RFC.
-//
-// Using a higher iteration count will increase the cost of an exhaustive
-// search but will also make derivation proportionally slower.
-func Key(password, salt []byte, iter, keyLen int, h func() hash.Hash) []byte {
-	prf := hmac.New(h, password)
-	hashLen := prf.Size()
-	numBlocks := (keyLen + hashLen - 1) / hashLen
-
-	var buf [4]byte
-	dk := make([]byte, 0, numBlocks*hashLen)
-	U := make([]byte, hashLen)
-	for block := 1; block <= numBlocks; block++ {
-		// N.B.: || means concatenation, ^ means XOR
-		// for each block T_i = U_1 ^ U_2 ^ ... ^ U_iter
-		// U_1 = PRF(password, salt || uint(i))
-		prf.Reset()
-		prf.Write(salt)
-		buf[0] = byte(block >> 24)
-		buf[1] = byte(block >> 16)
-		buf[2] = byte(block >> 8)
-		buf[3] = byte(block)
-		prf.Write(buf[:4])
-		dk = prf.Sum(dk)
-		T := dk[len(dk)-hashLen:]
-		copy(U, T)
-
-		// U_n = PRF(password, U_(n-1))
-		for n := 2; n <= iter; n++ {
-			prf.Reset()
-			prf.Write(U)
-			U = U[:0]
-			U = prf.Sum(U)
-			for x := range U {
-				T[x] ^= U[x]
-			}
-		}
-	}
-	return dk[:keyLen]
-}
diff --git a/vendor/golang.org/x/crypto/scrypt/scrypt.go b/vendor/golang.org/x/crypto/scrypt/scrypt.go
deleted file mode 100644
index 3362afd1..00000000
--- a/vendor/golang.org/x/crypto/scrypt/scrypt.go
+++ /dev/null
@@ -1,244 +0,0 @@
-// Copyright 2012 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// Package scrypt implements the scrypt key derivation function as defined in
-// Colin Percival's paper "Stronger Key Derivation via Sequential Memory-Hard
-// Functions" (https://www.tarsnap.com/scrypt/scrypt.pdf).
-package scrypt // import "golang.org/x/crypto/scrypt"
-
-import (
-	"crypto/sha256"
-	"errors"
-
-	"golang.org/x/crypto/pbkdf2"
-)
-
-const maxInt = int(^uint(0) >> 1)
-
-// blockCopy copies n numbers from src into dst.
-func blockCopy(dst, src []uint32, n int) {
-	copy(dst, src[:n])
-}
-
-// blockXOR XORs numbers from dst with n numbers from src.
-func blockXOR(dst, src []uint32, n int) {
-	for i, v := range src[:n] {
-		dst[i] ^= v
-	}
-}
-
-// salsaXOR applies Salsa20/8 to the XOR of 16 numbers from tmp and in,
-// and puts the result into both tmp and out.
-func salsaXOR(tmp *[16]uint32, in, out []uint32) {
-	w0 := tmp[0] ^ in[0]
-	w1 := tmp[1] ^ in[1]
-	w2 := tmp[2] ^ in[2]
-	w3 := tmp[3] ^ in[3]
-	w4 := tmp[4] ^ in[4]
-	w5 := tmp[5] ^ in[5]
-	w6 := tmp[6] ^ in[6]
-	w7 := tmp[7] ^ in[7]
-	w8 := tmp[8] ^ in[8]
-	w9 := tmp[9] ^ in[9]
-	w10 := tmp[10] ^ in[10]
-	w11 := tmp[11] ^ in[11]
-	w12 := tmp[12] ^ in[12]
-	w13 := tmp[13] ^ in[13]
-	w14 := tmp[14] ^ in[14]
-	w15 := tmp[15] ^ in[15]
-
-	x0, x1, x2, x3, x4, x5, x6, x7, x8 := w0, w1, w2, w3, w4, w5, w6, w7, w8
-	x9, x10, x11, x12, x13, x14, x15 := w9, w10, w11, w12, w13, w14, w15
-
-	for i := 0; i < 8; i += 2 {
-		u := x0 + x12
-		x4 ^= u<<7 | u>>(32-7)
-		u = x4 + x0
-		x8 ^= u<<9 | u>>(32-9)
-		u = x8 + x4
-		x12 ^= u<<13 | u>>(32-13)
-		u = x12 + x8
-		x0 ^= u<<18 | u>>(32-18)
-
-		u = x5 + x1
-		x9 ^= u<<7 | u>>(32-7)
-		u = x9 + x5
-		x13 ^= u<<9 | u>>(32-9)
-		u = x13 + x9
-		x1 ^= u<<13 | u>>(32-13)
-		u = x1 + x13
-		x5 ^= u<<18 | u>>(32-18)
-
-		u = x10 + x6
-		x14 ^= u<<7 | u>>(32-7)
-		u = x14 + x10
-		x2 ^= u<<9 | u>>(32-9)
-		u = x2 + x14
-		x6 ^= u<<13 | u>>(32-13)
-		u = x6 + x2
-		x10 ^= u<<18 | u>>(32-18)
-
-		u = x15 + x11
-		x3 ^= u<<7 | u>>(32-7)
-		u = x3 + x15
-		x7 ^= u<<9 | u>>(32-9)
-		u = x7 + x3
-		x11 ^= u<<13 | u>>(32-13)
-		u = x11 + x7
-		x15 ^= u<<18 | u>>(32-18)
-
-		u = x0 + x3
-		x1 ^= u<<7 | u>>(32-7)
-		u = x1 + x0
-		x2 ^= u<<9 | u>>(32-9)
-		u = x2 + x1
-		x3 ^= u<<13 | u>>(32-13)
-		u = x3 + x2
-		x0 ^= u<<18 | u>>(32-18)
-
-		u = x5 + x4
-		x6 ^= u<<7 | u>>(32-7)
-		u = x6 + x5
-		x7 ^= u<<9 | u>>(32-9)
-		u = x7 + x6
-		x4 ^= u<<13 | u>>(32-13)
-		u = x4 + x7
-		x5 ^= u<<18 | u>>(32-18)
-
-		u = x10 + x9
-		x11 ^= u<<7 | u>>(32-7)
-		u = x11 + x10
-		x8 ^= u<<9 | u>>(32-9)
-		u = x8 + x11
-		x9 ^= u<<13 | u>>(32-13)
-		u = x9 + x8
-		x10 ^= u<<18 | u>>(32-18)
-
-		u = x15 + x14
-		x12 ^= u<<7 | u>>(32-7)
-		u = x12 + x15
-		x13 ^= u<<9 | u>>(32-9)
-		u = x13 + x12
-		x14 ^= u<<13 | u>>(32-13)
-		u = x14 + x13
-		x15 ^= u<<18 | u>>(32-18)
-	}
-	x0 += w0
-	x1 += w1
-	x2 += w2
-	x3 += w3
-	x4 += w4
-	x5 += w5
-	x6 += w6
-	x7 += w7
-	x8 += w8
-	x9 += w9
-	x10 += w10
-	x11 += w11
-	x12 += w12
-	x13 += w13
-	x14 += w14
-	x15 += w15
-
-	out[0], tmp[0] = x0, x0
-	out[1], tmp[1] = x1, x1
-	out[2], tmp[2] = x2, x2
-	out[3], tmp[3] = x3, x3
-	out[4], tmp[4] = x4, x4
-	out[5], tmp[5] = x5, x5
-	out[6], tmp[6] = x6, x6
-	out[7], tmp[7] = x7, x7
-	out[8], tmp[8] = x8, x8
-	out[9], tmp[9] = x9, x9
-	out[10], tmp[10] = x10, x10
-	out[11], tmp[11] = x11, x11
-	out[12], tmp[12] = x12, x12
-	out[13], tmp[13] = x13, x13
-	out[14], tmp[14] = x14, x14
-	out[15], tmp[15] = x15, x15
-}
-
-func blockMix(tmp *[16]uint32, in, out []uint32, r int) {
-	blockCopy(tmp[:], in[(2*r-1)*16:], 16)
-	for i := 0; i < 2*r; i += 2 {
-		salsaXOR(tmp, in[i*16:], out[i*8:])
-		salsaXOR(tmp, in[i*16+16:], out[i*8+r*16:])
-	}
-}
-
-func integer(b []uint32, r int) uint64 {
-	j := (2*r - 1) * 16
-	return uint64(b[j]) | uint64(b[j+1])<<32
-}
-
-func smix(b []byte, r, N int, v, xy []uint32) {
-	var tmp [16]uint32
-	x := xy
-	y := xy[32*r:]
-
-	j := 0
-	for i := 0; i < 32*r; i++ {
-		x[i] = uint32(b[j]) | uint32(b[j+1])<<8 | uint32(b[j+2])<<16 | uint32(b[j+3])<<24
-		j += 4
-	}
-	for i := 0; i < N; i += 2 {
-		blockCopy(v[i*(32*r):], x, 32*r)
-		blockMix(&tmp, x, y, r)
-
-		blockCopy(v[(i+1)*(32*r):], y, 32*r)
-		blockMix(&tmp, y, x, r)
-	}
-	for i := 0; i < N; i += 2 {
-		j := int(integer(x, r) & uint64(N-1))
-		blockXOR(x, v[j*(32*r):], 32*r)
-		blockMix(&tmp, x, y, r)
-
-		j = int(integer(y, r) & uint64(N-1))
-		blockXOR(y, v[j*(32*r):], 32*r)
-		blockMix(&tmp, y, x, r)
-	}
-	j = 0
-	for _, v := range x[:32*r] {
-		b[j+0] = byte(v >> 0)
-		b[j+1] = byte(v >> 8)
-		b[j+2] = byte(v >> 16)
-		b[j+3] = byte(v >> 24)
-		j += 4
-	}
-}
-
-// Key derives a key from the password, salt, and cost parameters, returning
-// a byte slice of length keyLen that can be used as cryptographic key.
-//
-// N is a CPU/memory cost parameter, which must be a power of two greater than 1.
-// r and p must satisfy r * p < 2³⁰. If the parameters do not satisfy the
-// limits, the function returns a nil byte slice and an error.
-//
-// For example, you can get a derived key for e.g. AES-256 (which needs a
-// 32-byte key) by doing:
-//
-//      dk, err := scrypt.Key([]byte("some password"), salt, 32768, 8, 1, 32)
-//
-// The recommended parameters for interactive logins as of 2017 are N=32768, r=8
-// and p=1. The parameters N, r, and p should be increased as memory latency and
-// CPU parallelism increases; consider setting N to the highest power of 2 you
-// can derive within 100 milliseconds. Remember to get a good random salt.
-func Key(password, salt []byte, N, r, p, keyLen int) ([]byte, error) {
-	if N <= 1 || N&(N-1) != 0 {
-		return nil, errors.New("scrypt: N must be > 1 and a power of 2")
-	}
-	if uint64(r)*uint64(p) >= 1<<30 || r > maxInt/128/p || r > maxInt/256 || N > maxInt/128/r {
-		return nil, errors.New("scrypt: parameters are too large")
-	}
-
-	xy := make([]uint32, 64*r)
-	v := make([]uint32, 32*N*r)
-	b := pbkdf2.Key(password, salt, 1, p*128*r, sha256.New)
-
-	for i := 0; i < p; i++ {
-		smix(b[i*128*r:], r, N, v, xy)
-	}
-
-	return pbkdf2.Key(password, b, 1, keyLen, sha256.New), nil
-}
diff --git a/vendor/golang.org/x/crypto/sha3/shake.go b/vendor/golang.org/x/crypto/sha3/shake.go
index 97c9b062..a39e5d51 100644
--- a/vendor/golang.org/x/crypto/sha3/shake.go
+++ b/vendor/golang.org/x/crypto/sha3/shake.go
@@ -5,10 +5,18 @@
 package sha3
 
 // This file defines the ShakeHash interface, and provides
-// functions for creating SHAKE instances, as well as utility
+// functions for creating SHAKE and cSHAKE instances, as well as utility
 // functions for hashing bytes to arbitrary-length output.
+//
+//
+// SHAKE implementation is based on FIPS PUB 202 [1]
+// cSHAKE implementations is based on NIST SP 800-185 [2]
+//
+// [1] https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf
+// [2] https://doi.org/10.6028/NIST.SP.800-185
 
 import (
+	"encoding/binary"
 	"io"
 )
 
@@ -31,8 +39,77 @@ type ShakeHash interface {
 	Reset()
 }
 
-func (d *state) Clone() ShakeHash {
-	return d.clone()
+// cSHAKE specific context
+type cshakeState struct {
+	state // SHA-3 state context and Read/Write operations
+
+	// initBlock is the cSHAKE specific initialization set of bytes. It is initialized
+	// by newCShake function and stores concatenation of N followed by S, encoded
+	// by the method specified in 3.3 of [1].
+	// It is stored here in order for Reset() to be able to put context into
+	// initial state.
+	initBlock []byte
+}
+
+// Consts for configuring initial SHA-3 state
+const (
+	dsbyteShake  = 0x1f
+	dsbyteCShake = 0x04
+	rate128      = 168
+	rate256      = 136
+)
+
+func bytepad(input []byte, w int) []byte {
+	// leftEncode always returns max 9 bytes
+	buf := make([]byte, 0, 9+len(input)+w)
+	buf = append(buf, leftEncode(uint64(w))...)
+	buf = append(buf, input...)
+	padlen := w - (len(buf) % w)
+	return append(buf, make([]byte, padlen)...)
+}
+
+func leftEncode(value uint64) []byte {
+	var b [9]byte
+	binary.BigEndian.PutUint64(b[1:], value)
+	// Trim all but last leading zero bytes
+	i := byte(1)
+	for i < 8 && b[i] == 0 {
+		i++
+	}
+	// Prepend number of encoded bytes
+	b[i-1] = 9 - i
+	return b[i-1:]
+}
+
+func newCShake(N, S []byte, rate int, dsbyte byte) ShakeHash {
+	c := cshakeState{state: state{rate: rate, dsbyte: dsbyte}}
+
+	// leftEncode returns max 9 bytes
+	c.initBlock = make([]byte, 0, 9*2+len(N)+len(S))
+	c.initBlock = append(c.initBlock, leftEncode(uint64(len(N)*8))...)
+	c.initBlock = append(c.initBlock, N...)
+	c.initBlock = append(c.initBlock, leftEncode(uint64(len(S)*8))...)
+	c.initBlock = append(c.initBlock, S...)
+	c.Write(bytepad(c.initBlock, c.rate))
+	return &c
+}
+
+// Reset resets the hash to initial state.
+func (c *cshakeState) Reset() {
+	c.state.Reset()
+	c.Write(bytepad(c.initBlock, c.rate))
+}
+
+// Clone returns copy of a cSHAKE context within its current state.
+func (c *cshakeState) Clone() ShakeHash {
+	b := make([]byte, len(c.initBlock))
+	copy(b, c.initBlock)
+	return &cshakeState{state: *c.clone(), initBlock: b}
+}
+
+// Clone returns copy of SHAKE context within its current state.
+func (c *state) Clone() ShakeHash {
+	return c.clone()
 }
 
 // NewShake128 creates a new SHAKE128 variable-output-length ShakeHash.
@@ -42,7 +119,7 @@ func NewShake128() ShakeHash {
 	if h := newShake128Asm(); h != nil {
 		return h
 	}
-	return &state{rate: 168, dsbyte: 0x1f}
+	return &state{rate: rate128, dsbyte: dsbyteShake}
 }
 
 // NewShake256 creates a new SHAKE256 variable-output-length ShakeHash.
@@ -52,7 +129,33 @@ func NewShake256() ShakeHash {
 	if h := newShake256Asm(); h != nil {
 		return h
 	}
-	return &state{rate: 136, dsbyte: 0x1f}
+	return &state{rate: rate256, dsbyte: dsbyteShake}
+}
+
+// NewCShake128 creates a new instance of cSHAKE128 variable-output-length ShakeHash,
+// a customizable variant of SHAKE128.
+// N is used to define functions based on cSHAKE, it can be empty when plain cSHAKE is
+// desired. S is a customization byte string used for domain separation - two cSHAKE
+// computations on same input with different S yield unrelated outputs.
+// When N and S are both empty, this is equivalent to NewShake128.
+func NewCShake128(N, S []byte) ShakeHash {
+	if len(N) == 0 && len(S) == 0 {
+		return NewShake128()
+	}
+	return newCShake(N, S, rate128, dsbyteCShake)
+}
+
+// NewCShake256 creates a new instance of cSHAKE256 variable-output-length ShakeHash,
+// a customizable variant of SHAKE256.
+// N is used to define functions based on cSHAKE, it can be empty when plain cSHAKE is
+// desired. S is a customization byte string used for domain separation - two cSHAKE
+// computations on same input with different S yield unrelated outputs.
+// When N and S are both empty, this is equivalent to NewShake256.
+func NewCShake256(N, S []byte) ShakeHash {
+	if len(N) == 0 && len(S) == 0 {
+		return NewShake256()
+	}
+	return newCShake(N, S, rate256, dsbyteCShake)
 }
 
 // ShakeSum128 writes an arbitrary-length digest of data into hash.
diff --git a/vendor/gopkg.in/yaml.v2/README.md b/vendor/gopkg.in/yaml.v2/README.md
index b50c6e87..baef58a7 100644
--- a/vendor/gopkg.in/yaml.v2/README.md
+++ b/vendor/gopkg.in/yaml.v2/README.md
@@ -36,7 +36,7 @@ If opened in a browser, the import path itself leads to the API documentation:
 API stability
 -------------
 
-The package API for yaml v2 will remain stable as described in [gopkg.in](https://gopkg.in).
+The package rpcapi for yaml v2 will remain stable as described in [gopkg.in](https://gopkg.in).
 
 
 License
diff --git a/vendor/vendor.json b/vendor/vendor.json
index 3510af48..38ae6a1a 100644
--- a/vendor/vendor.json
+++ b/vendor/vendor.json
@@ -458,29 +458,17 @@
 			"revision": "c3a204f8e96543bb0cc090385c001078f184fc46",
 			"revisionTime": "2019-03-18T03:00:20Z"
 		},
-		{
-			"checksumSHA1": "1MGpGDQqnUoRpv7VEcQrXOBydXE=",
-			"path": "golang.org/x/crypto/pbkdf2",
-			"revision": "a1f597ede03a7bef967a422b5b3a5bd08805a01e",
-			"revisionTime": "2019-02-05T21:23:42Z"
-		},
 		{
 			"checksumSHA1": "UAbH5s3v5AfEvbGMEQAyzSFCMU0=",
 			"path": "golang.org/x/crypto/ripemd160",
-			"revision": "a1f597ede03a7bef967a422b5b3a5bd08805a01e",
-			"revisionTime": "2019-02-05T21:23:42Z"
-		},
-		{
-			"checksumSHA1": "q+Rqy6Spw6qDSj75TGEZF7nzoFM=",
-			"path": "golang.org/x/crypto/scrypt",
-			"revision": "a1f597ede03a7bef967a422b5b3a5bd08805a01e",
-			"revisionTime": "2019-02-05T21:23:42Z"
+			"revision": "df01cb2cc480549d72034218dd98bf97671450ac",
+			"revisionTime": "2019-04-17T08:53:58Z"
 		},
 		{
-			"checksumSHA1": "asZBHvcTKF5gVlI7AYnMlLXRYys=",
+			"checksumSHA1": "jBttuA4t/SdGUb+M2kBHmrGOmRs=",
 			"path": "golang.org/x/crypto/sha3",
-			"revision": "a1f597ede03a7bef967a422b5b3a5bd08805a01e",
-			"revisionTime": "2019-02-05T21:23:42Z"
+			"revision": "df01cb2cc480549d72034218dd98bf97671450ac",
+			"revisionTime": "2019-04-17T08:53:58Z"
 		},
 		{
 			"checksumSHA1": "F+tqxPGFt5x7DKZakbbMmENX1oQ=",
diff --git a/wallet/cache/account.go b/wallet/cache/account.go
deleted file mode 100644
index 91d89905..00000000
--- a/wallet/cache/account.go
+++ /dev/null
@@ -1,75 +0,0 @@
-// Copyright 2018 The Fractal Team Authors
-// This file is part of the fractal project.
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-package cache
-
-import (
-	"sort"
-	"strings"
-
-	"github.com/fractalplatform/fractal/common"
-)
-
-// Account represents an fractal account.
-type Account struct {
-	Addr      common.Address `json:"address"` // account address derived from the key.
-	Path      string         `json:"path"`    // key json file path.
-	PublicKey string         `json:"publicKey"`
-}
-
-// Cmp compares x and y and returns:
-//
-//   -1 if x <  y
-//    0 if x == y
-//   +1 if x >  y
-//
-func (a Account) Cmp(account Account) int {
-	return strings.Compare(a.Path, account.Path)
-}
-
-// Accounts  is a Account slice type.
-type Accounts []Account
-
-func (as Accounts) drop(accounts ...Account) Accounts {
-	for _, account := range accounts {
-		index := sort.Search(len(as), func(i int) bool {
-			return as[i].Cmp(account) >= 0
-		})
-		if index == len(as) {
-			as = append(as, account)
-			continue
-		}
-		as = append(as[:index], append([]Account{account}, as[index:]...)...)
-	}
-	return as
-}
-
-func (as Accounts) merge(accounts ...Account) Accounts {
-	for _, account := range accounts {
-		index := sort.Search(len(as), func(i int) bool {
-			return as[i].Cmp(account) >= 0
-		})
-		if index == len(as) {
-			continue
-		}
-		as = append(as[:index], as[index+1:]...)
-	}
-	return as
-}
-
-func (as Accounts) Len() int           { return len(as) }
-func (as Accounts) Less(i, j int) bool { return as[i].Cmp(as[j]) < 0 }
-func (as Accounts) Swap(i, j int)      { as[i], as[j] = as[j], as[i] }
diff --git a/wallet/cache/accountcache.go b/wallet/cache/accountcache.go
deleted file mode 100644
index 69dd99d5..00000000
--- a/wallet/cache/accountcache.go
+++ /dev/null
@@ -1,174 +0,0 @@
-// Copyright 2018 The Fractal Team Authors
-// This file is part of the fractal project.
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-package cache
-
-import (
-	"sort"
-	"sync"
-	"time"
-
-	"github.com/ethereum/go-ethereum/log"
-	"github.com/fractalplatform/fractal/common"
-	"github.com/fractalplatform/fractal/wallet/keystore"
-)
-
-const reloadInterval = 2 * time.Second
-
-// AccountCache is a live index of all accounts in the keystore.
-type AccountCache struct {
-	sync.Mutex
-	keydir      string
-	cache       fileCache
-	reloadTimer *time.Timer
-	accountsMap map[common.Address]Account
-}
-
-// NewAccountCache creates a account cache.
-func NewAccountCache(keydir string) *AccountCache {
-	ac := &AccountCache{
-		keydir:      keydir,
-		cache:       fileCache{all: make(map[string]interface{})},
-		accountsMap: make(map[common.Address]Account),
-	}
-	return ac
-}
-
-// Accounts returns all accounts in cacahe.
-func (ac *AccountCache) Accounts() Accounts {
-	ac.Reload()
-	ac.Lock()
-	defer ac.Unlock()
-	var cpy Accounts
-	for _, a := range ac.accountsMap {
-		cpy = append(cpy, a)
-	}
-	sort.Sort(cpy)
-	return cpy
-}
-
-// Reload reload cache.
-func (ac *AccountCache) Reload() {
-	ac.Lock()
-	if ac.reloadTimer == nil {
-		ac.reloadTimer = time.NewTimer(0)
-	} else {
-		select {
-		case <-ac.reloadTimer.C:
-		default:
-			ac.Unlock()
-			return // The cache was reloaded recently.
-		}
-	}
-	ac.reloadTimer.Reset(reloadInterval)
-	ac.Unlock()
-	ac.updateAccounts()
-}
-
-// Find find account by address.
-func (ac *AccountCache) Find(addr common.Address) *Account {
-	ac.Reload()
-	ac.Lock()
-	defer ac.Unlock()
-	a, ok := ac.accountsMap[addr]
-	if !ok {
-		return nil
-	}
-	return &a
-}
-
-// Close close account cache.
-func (ac *AccountCache) Close() {
-	ac.Lock()
-	if ac.reloadTimer != nil {
-		ac.reloadTimer.Stop()
-	}
-	ac.Unlock()
-}
-
-// Has check whether a key with the given address in cache.
-func (ac *AccountCache) Has(addr common.Address) bool {
-	ac.Reload()
-	ac.Lock()
-	defer ac.Unlock()
-	if _, ok := ac.accountsMap[addr]; ok {
-		return true
-	}
-	return false
-}
-
-// Add add a new acount in cache.
-func (ac *AccountCache) Add(new Account) {
-	ac.Lock()
-	defer ac.Unlock()
-	ac.accountsMap[new.Addr] = new
-}
-
-// Delete delete a account in cache.
-func (ac *AccountCache) Delete(addr common.Address) {
-	ac.Lock()
-	defer ac.Unlock()
-	delete(ac.accountsMap, addr)
-}
-
-func (ac *AccountCache) updateAccounts() error {
-	creates, deletes, updates, err := ac.cache.scan(ac.keydir)
-	if err != nil {
-		return err
-	}
-
-	if len(creates) == 0 && len(deletes) == 0 && len(updates) == 0 {
-		return nil
-	}
-
-	for _, path := range creates {
-		if a := readAccount(path); a != nil {
-			ac.Add(*a)
-		}
-	}
-	for _, path := range deletes {
-		if a := readAccount(path); a != nil {
-			ac.Delete(a.Addr)
-		}
-	}
-	for _, path := range updates {
-		if a := readAccount(path); a != nil {
-			ac.Add(*a)
-		}
-	}
-
-	return nil
-}
-
-func readAccount(path string) *Account {
-	if len(path) < 40 {
-		log.Error("invalid path", "path", path)
-		return nil
-	}
-	if common.IsHexAddress(path[len(path)-40:]) {
-		ks := &keystore.KeyStore{DirPath: "", ScryptN: 0, ScryptP: 0}
-		publicKey, err := ks.GetPublicKey(path)
-		if err != nil {
-			return nil
-		}
-		return &Account{
-			Addr:      common.HexToAddress(path[len(path)-40:]),
-			Path:      path,
-			PublicKey: publicKey,
-		}
-	}
-	return nil
-}
diff --git a/wallet/cache/accountcache_test.go b/wallet/cache/accountcache_test.go
deleted file mode 100644
index e28c803f..00000000
--- a/wallet/cache/accountcache_test.go
+++ /dev/null
@@ -1,92 +0,0 @@
-// Copyright 2018 The Fractal Team Authors
-// This file is part of the fractal project.
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-package cache
-
-import (
-	"encoding/hex"
-	"fmt"
-	"io/ioutil"
-	"os"
-	"sort"
-	"testing"
-	"time"
-
-	"github.com/fractalplatform/fractal/common"
-	"github.com/fractalplatform/fractal/crypto"
-	"github.com/stretchr/testify/assert"
-)
-
-func TestCache(t *testing.T) {
-	d, err := ioutil.TempDir("", "")
-	if err != nil {
-		t.Fatal(err)
-	}
-	defer os.RemoveAll(d)
-
-	cache := NewAccountCache(d)
-
-	var accs Accounts
-	for i := 0; i < 7; i++ {
-		addr := crypto.CreateAddress(common.Address{}, uint64(i))
-		account := Account{Addr: addr, Path: keyFileName(addr)}
-		cache.Add(account)
-		accs = append(accs, account)
-	}
-
-	wantAccounts := make(Accounts, len(accs))
-	copy(wantAccounts, accs)
-	sort.Sort(wantAccounts)
-
-	// test cache.Accounts
-	list := cache.Accounts()
-	assert.Equal(t, wantAccounts, list)
-
-	// test cache.Has
-	for _, a := range accs {
-		assert.Equal(t, true, cache.Has(a.Addr))
-	}
-
-	for i := 0; i < len(accs); i += 2 {
-		cache.Delete(wantAccounts[i].Addr)
-	}
-
-	// Check content again after deletion.
-	wantAccountsAfterDelete := Accounts{
-		wantAccounts[1],
-		wantAccounts[3],
-		wantAccounts[5],
-	}
-
-	list = cache.Accounts()
-	assert.Equal(t, wantAccountsAfterDelete, list)
-
-}
-
-func keyFileName(keyAddr common.Address) string {
-	toISO8601 := func(t time.Time) string {
-		var tz string
-		name, offset := t.Zone()
-		if name == "UTC" {
-			tz = "Z"
-		} else {
-			tz = fmt.Sprintf("%03d00", offset/3600)
-		}
-		return fmt.Sprintf("%04d-%02d-%02dT%02d-%02d-%02d.%09d%s", t.Year(), t.Month(), t.Day(), t.Hour(), t.Minute(), t.Second(), t.Nanosecond(), tz)
-	}
-
-	return fmt.Sprintf("UTC--%s--%s", toISO8601(time.Now().UTC()), hex.EncodeToString(keyAddr[:]))
-}
diff --git a/wallet/cache/filecache.go b/wallet/cache/filecache.go
deleted file mode 100644
index 99cda981..00000000
--- a/wallet/cache/filecache.go
+++ /dev/null
@@ -1,105 +0,0 @@
-// Copyright 2018 The Fractal Team Authors
-// This file is part of the fractal project.
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-package cache
-
-import (
-	"io/ioutil"
-	"os"
-	"path/filepath"
-	"strings"
-	"sync"
-	"time"
-
-	"github.com/ethereum/go-ethereum/log"
-)
-
-type fileCache struct {
-	all          map[string]interface{}
-	lastModified time.Time
-	mu           sync.RWMutex
-}
-
-func (fc *fileCache) scan(keyDir string) (creates, deletes, updates []string, err error) {
-	// List all the failes from the keystore folder
-	files, err := ioutil.ReadDir(keyDir)
-	if err != nil {
-		return nil, nil, nil, err
-	}
-
-	fc.mu.Lock()
-	defer fc.mu.Unlock()
-
-	// Iterate all the files and gather their metadata
-	all := make(map[string]interface{})
-	mods := make(map[string]interface{})
-	createsmap := make(map[string]interface{})
-
-	var newLastMod time.Time
-	for _, fi := range files {
-		path := filepath.Join(keyDir, fi.Name())
-		if !isKeyFile(fi) {
-			log.Trace("Ignoring file on account scan", "path", path)
-			continue
-		}
-
-		all[path] = struct{}{}
-
-		modified := fi.ModTime()
-		if modified.After(fc.lastModified) {
-			mods[path] = struct{}{}
-		}
-		if modified.After(newLastMod) {
-			newLastMod = modified
-		}
-	}
-
-	// Update the tracked files and return the three path slice
-	deletes = difference(fc.all, all) // Deletes = previous - current
-	creates = difference(all, fc.all) // Creates = current - previous
-
-	for _, v := range creates {
-		createsmap[v] = struct{}{}
-	}
-
-	updates = difference(mods, createsmap) // Updates = modified - creates
-
-	fc.all, fc.lastModified = all, newLastMod
-
-	return creates, deletes, updates, nil
-}
-
-// difference Returns the difference between x and y. The returned string slice
-// will contain all elements of x that are not also elements of y.
-func difference(x, y map[string]interface{}) []string {
-	var result []string
-	for elem := range x {
-		if _, ok := y[elem]; !ok {
-			result = append(result, elem)
-		}
-	}
-	return result
-}
-
-func isKeyFile(fi os.FileInfo) bool {
-	if strings.HasSuffix(fi.Name(), "~") || strings.HasPrefix(fi.Name(), ".") {
-		return false
-	}
-	if fi.IsDir() || fi.Mode()&os.ModeType != 0 {
-		return false
-	}
-	return true
-}
diff --git a/wallet/keystore/key.go b/wallet/keystore/key.go
deleted file mode 100644
index c5555e9b..00000000
--- a/wallet/keystore/key.go
+++ /dev/null
@@ -1,77 +0,0 @@
-// Copyright 2018 The Fractal Team Authors
-// This file is part of the fractal project.
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-package keystore
-
-import (
-	"crypto/ecdsa"
-	"io"
-	"io/ioutil"
-	"os"
-	"path/filepath"
-
-	"github.com/fractalplatform/fractal/common"
-	"github.com/fractalplatform/fractal/crypto"
-)
-
-// Key represents a key struct contains address and private key.
-type Key struct {
-	Addr       common.Address
-	PrivateKey *ecdsa.PrivateKey
-}
-
-// NewKey generates a new key.
-func NewKey(rand io.Reader) (*Key, error) {
-	privateKeyECDSA, err := ecdsa.GenerateKey(crypto.S256(), rand)
-	if err != nil {
-		return nil, err
-	}
-
-	return &Key{
-		Addr:       crypto.PubkeyToAddress(privateKeyECDSA.PublicKey),
-		PrivateKey: privateKeyECDSA,
-	}, nil
-}
-
-func writeTemporaryKeyFile(file string, content []byte) (string, error) {
-	// Create the keystore directory with appropriate permissions
-	// in case it is not present yet.
-	const dirPerm = 0700
-	if err := os.MkdirAll(filepath.Dir(file), dirPerm); err != nil {
-		return "", err
-	}
-	// Atomic write: create a temporary hidden file first
-	// then move it into place. TempFile assigns mode 0600.
-	f, err := ioutil.TempFile(filepath.Dir(file), "."+filepath.Base(file)+".tmp")
-	if err != nil {
-		return "", err
-	}
-	if _, err := f.Write(content); err != nil {
-		f.Close()
-		os.Remove(f.Name())
-		return "", err
-	}
-	f.Close()
-	return f.Name(), nil
-}
-
-func writeKeyFile(file string, content []byte) error {
-	name, err := writeTemporaryKeyFile(file, content)
-	if err != nil {
-		return err
-	}
-	return os.Rename(name, file)
-}
diff --git a/wallet/keystore/keyjson.go b/wallet/keystore/keyjson.go
deleted file mode 100644
index f18b43ec..00000000
--- a/wallet/keystore/keyjson.go
+++ /dev/null
@@ -1,155 +0,0 @@
-// Copyright 2018 The Fractal Team Authors
-// This file is part of the fractal project.
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-package keystore
-
-import (
-	"bytes"
-	"crypto/aes"
-	"crypto/cipher"
-	"crypto/rand"
-	"encoding/hex"
-	"github.com/ethereum/go-ethereum/common/hexutil"
-	"io"
-
-	"github.com/ethereum/go-ethereum/common/math"
-	"github.com/fractalplatform/fractal/crypto"
-	"golang.org/x/crypto/scrypt"
-)
-
-const (
-	defaultCipher = "aes-128-ctr"
-	defaultKDF    = "scrypt"
-)
-
-type keyJSON struct {
-	Address    string `json:"address"`
-	PublicKey  string `json:"publickey"`
-	Cipher     string `json:"cipher"`
-	CipherText string `json:"ciphertext"`
-	CipherIV   string `json:"cipheriv"`
-	KDF        kdf    `json:"kdf"`
-	MAC        string `json:"mac"`
-}
-
-type kdf struct {
-	Type   string `json:"type"`
-	KeyLen int    `json:"keylen"`
-	N      int    `json:"N"`
-	R      int    `json:"R"`
-	P      int    `json:"P"`
-	Salt   string `json:"salt"`
-}
-
-func (k *kdf) getKey(passphrase string) ([]byte, error) {
-	salt, err := hex.DecodeString(k.Salt)
-	if err != nil {
-		return nil, err
-	}
-	return scrypt.Key([]byte(passphrase), salt, k.N, k.R, k.P, k.KeyLen)
-}
-
-func (kj *keyJSON) encryptKey(key *Key, passphrase string, scryptN, scryptP int) error {
-	keyBytes := math.PaddedBigBytes(key.PrivateKey.D, 32)
-
-	salt := make([]byte, 32)
-	if _, err := io.ReadFull(rand.Reader, salt); err != nil {
-		panic("reading from crypto/rand failed: " + err.Error())
-	}
-	derivedKey, err := scrypt.Key([]byte(passphrase), salt, scryptN, scryptR, scryptP, scryptDKLen)
-	if err != nil {
-		return err
-	}
-
-	encryptKey := derivedKey[:16]
-
-	iv := make([]byte, aes.BlockSize) // 16
-	if _, err := io.ReadFull(rand.Reader, iv); err != nil {
-		panic("reading from crypto/rand failed: " + err.Error())
-	}
-	cipherText, err := aesCTRXOR(encryptKey, keyBytes, iv)
-	if err != nil {
-		return err
-	}
-
-	mac := crypto.Keccak256(derivedKey[16:32], cipherText)
-
-	kj.Address = key.Addr.Hex()
-	kj.PublicKey = hexutil.Bytes(crypto.FromECDSAPub(&key.PrivateKey.PublicKey)).String()
-	kj.Cipher = defaultCipher
-	kj.CipherIV = hex.EncodeToString(iv)
-	kj.CipherText = hex.EncodeToString(cipherText)
-	kj.MAC = hex.EncodeToString(mac)
-	kj.KDF.Type = defaultKDF
-	kj.KDF.KeyLen = scryptDKLen
-	kj.KDF.N = scryptN
-	kj.KDF.R = scryptR
-	kj.KDF.P = scryptP
-	kj.KDF.Salt = hex.EncodeToString(salt)
-
-	return nil
-}
-
-func (kj *keyJSON) decryptKey(passphrase string) (*Key, error) {
-	mac, err := hex.DecodeString(kj.MAC)
-	if err != nil {
-		return nil, err
-	}
-
-	iv, err := hex.DecodeString(kj.CipherIV)
-	if err != nil {
-		return nil, err
-	}
-
-	cipherText, err := hex.DecodeString(kj.CipherText)
-	if err != nil {
-		return nil, err
-	}
-
-	derivedKey, err := kj.KDF.getKey(passphrase)
-	if err != nil {
-		return nil, err
-	}
-
-	calculatedMAC := crypto.Keccak256(derivedKey[16:32], cipherText)
-	if !bytes.Equal(calculatedMAC, mac) {
-		return nil, ErrDecrypt
-	}
-
-	plainText, err := aesCTRXOR(derivedKey[:16], cipherText, iv)
-	if err != nil {
-		return nil, err
-	}
-
-	key := crypto.ToECDSAUnsafe(plainText)
-	return &Key{
-		Addr:       crypto.PubkeyToAddress(key.PublicKey),
-		PrivateKey: key,
-	}, nil
-
-}
-
-func aesCTRXOR(key, inText, iv []byte) ([]byte, error) {
-	// AES-128 is selected due to size of encryptKey.
-	aesBlock, err := aes.NewCipher(key)
-	if err != nil {
-		return nil, err
-	}
-	stream := cipher.NewCTR(aesBlock, iv)
-	outText := make([]byte, len(inText))
-	stream.XORKeyStream(outText, inText)
-	return outText, err
-}
diff --git a/wallet/keystore/keystore.go b/wallet/keystore/keystore.go
deleted file mode 100644
index 278c6f73..00000000
--- a/wallet/keystore/keystore.go
+++ /dev/null
@@ -1,118 +0,0 @@
-// Copyright 2018 The Fractal Team Authors
-// This file is part of the fractal project.
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-package keystore
-
-import (
-	"encoding/json"
-	"fmt"
-	"io/ioutil"
-	"path/filepath"
-
-	"github.com/fractalplatform/fractal/common"
-)
-
-const (
-	// StandardScryptN is the N parameter of Scrypt encryption algorithm, using 256MB
-	// memory and taking approximately 1s CPU time on a modern processor.
-	StandardScryptN = 1 << 18
-
-	// StandardScryptP is the P parameter of Scrypt encryption algorithm, using 256MB
-	// memory and taking approximately 1s CPU time on a modern processor.
-	StandardScryptP = 1
-
-	// LightScryptN is the N parameter of Scrypt encryption algorithm, using 4MB
-	// memory and taking approximately 100ms CPU time on a modern processor.
-	LightScryptN = 1 << 12
-
-	// LightScryptP is the P parameter of Scrypt encryption algorithm, using 4MB
-	// memory and taking approximately 100ms CPU time on a modern processor.
-	LightScryptP = 6
-
-	scryptR     = 8
-	scryptDKLen = 32
-)
-
-// KeyStore manages a key storage directory on disk.
-type KeyStore struct {
-	DirPath          string
-	ScryptN, ScryptP int
-}
-
-// GetKey load the key from the key file and decrypt it.
-func (ks *KeyStore) GetKey(addr common.Address, filename, passphrase string) (*Key, error) {
-	keyjson, err := ioutil.ReadFile(filename)
-	if err != nil {
-		return nil, err
-	}
-	key, err := DecryptKey(keyjson, passphrase)
-	if err != nil {
-		return nil, err
-	}
-	// check address
-	if key.Addr != addr {
-		return nil, fmt.Errorf("key content mismatch: have account %x, want %x", key.Addr, addr)
-	}
-	return key, nil
-}
-
-// StoreKey encrypts with 'passphrase' and stores in the given directory
-func (ks *KeyStore) StoreKey(key *Key, filename, passphrase string) error {
-	keyjson, err := EncryptKey(key, passphrase, ks.ScryptN, ks.ScryptP)
-	if err != nil {
-		return err
-	}
-	return writeKeyFile(filename, keyjson)
-}
-
-func (ks *KeyStore) GetPublicKey(filename string) (string, error) {
-	keyjson, err := ioutil.ReadFile(filename)
-	if err != nil {
-		return "", err
-	}
-	keyj := new(keyJSON)
-	if err := json.Unmarshal(keyjson, keyj); err != nil {
-		return "", err
-	}
-
-	return keyj.PublicKey, nil
-}
-
-// JoinPath join file name into key dir path.
-func (ks *KeyStore) JoinPath(filename string) string {
-	if filepath.IsAbs(filename) {
-		return filename
-	}
-	return filepath.Join(ks.DirPath, filename)
-}
-
-// DecryptKey decrypts a key from a json bytes.
-func DecryptKey(keyjson []byte, passphrase string) (*Key, error) {
-	keyj := new(keyJSON)
-	if err := json.Unmarshal(keyjson, keyj); err != nil {
-		return nil, err
-	}
-	return keyj.decryptKey(passphrase)
-}
-
-// EncryptKey encrypts a key using the specified scrypt parameters into a json bytes.
-func EncryptKey(key *Key, passphrase string, scryptN, scryptP int) ([]byte, error) {
-	keyj := new(keyJSON)
-	if err := keyj.encryptKey(key, passphrase, scryptN, scryptP); err != nil {
-		return nil, err
-	}
-	return json.Marshal(keyj)
-}
diff --git a/wallet/keystore/keystore_test.go b/wallet/keystore/keystore_test.go
deleted file mode 100644
index b1d573be..00000000
--- a/wallet/keystore/keystore_test.go
+++ /dev/null
@@ -1,59 +0,0 @@
-// Copyright 2018 The Fractal Team Authors
-// This file is part of the fractal project.
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-package keystore
-
-import (
-	"crypto/ecdsa"
-	crand "crypto/rand"
-	"io/ioutil"
-	"testing"
-
-	"github.com/fractalplatform/fractal/crypto"
-	"github.com/stretchr/testify/assert"
-)
-
-func TestGetAndStoreKey(t *testing.T) {
-	privateKeyECDSA, err := ecdsa.GenerateKey(crypto.S256(), crand.Reader)
-	if err != nil {
-		t.Fatal(err)
-	}
-	key := &Key{
-		Addr:       crypto.PubkeyToAddress(privateKeyECDSA.PublicKey),
-		PrivateKey: privateKeyECDSA,
-	}
-
-	password := "pwd"
-
-	ks := KeyStore{
-		ScryptN: StandardScryptN,
-		ScryptP: StandardScryptP,
-	}
-	f, err := ioutil.TempFile("", "")
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	ks.StoreKey(key, f.Name(), password)
-
-	newkey, err := ks.GetKey(key.Addr, f.Name(), password)
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	assert.Equal(t, newkey, key)
-
-}
diff --git a/wallet/wallet.go b/wallet/wallet.go
deleted file mode 100644
index e57f2056..00000000
--- a/wallet/wallet.go
+++ /dev/null
@@ -1,379 +0,0 @@
-// Copyright 2018 The Fractal Team Authors
-// This file is part of the fractal project.
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-package wallet
-
-import (
-	"crypto/ecdsa"
-	crand "crypto/rand"
-	"encoding/hex"
-	"encoding/json"
-	"errors"
-	"fmt"
-	"io/ioutil"
-	"math/big"
-	"os"
-	"time"
-
-	"github.com/ethereum/go-ethereum/common/hexutil"
-	"github.com/ethereum/go-ethereum/log"
-	am "github.com/fractalplatform/fractal/accountmanager"
-	"github.com/fractalplatform/fractal/blockchain"
-	"github.com/fractalplatform/fractal/common"
-	"github.com/fractalplatform/fractal/crypto"
-	"github.com/fractalplatform/fractal/types"
-	"github.com/fractalplatform/fractal/wallet/cache"
-	"github.com/fractalplatform/fractal/wallet/keystore"
-)
-
-// Wallet represents a software wallet.
-type Wallet struct {
-	accounts        cache.Accounts
-	cache           *cache.AccountCache
-	ks              *keystore.KeyStore
-	bindingFilePath string
-	blockchain      *blockchain.BlockChain
-}
-
-// NewWallet creates a wallet to sign transaction.
-func NewWallet(keyStoredir string, scryptN, scryptP int) *Wallet {
-	log.Info("Disk storage enabled for keystore", "dir", keyStoredir)
-	w := &Wallet{
-		cache: cache.NewAccountCache(keyStoredir),
-		ks:    &keystore.KeyStore{DirPath: keyStoredir, ScryptN: scryptN, ScryptP: scryptP},
-	}
-
-	w.bindingFilePath = w.ks.JoinPath("accountKeyBindingInfo.txt")
-	return w
-}
-
-func (w *Wallet) createFileIfNotExist(filePath string) error {
-	_, err := os.Stat(filePath)
-	if err != nil && os.IsNotExist(err) {
-		_, err = os.Create(filePath)
-		if err != nil {
-			log.Error("Create file fail:", "err=", err, "file=", filePath)
-			return err
-		}
-		log.Info("Create file success:", "file=", filePath)
-		return nil
-	}
-	return nil
-}
-func (w *Wallet) SetBlockChain(blockchain *blockchain.BlockChain) {
-	w.blockchain = blockchain
-}
-func (w *Wallet) GetAccountManager() (*am.AccountManager, error) {
-	statedb, err := w.blockchain.State()
-	if err != nil {
-		return nil, err
-	}
-	return am.NewAccountManager(statedb)
-}
-
-// NewAccount generates a new key and stores it into the key directory.
-func (w *Wallet) NewAccount(passphrase string) (cache.Account, error) {
-	key, err := keystore.NewKey(crand.Reader)
-	if err != nil {
-		return cache.Account{}, err
-	}
-	publicKey := hexutil.Bytes(crypto.FromECDSAPub(&key.PrivateKey.PublicKey)).String()
-	a := cache.Account{Addr: key.Addr,
-		Path:      w.ks.JoinPath(keyFileName(key.Addr)),
-		PublicKey: publicKey}
-
-	if err := w.ks.StoreKey(key, a.Path, passphrase); err != nil {
-		return cache.Account{}, err
-	}
-	w.cache.Add(a)
-	return a, nil
-}
-
-// Delete deletes a account by passsphrase.
-func (w *Wallet) Delete(a cache.Account, passphrase string) error {
-	a, _, err := w.getDecryptedKey(a, passphrase)
-	if err != nil {
-		return err
-	}
-
-	if err := os.Remove(a.Path); err != nil {
-		return err
-	}
-	w.cache.Delete(a.Addr)
-	return nil
-}
-
-// Update changes the passphrase of an existing account.
-func (w *Wallet) Update(a cache.Account, passphrase, newPassphrase string) error {
-	a, key, err := w.getDecryptedKey(a, passphrase)
-	if err != nil {
-		return err
-	}
-	return w.ks.StoreKey(key, a.Path, newPassphrase)
-}
-
-// Export exports as a JSON key, encrypted with newPassphrase.
-func (w *Wallet) Export(a cache.Account, passphrase, newPassphrase string) (keyJSON []byte, err error) {
-	_, key, err := w.getDecryptedKey(a, passphrase)
-	if err != nil {
-		return nil, err
-	}
-	N, P := keystore.StandardScryptN, keystore.StandardScryptP
-	return keystore.EncryptKey(key, newPassphrase, N, P)
-}
-
-// Import stores the given encrypted JSON key into the key directory.
-func (w *Wallet) Import(keyJSON []byte, passphrase, newPassphrase string) (cache.Account, error) {
-	key, err := keystore.DecryptKey(keyJSON, passphrase)
-	if err != nil {
-		return cache.Account{}, err
-	}
-	return w.importKey(key, newPassphrase)
-
-}
-
-// ImportECDSA stores the given key into the key directory, encrypting it with the passphrase.
-func (w *Wallet) ImportECDSA(priv *ecdsa.PrivateKey, passphrase string) (cache.Account, error) {
-	key := &keystore.Key{
-		Addr:       crypto.PubkeyToAddress(priv.PublicKey),
-		PrivateKey: priv,
-	}
-	if w.cache.Has(key.Addr) {
-		return cache.Account{}, ErrAccountExists
-	}
-	return w.importKey(key, passphrase)
-}
-
-// HasAddress reports whether a key with the given address is present.
-func (w *Wallet) HasAddress(addr common.Address) bool {
-	return w.cache.Has(addr)
-}
-
-// Accounts returns all key files
-func (w *Wallet) Accounts() cache.Accounts {
-	return w.cache.Accounts()
-}
-
-// Find resolves the given account into a unique entry in the keystore.
-func (w *Wallet) Find(addr common.Address) (cache.Account, error) {
-	account := w.cache.Find(addr)
-	if account != nil {
-		return *account, nil
-	}
-	return cache.Account{}, ErrNoMatch
-}
-
-// SignHashWithPassphrase signs hash if the private key matching the given address
-// can be decrypted with the given passphrase.
-func (w *Wallet) SignHashWithPassphrase(a cache.Account, passphrase string, hash []byte) (signature []byte, err error) {
-	_, key, err := w.getDecryptedKey(a, passphrase)
-	if err != nil {
-		return nil, err
-	}
-	return crypto.Sign(hash, key.PrivateKey)
-}
-
-// SignTxWithPassphrase signs the Action if the private key matching the given address
-// can be decrypted with the given passphrase.
-func (w *Wallet) SignTxWithPassphrase(a cache.Account, passphrase string, tx *types.Transaction, action *types.Action, chainID *big.Int) (*types.Transaction, error) {
-	_, key, err := w.getDecryptedKey(a, passphrase)
-	if err != nil {
-		return nil, err
-	}
-	if err := types.SignAction(action, tx, types.NewSigner(chainID), key.PrivateKey); err != nil {
-		return nil, err
-	}
-	return tx, nil
-}
-
-func (w *Wallet) importKey(key *keystore.Key, passphrase string) (cache.Account, error) {
-	a := cache.Account{Addr: key.Addr, Path: w.ks.JoinPath(keyFileName(key.Addr))}
-	if err := w.ks.StoreKey(key, a.Path, passphrase); err != nil {
-		return cache.Account{}, err
-	}
-	w.cache.Add(a)
-	return a, nil
-}
-func (w *Wallet) GetPrivateKey(a cache.Account, passphrase string) (*keystore.Key, error) {
-	_, key, err := w.getDecryptedKey(a, passphrase)
-	if err != nil {
-		return nil, err
-	}
-	return key, nil
-}
-func (w *Wallet) getDecryptedKey(a cache.Account, passphrase string) (cache.Account, *keystore.Key, error) {
-	a, err := w.Find(a.Addr)
-	if err != nil {
-		return a, nil, err
-	}
-	key, err := w.ks.GetKey(a.Addr, a.Path, passphrase)
-	return a, key, err
-}
-
-// keyFileName implements the naming convention for keyfiles:
-// UTC--<created_at UTC ISO8601>-<address hex>
-func keyFileName(keyAddr common.Address) string {
-	ts := time.Now().UTC()
-	return fmt.Sprintf("UTC--%s--%s", toISO8601(ts), hex.EncodeToString(keyAddr[:]))
-}
-
-func toISO8601(t time.Time) string {
-	var tz string
-	name, offset := t.Zone()
-	if name == "UTC" {
-		tz = "Z"
-	} else {
-		tz = fmt.Sprintf("%03d00", offset/3600)
-	}
-	return fmt.Sprintf("%04d-%02d-%02dT%02d-%02d-%02d.%09d%s", t.Year(), t.Month(), t.Day(), t.Hour(), t.Minute(), t.Second(), t.Nanosecond(), tz)
-}
-
-// BindAccountNameAddr bind the account name and publicKey, the current publicKey is got from account manager.
-func (w *Wallet) BindAccountAndPublicKey(accountName string) error {
-	publicKeyAccountsMap := w.getBindingInfo()
-
-	// get account info firstly
-	accountMgr, err := w.GetAccountManager()
-	if err != nil {
-		return err
-	}
-	account, err := accountMgr.GetAccountByName(common.Name(accountName))
-	if err != nil {
-		return err
-	}
-	curPublicKey := account.PublicKey.String()
-
-	// We need consider 5 situations below:
-	// 1:publicKey exist, account NOT exist
-	// 2:publicKey NOT exist, account exist
-	// 3:publicKey AND account exist,but NOT matched
-	// 4:publicKey AND account exist,and matched
-	// 5:publicKey AND account both NOT exist
-
-	// below loop can resolve:
-	// (1) when account exist, if 4, return, if 2 and 3, it can dismatch them, but we need match new publicKey then
-	// (2) when account NOT exist, copy original info
-	tmpPublicKeyAccountsMap := make(map[string][]string)
-	for publicKey, accounts := range publicKeyAccountsMap {
-		tmpAccounts := make([]string, 0)
-		for _, account := range accounts {
-			if account != accountName {
-				tmpAccounts = append(tmpAccounts, account)
-				continue
-			} else if curPublicKey == publicKey {
-				return nil
-			}
-		}
-		if len(tmpAccounts) > 0 {
-			tmpPublicKeyAccountsMap[publicKey] = tmpAccounts
-		}
-	}
-	if _, ok := tmpPublicKeyAccountsMap[curPublicKey]; ok {
-		tmpPublicKeyAccountsMap[curPublicKey] = append(tmpPublicKeyAccountsMap[curPublicKey], accountName)
-	} else {
-		accounts := make([]string, 0)
-		accounts = append(accounts, accountName)
-		tmpPublicKeyAccountsMap[curPublicKey] = accounts
-	}
-
-	return w.writeBindingInfo(tmpPublicKeyAccountsMap)
-}
-
-// ps: in this func, we can't use account's publicKey to get accounts info,
-// because the account's publicKey has been updated by block chain.
-func (w *Wallet) DeleteBound(accountName string) error {
-	publicKeyAccountsMap := w.getBindingInfo()
-
-	tmpPublicKeyAccountsMap := make(map[string][]string)
-	for publicKey, accounts := range publicKeyAccountsMap {
-		tmpAccounts := make([]string, 0)
-		for _, account := range accounts {
-			if account != accountName {
-				tmpAccounts = append(tmpAccounts, account)
-				continue
-			}
-		}
-		if len(tmpAccounts) > 0 {
-			tmpPublicKeyAccountsMap[publicKey] = tmpAccounts
-		}
-	}
-	return w.writeBindingInfo(tmpPublicKeyAccountsMap)
-}
-
-func (w *Wallet) GetAccountsByPublicKey(publicKey string) ([]am.Account, error) {
-	publicKeyAccountsMap := w.getBindingInfo()
-	accounts := make([]am.Account, 0)
-	if accountNames, ok := publicKeyAccountsMap[publicKey]; ok {
-		accountMgr, err := w.GetAccountManager()
-		if err != nil {
-			return nil, err
-		}
-		for _, accountName := range accountNames {
-			account, err := accountMgr.GetAccountByName(common.Name(accountName))
-			if err != nil {
-				return nil, err
-			}
-			accounts = append(accounts, *account)
-		}
-	}
-	return accounts, nil
-}
-
-func (w *Wallet) GetAllAccounts() ([]am.Account, error) {
-	publicKeyAccountsMap := w.getBindingInfo()
-	accountMgr, err := w.GetAccountManager()
-	if err != nil {
-		return nil, err
-	}
-	accounts := make([]am.Account, 0)
-	for _, accountNames := range publicKeyAccountsMap {
-		for _, accountName := range accountNames {
-			account, err := accountMgr.GetAccountByName(common.Name(accountName))
-			if err != nil {
-				return nil, err
-			}
-			accounts = append(accounts, *account)
-		}
-	}
-	return accounts, nil
-}
-
-func (w *Wallet) getBindingInfo() map[string][]string {
-	publicKeyAccountsMap := make(map[string][]string)
-	fileContent, _ := ioutil.ReadFile(w.bindingFilePath)
-	if fileContent != nil && len(fileContent) > 0 {
-		json.Unmarshal(fileContent, &publicKeyAccountsMap)
-	}
-	log.Debug("getBindingInfo:", "binging info", publicKeyAccountsMap)
-	return publicKeyAccountsMap
-}
-
-func (w *Wallet) writeBindingInfo(addrAccountsMap map[string][]string) error {
-	log.Debug("writeBindingInfo:", "binging info", addrAccountsMap)
-	fileContent, err := json.Marshal(addrAccountsMap)
-	if err != nil {
-		log.Error("fail to marshall map to json string:", addrAccountsMap)
-		return err
-	}
-
-	if ioutil.WriteFile(w.bindingFilePath, fileContent, 0666) == nil {
-		log.Debug("success to write binding info:", string(fileContent))
-		return nil
-	} else {
-		log.Error("fail to write binding info:", string(fileContent))
-		return errors.New("fail to write binding info")
-	}
-}
diff --git a/wallet/wallet_test.go b/wallet/wallet_test.go
deleted file mode 100644
index 1fd20b84..00000000
--- a/wallet/wallet_test.go
+++ /dev/null
@@ -1,161 +0,0 @@
-// Copyright 2018 The Fractal Team Authors
-// This file is part of the fractal project.
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-package wallet
-
-import (
-	"crypto/ecdsa"
-	crand "crypto/rand"
-	"io/ioutil"
-	"os"
-	"runtime"
-	"strings"
-	"testing"
-
-	"github.com/fractalplatform/fractal/common"
-	"github.com/fractalplatform/fractal/crypto"
-	"github.com/fractalplatform/fractal/wallet/keystore"
-	"github.com/stretchr/testify/assert"
-)
-
-func TestWallet(t *testing.T) {
-	d, err := ioutil.TempDir("", "")
-	if err != nil {
-		t.Fatal(err)
-	}
-	defer os.RemoveAll(d)
-
-	w := NewWallet(d, keystore.StandardScryptN, keystore.StandardScryptP)
-
-	// test wallet.NewAccount
-	a, err := w.NewAccount("password")
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	if !strings.HasPrefix(a.Path, d) {
-		t.Errorf("account file %s doesn't have dir prefix", a.Path)
-	}
-
-	stat, err := os.Stat(a.Path)
-	if err != nil {
-		t.Fatalf("account file %s doesn't exist (%v)", a.Path, err)
-	}
-
-	if runtime.GOOS != "windows" && stat.Mode() != 0600 {
-		t.Fatalf("account file has wrong mode: got %o, want %o", stat.Mode(), 0600)
-	}
-
-	// test wallet.HasAddress
-	if !w.HasAddress(a.Addr) {
-		t.Fatalf("HasAccount(%x) should've returned true", a.Addr)
-	}
-
-	// test wallet.Update
-	if err := w.Update(a, "password", "newpassword"); err != nil {
-		t.Fatalf("Update error: %v", err)
-	}
-
-	// test wallet.Delete
-	if err := w.Delete(a, "newpassword"); err != nil {
-		t.Fatalf("Delete error: %v", err)
-	}
-
-	if common.FileExist(a.Path) {
-		t.Fatalf("account file %s should be gone after Delete", a.Path)
-	}
-
-	if w.HasAddress(a.Addr) {
-		t.Fatalf("HasAccount(%x) should've returned true after Delete", a.Addr)
-	}
-}
-
-func TestExportAndImportKey(t *testing.T) {
-	d, err := ioutil.TempDir("", "")
-	if err != nil {
-		t.Fatal(err)
-	}
-	defer os.RemoveAll(d)
-
-	w := NewWallet(d, keystore.StandardScryptN, keystore.StandardScryptP)
-
-	privateKeyECDSA, err := ecdsa.GenerateKey(crypto.S256(), crand.Reader)
-	if err != nil {
-		t.Fatal(err)
-	}
-	password := "password"
-	newpassword := "newpassword"
-	newnewpassword := "newnewpassword"
-
-	// test wallet.ImportECDSA
-	a, err := w.ImportECDSA(privateKeyECDSA, password)
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	// test wallet.Export
-	jsonbytes, err := w.Export(a, password, newpassword)
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	if err := w.Delete(a, password); err != nil {
-		t.Fatal(err)
-	}
-
-	// test wallet.Import
-	newA, err := w.Import(jsonbytes, newpassword, newnewpassword)
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	assert.Equal(t, a.Addr, newA.Addr)
-}
-
-func TestSignWithPassphrase(t *testing.T) {
-	var hash = make([]byte, 32)
-
-	d, err := ioutil.TempDir("", "")
-	if err != nil {
-		t.Fatal(err)
-	}
-	defer os.RemoveAll(d)
-
-	w := NewWallet(d, keystore.StandardScryptN, keystore.StandardScryptP)
-
-	privateKeyECDSA, err := ecdsa.GenerateKey(crypto.S256(), crand.Reader)
-	if err != nil {
-		t.Fatal(err)
-	}
-	password := "password"
-
-	sig, err := crypto.Sign(hash, privateKeyECDSA)
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	a, err := w.ImportECDSA(privateKeyECDSA, password)
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	nSig, err := w.SignHashWithPassphrase(a, password, hash)
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	assert.Equal(t, nSig, sig)
-}