Skip to content

Commit

Permalink
Add StateUpdate payload
Browse files Browse the repository at this point in the history
support store a value use Namespace and key as index.

Signed-off-by: zhengq1 <[email protected]>

(cherry picked from commit 5223bd3)
Signed-off-by: zhengq1 <[email protected]>
  • Loading branch information
zhengq1 committed Jul 28, 2017
1 parent f9e7513 commit 6fcbb9a
Show file tree
Hide file tree
Showing 11 changed files with 262 additions and 5 deletions.
17 changes: 17 additions & 0 deletions account/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -563,3 +563,20 @@ func GetBookKeepers() []*crypto.PubKey {

return pubKeys
}

func GetStateUpdater() []*crypto.PubKey {
var pubKeys = []*crypto.PubKey{}
for _, key := range config.Parameters.StateUpdater {
pubKey := []byte(key)
pubKey, err := hex.DecodeString(key)
// TODO Convert the key string to byte
k, err := crypto.DecodePoint(pubKey)
if err != nil {
log.Error("Incorrectly book keepers key")
return nil
}
pubKeys = append(pubKeys, k)
}

return pubKeys
}
1 change: 1 addition & 0 deletions common/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ type Configuration struct {
Version int `json:"Version"`
SeedList []string `json:"SeedList"`
BookKeepers []string `json:"BookKeepers"` // The default book keepers' publickey
StateUpdater []string `json:"StateUpdater"`
HttpRestPort int `json:"HttpRestPort"`
RestCertPath string `json:"RestCertPath"`
RestKeyPath string `json:"RestKeyPath"`
Expand Down
4 changes: 2 additions & 2 deletions core/ledger/blockchain.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ func NewBlockchain(height uint32) *Blockchain {
}
}

