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 .
+
# 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 .
-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 .
-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(¤tBlock); 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: ¶ms.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 = ¶ms.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 = (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 .
-
-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 /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
-
-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
-
-Imports an unencrypted private key from 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 .
+
+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 -g ",
+ 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 ",
+ 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 .
+
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 .
-
-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 .
+
+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 = (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 ",
+ Use: "init -g -d ",
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 = (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 .
-
-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 .
-
-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 .
-
-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 .
-
-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 .
-
-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 .
-
-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 .
+
+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 .
-
-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 .
+
+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 = ¶ms.ChainConfig{
- ContractChargeRatio: 80,
- AssetChargeRatio: 80,
- }
+ cfg.ChainConfig = params.DefaultChainconfig
//cfg.ChainConfig = ¶ms.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 .
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see .
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 .
-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 .
-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 .
-// 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 .
-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 .
-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 .
-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 .
-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 .
-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 .
+
+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 .
+
+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 .
+
+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 .
-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 .
+
+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 .
+
+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 .
+
+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 .
+
+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 .
+
+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 .
+
+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 .
+
+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 .
+
+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 .
-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 .
-
-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 .
+
+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 .
-
-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 .
-
-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 .
-
-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 .
-
-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 .
-
-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 .
-
-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 .
-
-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 .
+
+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 .
-
-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 .
-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 .
+
+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 .
-
-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 .
-
-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 .
-
-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 .
-
-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 .
-
-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 .
-
-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 .
-
-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 .
-
-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 .
-
-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---
-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 .
-
-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)
-}