Skip to content

Commit d758140

Browse files
committed
Add StateUpdate payload
support store a value use Namespace and key as index. Signed-off-by: zhengq1 <ljqlyy@gmail.com>
1 parent 6f15a40 commit d758140

11 files changed

Lines changed: 262 additions & 5 deletions

File tree

account/client.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -563,3 +563,20 @@ func GetBookKeepers() []*crypto.PubKey {
563563

564564
return pubKeys
565565
}
566+
567+
func GetStateUpdater() []*crypto.PubKey {
568+
var pubKeys = []*crypto.PubKey{}
569+
for _, key := range config.Parameters.StateUpdater {
570+
pubKey := []byte(key)
571+
pubKey, err := hex.DecodeString(key)
572+
// TODO Convert the key string to byte
573+
k, err := crypto.DecodePoint(pubKey)
574+
if err != nil {
575+
log.Error("Incorrectly book keepers key")
576+
return nil
577+
}
578+
pubKeys = append(pubKeys, k)
579+
}
580+
581+
return pubKeys
582+
}

common/config/config.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ type Configuration struct {
1919
Version int `json:"Version"`
2020
SeedList []string `json:"SeedList"`
2121
BookKeepers []string `json:"BookKeepers"` // The default book keepers' publickey
22+
StateUpdater []string `json:"StateUpdater"`
2223
HttpRestPort int `json:"HttpRestPort"`
2324
RestCertPath string `json:"RestCertPath"`
2425
RestKeyPath string `json:"RestKeyPath"`

core/ledger/blockchain.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ func NewBlockchain(height uint32) *Blockchain {
2323
}
2424
}
2525