func NewBlockchainWithGenesisBlock(defaultBookKeeper []*crypto.PubKey) (*Blockchain, error) {
func NewBlockchainWithGenesisBlock(defaultBookKeeper []*crypto.PubKey, defaultStateUpdater []*crypto.PubKey) (*Blockchain, error) {
genesisBlock, err := GenesisBlockInit()
if err != nil {
return nil, NewDetailErr(err, ErrNoCode, "[Blockchain], NewBlockchainWithGenesisBlock failed.")
Expand All @@ -32,7 +32,7 @@ func NewBlockchainWithGenesisBlock(defaultBookKeeper []*crypto.PubKey) (*Blockch
hashx := genesisBlock.Hash()
genesisBlock.hash = &hashx

height, err := DefaultLedger.Store.InitLedgerStoreWithGenesisBlock(genesisBlock, defaultBookKeeper)
height, err := DefaultLedger.Store.InitLedgerStoreWithGenesisBlock(genesisBlock, defaultBookKeeper, defaultStateUpdater)
if err != nil {
return nil, NewDetailErr(err, ErrNoCode, "[Blockchain], InitLevelDBStoreWithGenesisBlock failed.")
}
Expand Down
5 changes: 5 additions & 0 deletions core/ledger/ledger.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (

var DefaultLedger *Ledger
var StandbyBookKeepers []*crypto.PubKey
var StateUpdater []*crypto.PubKey

// Ledger - the struct for onchainDNA ledger
type Ledger struct {
Expand All @@ -26,6 +27,10 @@ func (l *Ledger) IsDoubleSpend(Tx *tx.Transaction) bool {
return DefaultLedger.Store.IsDoubleSpend(Tx)
}

func (l *Ledger) IsStateUpdaterVaild(Tx *tx.Transaction) bool {
return DefaultLedger.Store.IsStateUpdaterVaild(Tx)
}

//Get the DefaultLedger.
//Note: the later version will support the mutiLedger.So this func mybe expired later.
func GetDefaultLedger() (*Ledger, error) {
Expand Down
6 changes: 5 additions & 1 deletion core/ledger/ledgerStore.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ type ILedgerStore interface {
GetHeaderHashByHeight(height uint32) Uint256

GetBookKeeperList() ([]*crypto.PubKey, []*crypto.PubKey, error)
InitLedgerStoreWithGenesisBlock(genesisblock *Block, defaultBookKeeper []*crypto.PubKey) (uint32, error)
InitLedgerStoreWithGenesisBlock(genesisblock *Block, defaultBookKeeper []*crypto.PubKey, defaultStateUpdater []*crypto.PubKey) (uint32, error)

GetQuantityIssued(assetid Uint256) (Fixed64, error)

Expand All @@ -48,4 +48,8 @@ type ILedgerStore interface {

IsTxHashDuplicate(txhash Uint256) bool
IsBlockInStore(hash Uint256) bool

GetStateUpdater() ([]*crypto.PubKey, error)
GetState(namespace []byte, key []byte) ([]byte, error)
IsStateUpdaterVaild(Tx *tx.Transaction) bool
}
131 changes: 130 additions & 1 deletion core/store/ChainStore/ChainStore.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ func NewChainStore(file string) (*ChainStore, error) {
}, nil
}

func (bd *ChainStore) InitLedgerStoreWithGenesisBlock(genesisBlock *Block, defaultBookKeeper []*crypto.PubKey) (uint32, error) {
func (bd *ChainStore) InitLedgerStoreWithGenesisBlock(genesisBlock *Block, defaultBookKeeper []*crypto.PubKey, defaultStateUpdater []*crypto.PubKey) (uint32, error) {

hash := genesisBlock.Hash()
bd.headerIndex[0] = hash
Expand Down Expand Up @@ -238,6 +238,24 @@ func (bd *ChainStore) InitLedgerStoreWithGenesisBlock(genesisBlock *Block, defau
bd.st.Put(bkListKey.Bytes(), bkListValue.Bytes())
///////////////////////////////////////////////////

///////////////////////////////////////////////////
// process defaultStateUpdater
///////////////////////////////////////////////////
// StateUpdater key
suKey := bytes.NewBuffer(nil)
suKey.WriteByte(byte(CA_StateUpdater))

// StateUpdater value
suValue := bytes.NewBuffer(nil)
serialization.WriteVarUint(suValue, uint64(len(defaultStateUpdater)))
for k := 0; k < len(defaultStateUpdater); k++ {
defaultStateUpdater[k].Serialize(suValue)
}

// StateUpdater put value
bd.st.Put(suKey.Bytes(), suValue.Bytes())
///////////////////////////////////////////////////

// persist genesis block
bd.persist(genesisBlock)

Expand Down Expand Up @@ -660,6 +678,35 @@ func (self *ChainStore) GetBookKeeperList() ([]*crypto.PubKey, []*crypto.PubKey,
return currBookKeeper, nextBookKeeper, nil
}

func (self *ChainStore) GetStateUpdater() ([]*crypto.PubKey, error) {
prefix := []byte{byte(CA_StateUpdater)}
suValue, err_get := self.st.Get(prefix)
if err_get != nil {
return nil, err_get
}

r := bytes.NewReader(suValue)

// read length
count, err := serialization.ReadVarUint(r, 0)
if err != nil {
return nil, err
}

var stateUpdater = make([]*crypto.PubKey, count)
for i := uint64(0); i < count; i++ {
bk := new(crypto.PubKey)
err := bk.DeSerialize(r)
if err != nil {
return nil, err
}

stateUpdater[i] = bk
}

return stateUpdater, nil
}

func (bd *ChainStore) persist(b *Block) error {
utxoUnspents := make(map[Uint160]map[Uint256][]*tx.UTXOUnspent)
unspents := make(map[Uint256][]uint16)
Expand Down Expand Up @@ -746,6 +793,7 @@ func (bd *ChainStore) persist(b *Block) error {
b.Transactions[i].TxType == tx.IssueAsset ||
b.Transactions[i].TxType == tx.TransferAsset ||
b.Transactions[i].TxType == tx.Record ||
b.Transactions[i].TxType == tx.StateUpdate ||
b.Transactions[i].TxType == tx.BookKeeper ||
b.Transactions[i].TxType == tx.PrivacyPayload ||
b.Transactions[i].TxType == tx.BookKeeping ||
Expand Down Expand Up @@ -774,6 +822,48 @@ func (bd *ChainStore) persist(b *Block) error {
}
}

if b.Transactions[i].TxType == tx.StateUpdate {
su := b.Transactions[i].Payload.(*payload.StateUpdate)

// stateKey
statePrefix := []byte{byte(ST_STATES)}
stateKey := append(statePrefix, su.Namespace...)
stateKey = append(stateKey, su.Key...)
//stateValueOld, err_get := bd.st.Get(stateKey)

// stateValue
//stateValue := bytes.NewBuffer(nil)
//serialization.WriteVarBytes(stateValue, su.Value)

// verify tx signer public is in StateUpdater list.
//publicKey := b.Transactions[i].Programs[0].Parameter[1:34]
log.Trace(fmt.Sprintf("StateUpdate tx publickey: %x", su.Updater))

stateUpdater, err := bd.GetStateUpdater()
if err != nil {
return err
}

findflag := false
for k := 0; k < len(stateUpdater); k++ {
log.Trace(fmt.Sprintf("StateUpdate updaterPublickey %d: %x %x", k, stateUpdater[k].X, stateUpdater[k].Y))

if su.Updater.X.Cmp(stateUpdater[k].X) == 0 && su.Updater.Y.Cmp(stateUpdater[k].Y) == 0 {
findflag = true
break
}
}

if !findflag {
return errors.New(fmt.Sprintf("[persist] stateUpdater publickey not found in store, reject. tx publickey: %x", su.Updater))
}

// if not found in store, put value to the key.
// if found in store, rewrite value.
log.Trace(fmt.Sprintf("[persist] StateUpdate modify, key: %x, value:%x", stateKey, su.Value))
bd.st.BatchPut(stateKey, su.Value)
}

for index := 0; index < len(b.Transactions[i].Outputs); index++ {
output := b.Transactions[i].Outputs[index]
programHash := output.ProgramHash
Expand Down Expand Up @@ -1291,6 +1381,45 @@ func (bd *ChainStore) GetAccount(programHash Uint160) (*account.AccountState, er
return accountState, nil
}

func (bd *ChainStore) IsStateUpdaterVaild(Tx *tx.Transaction) bool {
su := Tx.Payload.(*payload.StateUpdate)

stateUpdater, err := bd.GetStateUpdater()
if err != nil {
return false
}

findflag := false
for k := 0; k < len(stateUpdater); k++ {
log.Trace(fmt.Sprintf("StateUpdate updaterPublickey %d: %x %x", k, stateUpdater[k].X, stateUpdater[k].Y))

if su.Updater.X.Cmp(stateUpdater[k].X) == 0 && su.Updater.Y.Cmp(stateUpdater[k].Y) == 0 {
findflag = true
break
}
}

if !findflag {
return false
}

return true
}

func (bd *ChainStore) GetState(namespace []byte, key []byte) ([]byte, error) {

// stateKey
statePrefix := []byte{byte(ST_STATES)}
stateKey := append(statePrefix, namespace...)
stateKey = append(stateKey, key...)
stateValue, err := bd.st.Get(stateKey)
if err != nil {
return nil, err
}

return stateValue, nil
}

func (bd *ChainStore) IsBlockInStore(hash Uint256) bool {

var b *Block = new(Block)
Expand Down
6 changes: 6 additions & 0 deletions core/store/ChainStore/DataEntryPrefix.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,17 @@ const (
ST_QuantityIssued DataEntryPrefix = 0xc1
ST_ACCOUNT DataEntryPrefix = 0xc2

// STATES
ST_STATES DataEntryPrefix = 0xd0

//SYSTEM
SYS_CurrentBlock DataEntryPrefix = 0x40
SYS_CurrentHeader DataEntryPrefix = 0x41
SYS_CurrentBookKeeper DataEntryPrefix = 0x42

// CA
CA_StateUpdater DataEntryPrefix = 0x50

//CONFIG
CFG_Version DataEntryPrefix = 0xf0
)
68 changes: 68 additions & 0 deletions core/transaction/payload/StateUpdate.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package payload

import (
"DNA/common/serialization"
"DNA/crypto"
. "DNA/errors"
"errors"
"io"
)

type StateUpdate struct {
Namespace []byte
Key []byte
Value []byte
Updater *crypto.PubKey
}

func (su *StateUpdate) Data() []byte {
return []byte{0}
}

func (su *StateUpdate) Serialize(w io.Writer) error {
err := serialization.WriteVarBytes(w, su.Namespace)
if err != nil {
return NewDetailErr(err, ErrNoCode, "[StateUpdate], Namespace serialize failed.")
}

err = serialization.WriteVarBytes(w, su.Key)
if err != nil {
return NewDetailErr(err, ErrNoCode, "[StateUpdate], key serialize failed.")
}

err = serialization.WriteVarBytes(w, su.Value)
if err != nil {
return NewDetailErr(err, ErrNoCode, "[StateUpdate], value serialize failed.")
}

su.Updater.Serialize(w)

return nil
}

func (su *StateUpdate) Deserialize(r io.Reader) error {
var err error

su.Namespace, err = serialization.ReadVarBytes(r)
if err != nil {
return NewDetailErr(errors.New("[StateUpdate], Namespace deserialize failed."), ErrNoCode, "")
}

su.Key, err = serialization.ReadVarBytes(r)
if err != nil {
return NewDetailErr(errors.New("[StateUpdate], key deserialize failed."), ErrNoCode, "")
}

su.Value, err = serialization.ReadVarBytes(r)
if err != nil {
return NewDetailErr(errors.New("[StateUpdate], value deserialize failed."), ErrNoCode, "")
}

su.Updater = new(crypto.PubKey)
err = su.Updater.DeSerialize(r)
if err != nil {
return NewDetailErr(err, ErrNoCode, "[StateUpdate], updater Deserialize failed.")
}

return nil
}
15 changes: 15 additions & 0 deletions core/transaction/transaction.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ const (
RegisterAsset TransactionType = 0x40
TransferAsset TransactionType = 0x80
Record TransactionType = 0x81
StateUpdate TransactionType = 0x90
DeployCode TransactionType = 0xd0
DataFile TransactionType = 0x12
)
Expand Down Expand Up @@ -200,6 +201,8 @@ func (tx *Transaction) DeserializeUnsignedWithoutType(r io.Reader) error {
tx.Payload = new(payload.PrivacyPayload)
case DataFile:
tx.Payload = new(payload.DataFile)
case StateUpdate:
tx.Payload = new(payload.StateUpdate)
default:
return errors.New("[Transaction],invalide transaction type.")
}
Expand Down Expand Up @@ -340,6 +343,18 @@ func (tx *Transaction) GetProgramHashes() ([]Uint160, error) {
return nil, NewDetailErr(err, ErrNoCode, "[Transaction], GetProgramHashes ToCodeHash failed.")
}
hashs = append(hashs, astHash)
case StateUpdate:
updater := tx.Payload.(*payload.StateUpdate).Updater
signatureRedeemScript, err := contract.CreateSignatureRedeemScript(updater)
if err != nil {
return nil, NewDetailErr(err, ErrNoCode, "[Transaction], StateUpdate GetProgramHashes CreateSignatureRedeemScript failed.")
}

astHash, err := ToCodeHash(signatureRedeemScript)
if err != nil {
return nil, NewDetailErr(err, ErrNoCode, "[Transaction], StateUpdate GetProgramHashes ToCodeHash failed.")
}
hashs = append(hashs, astHash)
default:
}
//remove dupilicated hashes
Expand Down
Loading

0 comments on commit 6fcbb9a

Please sign in to comment.