26-
func NewBlockchainWithGenesisBlock( defaultBookKeeper []*crypto.PubKey ) (*Blockchain, error) {
26+
func NewBlockchainWithGenesisBlock(defaultBookKeeper []*crypto.PubKey, defaultStateUpdater []*crypto.PubKey) (*Blockchain, error) {
2727
genesisBlock, err := GenesisBlockInit()
2828
if err != nil {
2929
return nil, NewDetailErr(err, ErrNoCode, "[Blockchain], NewBlockchainWithGenesisBlock failed.")
@@ -32,7 +32,7 @@ func NewBlockchainWithGenesisBlock( defaultBookKeeper []*crypto.PubKey ) (*Block
3232
hashx := genesisBlock.Hash()
3333
genesisBlock.hash = &hashx
3434

35-
height, err := DefaultLedger.Store.InitLedgerStoreWithGenesisBlock( genesisBlock, defaultBookKeeper )
35+
height, err := DefaultLedger.Store.InitLedgerStoreWithGenesisBlock(genesisBlock, defaultBookKeeper, defaultStateUpdater)
3636
if err != nil {
3737
return nil, NewDetailErr(err, ErrNoCode, "[Blockchain], InitLevelDBStoreWithGenesisBlock failed.")
3838
}

core/ledger/ledger.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import (
1313

1414
var DefaultLedger *Ledger
1515
var StandbyBookKeepers []*crypto.PubKey
16+
var StateUpdater []*crypto.PubKey
1617

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

30+
func (l *Ledger) IsStateUpdaterVaild(Tx *tx.Transaction) bool {
31+
return DefaultLedger.Store.IsStateUpdaterVaild(Tx)
32+
}
33+
2934
//Get the DefaultLedger.
3035
//Note: the later version will support the mutiLedger.So this func mybe expired later.
3136
func GetDefaultLedger() (*Ledger, error) {

core/ledger/ledgerStore.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ type ILedgerStore interface {
3636
GetHeaderHashByHeight(height uint32) Uint256
3737

3838
GetBookKeeperList() ([]*crypto.PubKey, []*crypto.PubKey, error)
39-
InitLedgerStoreWithGenesisBlock(genesisblock *Block, defaultBookKeeper []*crypto.PubKey) (uint32, error)
39+
InitLedgerStoreWithGenesisBlock(genesisblock *Block, defaultBookKeeper []*crypto.PubKey, defaultStateUpdater []*crypto.PubKey) (uint32, error)
4040

4141
GetQuantityIssued(assetid Uint256) (Fixed64, error)
4242

@@ -45,4 +45,8 @@ type ILedgerStore interface {
4545
GetUnspentFromProgramHash(programHash Uint160, assetid Uint256) ([]*tx.UTXOUnspent, error)
4646

4747
IsTxHashDuplicate(txhash Uint256) bool
48+
49+
GetStateUpdater() ([]*crypto.PubKey, error)
50+
GetState(namespace []byte, key []byte) ([]byte, error)
51+
IsStateUpdaterVaild(Tx *tx.Transaction) bool
4852
}

core/store/ChainStore/ChainStore.go

Lines changed: 130 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ func NewChainStore(file string) (*ChainStore, error) {
7676
}, nil
7777
}
7878

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

8181
hash := genesisBlock.Hash()
8282
bd.headerIndex[0] = hash
@@ -230,6 +230,24 @@ func (bd *ChainStore) InitLedgerStoreWithGenesisBlock(genesisBlock *Block, defau
230230
bd.st.Put(bkListKey.Bytes(), bkListValue.Bytes())
231231
///////////////////////////////////////////////////
232232

233+
///////////////////////////////////////////////////
234+
// process defaultStateUpdater
235+
///////////////////////////////////////////////////
236+
// StateUpdater key
237+
suKey := bytes.NewBuffer(nil)
238+
suKey.WriteByte(byte(CA_StateUpdater))
239+
240+
// StateUpdater value
241+
suValue := bytes.NewBuffer(nil)
242+
serialization.WriteVarUint(suValue, uint64(len(defaultStateUpdater)))
243+
for k := 0; k < len(defaultStateUpdater); k++ {
244+
defaultStateUpdater[k].Serialize(suValue)
245+
}
246+
247+
// StateUpdater put value
248+
bd.st.Put(suKey.Bytes(), suValue.Bytes())
249+
///////////////////////////////////////////////////
250+
233251
// persist genesis block
234252
bd.persist(genesisBlock)
235253

@@ -652,6 +670,35 @@ func (self *ChainStore) GetBookKeeperList() ([]*crypto.PubKey, []*crypto.PubKey,
652670
return currBookKeeper, nextBookKeeper, nil
653671
}
654672

673+
func (self *ChainStore) GetStateUpdater() ([]*crypto.PubKey, error) {
674+
prefix := []byte{byte(CA_StateUpdater)}
675+
suValue, err_get := self.st.Get(prefix)
676+
if err_get != nil {
677+
return nil, err_get
678+
}
679+
680+
r := bytes.NewReader(suValue)
681+
682+
// read length
683+
count, err := serialization.ReadVarUint(r, 0)
684+
if err != nil {
685+
return nil, err
686+
}
687+
688+
var stateUpdater = make([]*crypto.PubKey, count)
689+
for i := uint64(0); i < count; i++ {
690+
bk := new(crypto.PubKey)
691+
err := bk.DeSerialize(r)
692+
if err != nil {
693+
return nil, err
694+
}
695+
696+
stateUpdater[i] = bk
697+
}
698+
699+
return stateUpdater, nil
700+
}
701+
655702
func (bd *ChainStore) persist(b *Block) error {
656703
utxoUnspents := make(map[Uint160]map[Uint256][]*tx.UTXOUnspent)
657704
unspents := make(map[Uint256][]uint16)
@@ -738,6 +785,7 @@ func (bd *ChainStore) persist(b *Block) error {
738785
b.Transactions[i].TxType == tx.IssueAsset ||
739786
b.Transactions[i].TxType == tx.TransferAsset ||
740787
b.Transactions[i].TxType == tx.Record ||
788+
b.Transactions[i].TxType == tx.StateUpdate ||
741789
b.Transactions[i].TxType == tx.BookKeeper ||
742790
b.Transactions[i].TxType == tx.PrivacyPayload ||
743791
b.Transactions[i].TxType == tx.BookKeeping ||
@@ -766,6 +814,48 @@ func (bd *ChainStore) persist(b *Block) error {
766814
}
767815
}
768816

817+
if b.Transactions[i].TxType == tx.StateUpdate {
818+
su := b.Transactions[i].Payload.(*payload.StateUpdate)
819+
820+
// stateKey
821+
statePrefix := []byte{byte(ST_STATES)}
822+
stateKey := append(statePrefix, su.Namespace...)
823+
stateKey = append(stateKey, su.Key...)
824+
//stateValueOld, err_get := bd.st.Get(stateKey)
825+
826+
// stateValue
827+
//stateValue := bytes.NewBuffer(nil)
828+
//serialization.WriteVarBytes(stateValue, su.Value)
829+
830+
// verify tx signer public is in StateUpdater list.
831+
//publicKey := b.Transactions[i].Programs[0].Parameter[1:34]
832+
log.Trace(fmt.Sprintf("StateUpdate tx publickey: %x", su.Updater))
833+
834+
stateUpdater, err := bd.GetStateUpdater()
835+
if err != nil {
836+
return err
837+
}
838+
839+
findflag := false
840+
for k := 0; k < len(stateUpdater); k++ {
841+
log.Trace(fmt.Sprintf("StateUpdate updaterPublickey %d: %x %x", k, stateUpdater[k].X, stateUpdater[k].Y))
842+
843+
if su.Updater.X.Cmp(stateUpdater[k].X) == 0 && su.Updater.Y.Cmp(stateUpdater[k].Y) == 0 {
844+
findflag = true
845+
break
846+
}
847+
}
848+
849+
if !findflag {
850+
return errors.New(fmt.Sprintf("[persist] stateUpdater publickey not found in store, reject. tx publickey: %x", su.Updater))
851+
}
852+
853+
// if not found in store, put value to the key.
854+
// if found in store, rewrite value.
855+
log.Trace(fmt.Sprintf("[persist] StateUpdate modify, key: %x, value:%x", stateKey, su.Value))
856+
bd.st.BatchPut(stateKey, su.Value)
857+
}
858+
769859
for index := 0; index < len(b.Transactions[i].Outputs); index++ {
770860
output := b.Transactions[i].Outputs[index]
771861
programHash := output.ProgramHash
@@ -1279,6 +1369,45 @@ func (bd *ChainStore) GetAccount(programHash Uint160) (*account.AccountState, er
12791369
return accountState, nil
12801370
}
12811371

1372+
func (bd *ChainStore) IsStateUpdaterVaild(Tx *tx.Transaction) bool {
1373+
su := Tx.Payload.(*payload.StateUpdate)
1374+
1375+
stateUpdater, err := bd.GetStateUpdater()
1376+
if err != nil {
1377+
return false
1378+
}
1379+
1380+
findflag := false
1381+
for k := 0; k < len(stateUpdater); k++ {
1382+
log.Trace(fmt.Sprintf("StateUpdate updaterPublickey %d: %x %x", k, stateUpdater[k].X, stateUpdater[k].Y))
1383+
1384+
if su.Updater.X.Cmp(stateUpdater[k].X) == 0 && su.Updater.Y.Cmp(stateUpdater[k].Y) == 0 {
1385+
findflag = true
1386+
break
1387+
}
1388+
}
1389+
1390+
if !findflag {
1391+
return false
1392+
}
1393+
1394+
return true
1395+
}
1396+
1397+
func (bd *ChainStore) GetState(namespace []byte, key []byte) ([]byte, error) {
1398+
1399+
// stateKey
1400+
statePrefix := []byte{byte(ST_STATES)}
1401+
stateKey := append(statePrefix, namespace...)
1402+
stateKey = append(stateKey, key...)
1403+
stateValue, err := bd.st.Get(stateKey)
1404+
if err != nil {
1405+
return nil, err
1406+
}
1407+
1408+
return stateValue, nil
1409+
}
1410+
12821411
func (bd *ChainStore) GetUnspentFromProgramHash(programHash Uint160, assetid Uint256) ([]*tx.UTXOUnspent, error) {
12831412

12841413
prefix := []byte{byte(IX_Unspent_UTXO)}

core/store/ChainStore/DataEntryPrefix.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,17 @@ const (
2222
ST_QuantityIssued DataEntryPrefix = 0xc1
2323
ST_ACCOUNT DataEntryPrefix = 0xc2
2424

25+
// STATES
26+
ST_STATES DataEntryPrefix = 0xd0
27+
2528
//SYSTEM
2629
SYS_CurrentBlock DataEntryPrefix = 0x40
2730
SYS_CurrentHeader DataEntryPrefix = 0x41
2831
SYS_CurrentBookKeeper DataEntryPrefix = 0x42
2932

33+
// CA
34+
CA_StateUpdater DataEntryPrefix = 0x50
35+
3036
//CONFIG
3137
CFG_Version DataEntryPrefix = 0xf0
3238
)
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
package payload
2+
3+
import (
4+
"DNA/common/serialization"
5+
"DNA/crypto"
6+
. "DNA/errors"
7+
"errors"
8+
"io"
9+
)
10+
11+
type StateUpdate struct {
12+
Namespace []byte
13+
Key []byte
14+
Value []byte
15+
Updater *crypto.PubKey
16+
}
17+
18+
func (su *StateUpdate) Data() []byte {
19+
return []byte{0}
20+
}
21+
22+
func (su *StateUpdate) Serialize(w io.Writer) error {
23+
err := serialization.WriteVarBytes(w, su.Namespace)
24+
if err != nil {
25+
return NewDetailErr(err, ErrNoCode, "[StateUpdate], Namespace serialize failed.")
26+
}
27+
28+
err = serialization.WriteVarBytes(w, su.Key)
29+
if err != nil {
30+
return NewDetailErr(err, ErrNoCode, "[StateUpdate], key serialize failed.")
31+
}
32+
33+
err = serialization.WriteVarBytes(w, su.Value)
34+
if err != nil {
35+
return NewDetailErr(err, ErrNoCode, "[StateUpdate], value serialize failed.")
36+
}
37+
38+
su.Updater.Serialize(w)
39+
40+
return nil
41+
}
42+
43+
func (su *StateUpdate) Deserialize(r io.Reader) error {
44+
var err error
45+
46+
su.Namespace, err = serialization.ReadVarBytes(r)
47+
if err != nil {
48+
return NewDetailErr(errors.New("[StateUpdate], Namespace deserialize failed."), ErrNoCode, "")
49+
}
50+
51+
su.Key, err = serialization.ReadVarBytes(r)
52+
if err != nil {
53+
return NewDetailErr(errors.New("[StateUpdate], key deserialize failed."), ErrNoCode, "")
54+
}
55+
56+
su.Value, err = serialization.ReadVarBytes(r)
57+
if err != nil {
58+
return NewDetailErr(errors.New("[StateUpdate], value deserialize failed."), ErrNoCode, "")
59+
}
60+
61+
su.Updater = new(crypto.PubKey)
62+
err = su.Updater.DeSerialize(r)
63+
if err != nil {
64+
return NewDetailErr(err, ErrNoCode, "[StateUpdate], updater Deserialize failed.")
65+
}
66+
67+
return nil
68+
}

core/transaction/transaction.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ const (
2828
RegisterAsset TransactionType = 0x40
2929
TransferAsset TransactionType = 0x80
3030
Record TransactionType = 0x81
31+
StateUpdate TransactionType = 0x90
3132
DeployCode TransactionType = 0xd0
3233
DataFile TransactionType = 0x12
3334
)
@@ -200,6 +201,8 @@ func (tx *Transaction) DeserializeUnsignedWithoutType(r io.Reader) error {
200201
tx.Payload = new(payload.PrivacyPayload)
201202
case DataFile:
202203
tx.Payload = new(payload.DataFile)
204+
case StateUpdate:
205+
tx.Payload = new(payload.StateUpdate)
203206
default:
204207
return errors.New("[Transaction],invalide transaction type.")
205208
}
@@ -340,6 +343,18 @@ func (tx *Transaction) GetProgramHashes() ([]Uint160, error) {
340343
return nil, NewDetailErr(err, ErrNoCode, "[Transaction], GetProgramHashes ToCodeHash failed.")
341344
}
342345
hashs = append(hashs, astHash)
346+
case StateUpdate:
347+
updater := tx.Payload.(*payload.StateUpdate).Updater
348+
signatureRedeemScript, err := contract.CreateSignatureRedeemScript(updater)
349+
if err != nil {
350+
return nil, NewDetailErr(err, ErrNoCode, "[Transaction], StateUpdate GetProgramHashes CreateSignatureRedeemScript failed.")
351+
}
352+
353+
astHash, err := ToCodeHash(signatureRedeemScript)
354+
if err != nil {
355+
return nil, NewDetailErr(err, ErrNoCode, "[Transaction], StateUpdate GetProgramHashes ToCodeHash failed.")
356+
}
357+
hashs = append(hashs, astHash)
343358
default:
344359
}
345360
//remove dupilicated hashes

0 commit comments

Comments
 (0)