Commit df9d9538 authored by harrylee's avatar harrylee Committed by vipwzw

rebuild storage

parent 687f0d38
...@@ -12,25 +12,25 @@ import ( ...@@ -12,25 +12,25 @@ import (
func (s *storage) Exec_ContentStorage(payload *storagetypes.ContentOnlyNotaryStorage, tx *types.Transaction, index int) (*types.Receipt, error) { func (s *storage) Exec_ContentStorage(payload *storagetypes.ContentOnlyNotaryStorage, tx *types.Transaction, index int) (*types.Receipt, error) {
action := newStorageAction(s, tx, index) action := newStorageAction(s, tx, index)
return action.ContentStorage(&storagetypes.Storage{Value: &storagetypes.Storage_ContentStorage{ContentStorage: payload}}) return action.ContentStorage(payload)
} }
func (s *storage) Exec_HashStorage(payload *storagetypes.HashOnlyNotaryStorage, tx *types.Transaction, index int) (*types.Receipt, error) { func (s *storage) Exec_HashStorage(payload *storagetypes.HashOnlyNotaryStorage, tx *types.Transaction, index int) (*types.Receipt, error) {
action := newStorageAction(s, tx, index) action := newStorageAction(s, tx, index)
return action.HashStorage(&storagetypes.Storage{Value: &storagetypes.Storage_HashStorage{HashStorage: payload}}) return action.HashStorage(payload)
} }
func (s *storage) Exec_LinkStorage(payload *storagetypes.LinkNotaryStorage, tx *types.Transaction, index int) (*types.Receipt, error) { func (s *storage) Exec_LinkStorage(payload *storagetypes.LinkNotaryStorage, tx *types.Transaction, index int) (*types.Receipt, error) {
action := newStorageAction(s, tx, index) action := newStorageAction(s, tx, index)
return action.LinkStorage(&storagetypes.Storage{Value: &storagetypes.Storage_LinkStorage{LinkStorage: payload}}) return action.LinkStorage(payload)
} }
func (s *storage) Exec_EncryptStorage(payload *storagetypes.EncryptNotaryStorage, tx *types.Transaction, index int) (*types.Receipt, error) { func (s *storage) Exec_EncryptStorage(payload *storagetypes.EncryptNotaryStorage, tx *types.Transaction, index int) (*types.Receipt, error) {
action := newStorageAction(s, tx, index) action := newStorageAction(s, tx, index)
return action.EncryptStorage(&storagetypes.Storage{Value: &storagetypes.Storage_EncryptStorage{EncryptStorage: payload}}) return action.EncryptStorage(payload)
} }
func (s *storage) Exec_EncryptShareStorage(payload *storagetypes.EncryptShareNotaryStorage, tx *types.Transaction, index int) (*types.Receipt, error) { func (s *storage) Exec_EncryptShareStorage(payload *storagetypes.EncryptShareNotaryStorage, tx *types.Transaction, index int) (*types.Receipt, error) {
action := newStorageAction(s, tx, index) action := newStorageAction(s, tx, index)
return action.EncryptShareStorage(&storagetypes.Storage{Value: &storagetypes.Storage_EncryptShareStorage{EncryptShareStorage: payload}}) return action.EncryptShareStorage(payload)
} }
package executor package executor
import ( import (
"fmt"
"github.com/33cn/chain33/types" "github.com/33cn/chain33/types"
storagetypes "github.com/33cn/plugin/plugin/dapp/storage/types" ety "github.com/33cn/plugin/plugin/dapp/storage/types"
) )
/* /*
...@@ -10,33 +11,94 @@ import ( ...@@ -10,33 +11,94 @@ import (
* 非关键数据,本地存储(localDB), 用于辅助查询,效率高 * 非关键数据,本地存储(localDB), 用于辅助查询,效率高
*/ */
func (s *storage) ExecLocal_ContentStorage(payload *storagetypes.ContentOnlyNotaryStorage, tx *types.Transaction, receiptData *types.ReceiptData, index int) (*types.LocalDBSet, error) { func (s *storage) ExecLocal_ContentStorage(payload *ety.ContentOnlyNotaryStorage, tx *types.Transaction, receiptData *types.ReceiptData, index int) (*types.LocalDBSet, error) {
dbSet := &types.LocalDBSet{} dbSet := &types.LocalDBSet{}
//implement code if receiptData.Ty == types.ExecOk {
for _, log := range receiptData.Logs {
switch log.Ty {
case ety.TyContentStorageLog:
storage := &ety.Storage{}
if err := types.Decode(log.Log, storage); err != nil {
return nil, err
}
fmt.Println(string(storage.GetContentStorage().Key))
kv := &types.KeyValue{Key: getLocalDBKey(storage.GetContentStorage().Key), Value: types.Encode(storage)}
dbSet.KV = append(dbSet.KV, kv)
}
}
}
return s.addAutoRollBack(tx, dbSet.KV), nil return s.addAutoRollBack(tx, dbSet.KV), nil
} }
func (s *storage) ExecLocal_HashStorage(payload *storagetypes.HashOnlyNotaryStorage, tx *types.Transaction, receiptData *types.ReceiptData, index int) (*types.LocalDBSet, error) { func (s *storage) ExecLocal_HashStorage(payload *ety.HashOnlyNotaryStorage, tx *types.Transaction, receiptData *types.ReceiptData, index int) (*types.LocalDBSet, error) {
dbSet := &types.LocalDBSet{} dbSet := &types.LocalDBSet{}
//implement code if receiptData.Ty == types.ExecOk {
for _, log := range receiptData.Logs {
switch log.Ty {
case ety.TyHashStorageLog:
storage := &ety.Storage{}
if err := types.Decode(log.Log, storage); err != nil {
return nil, err
}
kv := &types.KeyValue{Key: getLocalDBKey(storage.GetHashStorage().Key), Value: types.Encode(storage)}
dbSet.KV = append(dbSet.KV, kv)
}
}
}
return s.addAutoRollBack(tx, dbSet.KV), nil return s.addAutoRollBack(tx, dbSet.KV), nil
} }
func (s *storage) ExecLocal_LinkStorage(payload *storagetypes.LinkNotaryStorage, tx *types.Transaction, receiptData *types.ReceiptData, index int) (*types.LocalDBSet, error) { func (s *storage) ExecLocal_LinkStorage(payload *ety.LinkNotaryStorage, tx *types.Transaction, receiptData *types.ReceiptData, index int) (*types.LocalDBSet, error) {
dbSet := &types.LocalDBSet{} dbSet := &types.LocalDBSet{}
//implement code if receiptData.Ty == types.ExecOk {
for _, log := range receiptData.Logs {
switch log.Ty {
case ety.TyLinkStorageLog:
storage := &ety.Storage{}
if err := types.Decode(log.Log, storage); err != nil {
return nil, err
}
kv := &types.KeyValue{Key: getLocalDBKey(storage.GetLinkStorage().Key), Value: types.Encode(storage)}
dbSet.KV = append(dbSet.KV, kv)
}
}
}
return s.addAutoRollBack(tx, dbSet.KV), nil return s.addAutoRollBack(tx, dbSet.KV), nil
} }
func (s *storage) ExecLocal_EncryptStorage(payload *storagetypes.EncryptNotaryStorage, tx *types.Transaction, receiptData *types.ReceiptData, index int) (*types.LocalDBSet, error) { func (s *storage) ExecLocal_EncryptStorage(payload *ety.EncryptNotaryStorage, tx *types.Transaction, receiptData *types.ReceiptData, index int) (*types.LocalDBSet, error) {
dbSet := &types.LocalDBSet{} dbSet := &types.LocalDBSet{}
//implement code if receiptData.Ty == types.ExecOk {
for _, log := range receiptData.Logs {
switch log.Ty {
case ety.TyEncryptStorageLog:
storage := &ety.Storage{}
if err := types.Decode(log.Log, storage); err != nil {
return nil, err
}
kv := &types.KeyValue{Key: getLocalDBKey(storage.GetEncryptStorage().Key), Value: types.Encode(storage)}
dbSet.KV = append(dbSet.KV, kv)
}
}
}
return s.addAutoRollBack(tx, dbSet.KV), nil return s.addAutoRollBack(tx, dbSet.KV), nil
} }
func (s *storage) ExecLocal_EncryptShareStorage(payload *storagetypes.EncryptShareNotaryStorage, tx *types.Transaction, receiptData *types.ReceiptData, index int) (*types.LocalDBSet, error) { func (s *storage) ExecLocal_EncryptShareStorage(payload *ety.EncryptShareNotaryStorage, tx *types.Transaction, receiptData *types.ReceiptData, index int) (*types.LocalDBSet, error) {
dbSet := &types.LocalDBSet{} dbSet := &types.LocalDBSet{}
//implement code if receiptData.Ty == types.ExecOk {
for _, log := range receiptData.Logs {
switch log.Ty {
case ety.TyEncryptShareStorageLog:
storage := &ety.Storage{}
if err := types.Decode(log.Log, storage); err != nil {
return nil, err
}
kv := &types.KeyValue{Key: getLocalDBKey(storage.GetEncryptShareStorage().Key), Value: types.Encode(storage)}
dbSet.KV = append(dbSet.KV, kv)
}
}
}
return s.addAutoRollBack(tx, dbSet.KV), nil return s.addAutoRollBack(tx, dbSet.KV), nil
} }
......
...@@ -19,3 +19,9 @@ func Key(txHash string) (key []byte) { ...@@ -19,3 +19,9 @@ func Key(txHash string) (key []byte) {
key = append(key, []byte(txHash)...) key = append(key, []byte(txHash)...)
return key return key
} }
func getLocalDBKey(txHash string) (key []byte) {
key = append(key, []byte(KeyPrefixLocalDB)...)
key = append(key, []byte(txHash)...)
return key
}
...@@ -7,10 +7,10 @@ import ( ...@@ -7,10 +7,10 @@ import (
//从statedb 读取原始数据 //从statedb 读取原始数据
func (s *storage) Query_QueryStorage(in *storagetypes.QueryStorage) (types.Message, error) { func (s *storage) Query_QueryStorage(in *storagetypes.QueryStorage) (types.Message, error) {
return QueryStorage(s.GetStateDB(), in) return QueryStorage(s.GetStateDB(), s.GetLocalDB(), in.TxHash)
} }
//通过状态查询ids //通过状态查询ids
func (s *storage) Query_BatchQueryStorage(in *storagetypes.BatchQueryStorage) (types.Message, error) { func (s *storage) Query_BatchQueryStorage(in *storagetypes.BatchQueryStorage) (types.Message, error) {
return BatchQueryStorage(s.GetStateDB(), in) return BatchQueryStorage(s.GetStateDB(), s.GetLocalDB(), in)
} }
...@@ -51,6 +51,11 @@ func (s *storage) GetDriverName() string { ...@@ -51,6 +51,11 @@ func (s *storage) GetDriverName() string {
return driverName return driverName
} }
//ExecutorOrder Exec 的时候 同时执行 ExecLocal
func (s *storage) ExecutorOrder() int64 {
return drivers.ExecLocalSameTime
}
// CheckTx 实现自定义检验交易接口,供框架调用 // CheckTx 实现自定义检验交易接口,供框架调用
func (s *storage) CheckTx(tx *types.Transaction, index int) error { func (s *storage) CheckTx(tx *types.Transaction, index int) error {
// implement code // implement code
......
...@@ -61,7 +61,7 @@ var ( ...@@ -61,7 +61,7 @@ var (
func init() { func init() {
r = rand.New(rand.NewSource(types.Now().UnixNano())) r = rand.New(rand.NewSource(types.Now().UnixNano()))
} }
func TestOrace(t *testing.T) { func TestStorage(t *testing.T) {
cfg := types.NewChain33Config(strings.Replace(types.GetDefaultCfgstring(), "Title=\"local\"", "Title=\"chain33\"", 1)) cfg := types.NewChain33Config(strings.Replace(types.GetDefaultCfgstring(), "Title=\"local\"", "Title=\"chain33\"", 1))
Init(oty.StorageX, cfg, nil) Init(oty.StorageX, cfg, nil)
total := 100 * types.Coin total := 100 * types.Coin
...@@ -102,204 +102,65 @@ func TestOrace(t *testing.T) { ...@@ -102,204 +102,65 @@ func TestOrace(t *testing.T) {
accD, _ := account.NewAccountDB(cfg, "coins", "bty", stateDB) accD, _ := account.NewAccountDB(cfg, "coins", "bty", stateDB)
accD.SaveExecAccount(execAddr, &accountD) accD.SaveExecAccount(execAddr, &accountD)
env := execEnv{ env := &execEnv{
10, 10,
cfg.GetDappFork(oty.StorageX, "Enable"), cfg.GetDappFork(oty.StorageX, "Enable"),
1539918074, 1539918074,
} }
// publish event tx, err := CreateTx("ContentStorage", &oty.ContentOnlyNotaryStorage{Content: contents[0], Op: 0}, PrivKeyA, cfg)
ety := types.LoadExecutorType(oty.StorageX)
tx, err := ety.Create("ContentStorage", &oty.ContentOnlyNotaryStorage{Content: contents[0]})
assert.Nil(t, err)
tx, err = types.FormatTx(cfg, oty.StorageX, tx)
assert.Nil(t, err)
tx, err = signTx(tx, PrivKeyA)
assert.Nil(t, err) assert.Nil(t, err)
t.Log("tx", tx) Exec_Block(t, stateDB, kvdb, env, tx)
exec := newStorage()
q := queue.New("channel")
q.SetConfig(cfg)
api, _ := client.New(q.Client(), nil)
exec.SetAPI(api)
exec.SetStateDB(stateDB)
exec.SetLocalDB(kvdb)
exec.SetEnv(1, env.blockTime, env.difficulty)
receipt, err := exec.Exec(tx, int(1))
if err != nil {
t.Error(err)
}
for _, kv := range receipt.KV {
stateDB.Set(kv.Key, kv.Value)
}
receiptDate := &types.ReceiptData{Ty: receipt.Ty, Logs: receipt.Logs}
set, err := exec.ExecLocal(tx, receiptDate, int(1))
if err != nil {
t.Error(err)
}
for _, kv := range set.KV {
kvdb.Set(kv.Key, kv.Value)
}
txhash := common.ToHex(tx.Hash()) txhash := common.ToHex(tx.Hash())
t.Log("txhash:", txhash)
//根据hash查询存储得明文内容 //根据hash查询存储得明文内容
msg, err := exec.Query(oty.FuncNameQueryStorage, types.Encode(&oty.QueryStorage{ reply, err := QueryStorageByKey(stateDB, kvdb, txhash, cfg)
TxHash: txhash})) assert.Nil(t, err)
if err != nil {
t.Error(err)
}
t.Log(msg)
reply := msg.(*oty.Storage)
assert.Equal(t, contents[0], reply.GetContentStorage().Content) assert.Equal(t, contents[0], reply.GetContentStorage().Content)
//根据hash批量查询存储数据 //根据hash批量查询存储数据
msg, err = exec.Query(oty.FuncNameBatchQueryStorage, types.Encode(&oty.BatchQueryStorage{ reply2, err := QueryBatchStorageByKey(stateDB, kvdb, &oty.BatchQueryStorage{TxHashs: []string{txhash}}, cfg)
TxHashs: []string{txhash}})) assert.Nil(t, err)
if err != nil {
t.Error(err)
}
t.Log(msg)
reply2 := msg.(*oty.BatchReplyStorage)
assert.Equal(t, contents[0], reply2.Storages[0].GetContentStorage().Content) assert.Equal(t, contents[0], reply2.Storages[0].GetContentStorage().Content)
tx, err = ety.Create("HashStorage", &oty.HashOnlyNotaryStorage{Hash: common.Sha256(contents[0])}) tx, err = CreateTx("ContentStorage", &oty.ContentOnlyNotaryStorage{Content: contents[1], Op: 1,Key:txhash}, PrivKeyA, cfg)
assert.Nil(t, err) assert.Nil(t, err)
tx, err = types.FormatTx(cfg, oty.StorageX, tx) Exec_Block(t, stateDB, kvdb, env, tx)
reply, err = QueryStorageByKey(stateDB, kvdb, txhash, cfg)
assert.Nil(t, err) assert.Nil(t, err)
tx, err = signTx(tx, PrivKeyA) assert.Equal(t, append(append(contents[0],[]byte(",")...),contents[1]...), reply.GetContentStorage().Content)
tx, err = CreateTx("HashStorage", &oty.HashOnlyNotaryStorage{Hash: common.Sha256(contents[0])}, PrivKeyA, cfg)
assert.Nil(t, err) assert.Nil(t, err)
t.Log("tx", tx) Exec_Block(t, stateDB, kvdb, env, tx)
exec.SetEnv(env.blockHeight+1, env.blockTime+20, env.difficulty+1)
receipt, err = exec.Exec(tx, int(1))
if err != nil {
t.Error(err)
}
for _, kv := range receipt.KV {
stateDB.Set(kv.Key, kv.Value)
}
receiptDate = &types.ReceiptData{Ty: receipt.Ty, Logs: receipt.Logs}
set, err = exec.ExecLocal(tx, receiptDate, int(1))
if err != nil {
t.Error(err)
}
for _, kv := range set.KV {
kvdb.Set(kv.Key, kv.Value)
}
txhash = common.ToHex(tx.Hash()) txhash = common.ToHex(tx.Hash())
t.Log("txhash:", txhash)
//根据hash查询存储得明文内容 //根据hash查询存储得明文内容
msg, err = exec.Query(oty.FuncNameQueryStorage, types.Encode(&oty.QueryStorage{ reply, err = QueryStorageByKey(stateDB, kvdb, txhash, cfg)
TxHash: txhash})) assert.Nil(t, err)
if err != nil {
t.Error(err)
}
t.Log(msg)
reply = msg.(*oty.Storage)
assert.Equal(t, common.Sha256(contents[0]), reply.GetHashStorage().Hash) assert.Equal(t, common.Sha256(contents[0]), reply.GetHashStorage().Hash)
//根据hash批量查询存储数据
msg, err = exec.Query(oty.FuncNameBatchQueryStorage, types.Encode(&oty.BatchQueryStorage{
TxHashs: []string{txhash}}))
if err != nil {
t.Error(err)
}
t.Log(msg)
reply2 = msg.(*oty.BatchReplyStorage)
assert.Equal(t, common.Sha256(contents[0]), reply2.Storages[0].GetHashStorage().Hash)
//存储链接地址 //存储链接地址
tx, err = ety.Create("LinkStorage", &oty.LinkNotaryStorage{Hash: common.Sha256(contents[0]), Link: contents[0]}) tx, err = CreateTx("LinkStorage", &oty.LinkNotaryStorage{Hash: common.Sha256(contents[0]), Link: contents[0]}, PrivKeyA, cfg)
assert.Nil(t, err) assert.Nil(t, err)
tx, err = types.FormatTx(cfg, oty.StorageX, tx) Exec_Block(t, stateDB, kvdb, env, tx)
assert.Nil(t, err)
tx, err = signTx(tx, PrivKeyA)
assert.Nil(t, err)
t.Log("tx", tx)
exec.SetEnv(env.blockHeight+1, env.blockTime+20, env.difficulty+1)
receipt, err = exec.Exec(tx, int(1))
if err != nil {
t.Error(err)
}
for _, kv := range receipt.KV {
stateDB.Set(kv.Key, kv.Value)
}
receiptDate = &types.ReceiptData{Ty: receipt.Ty, Logs: receipt.Logs}
set, err = exec.ExecLocal(tx, receiptDate, int(1))
if err != nil {
t.Error(err)
}
for _, kv := range set.KV {
kvdb.Set(kv.Key, kv.Value)
}
txhash = common.ToHex(tx.Hash()) txhash = common.ToHex(tx.Hash())
t.Log("txhash:", txhash)
//根据hash查询存储得明文内容 //根据hash查询存储得明文内容
msg, err = exec.Query(oty.FuncNameQueryStorage, types.Encode(&oty.QueryStorage{ reply, err = QueryStorageByKey(stateDB, kvdb, txhash, cfg)
TxHash: txhash})) assert.Nil(t, err)
if err != nil {
t.Error(err)
}
t.Log(msg)
reply = msg.(*oty.Storage)
assert.Equal(t, common.Sha256(contents[0]), reply.GetLinkStorage().Hash) assert.Equal(t, common.Sha256(contents[0]), reply.GetLinkStorage().Hash)
//根据hash批量查询存储数据
msg, err = exec.Query(oty.FuncNameBatchQueryStorage, types.Encode(&oty.BatchQueryStorage{
TxHashs: []string{txhash}}))
if err != nil {
t.Error(err)
}
t.Log(msg)
reply2 = msg.(*oty.BatchReplyStorage)
assert.Equal(t, common.Sha256(contents[0]), reply2.Storages[0].GetLinkStorage().Hash)
//加密存储 //加密存储
aes := des.NewAES(keys[2], ivs[0]) aes := des.NewAES(keys[2], ivs[0])
crypted, err := aes.Encrypt(contents[0]) crypted, err := aes.Encrypt(contents[0])
if err != nil {
t.Error(err)
}
tx, err = ety.Create("EncryptStorage", &oty.EncryptNotaryStorage{ContentHash: common.Sha256(contents[0]), EncryptContent: crypted, Nonce: ivs[0]})
assert.Nil(t, err) assert.Nil(t, err)
tx, err = types.FormatTx(cfg, oty.StorageX, tx) tx, err = CreateTx("EncryptStorage", &oty.EncryptNotaryStorage{ContentHash: common.Sha256(contents[0]), EncryptContent: crypted, Nonce: ivs[0]}, PrivKeyA, cfg)
assert.Nil(t, err)
tx, err = signTx(tx, PrivKeyA)
assert.Nil(t, err) assert.Nil(t, err)
t.Log("tx", tx) Exec_Block(t, stateDB, kvdb, env, tx)
exec.SetEnv(env.blockHeight+1, env.blockTime+20, env.difficulty+1)
receipt, err = exec.Exec(tx, int(1))
if err != nil {
t.Error(err)
}
for _, kv := range receipt.KV {
stateDB.Set(kv.Key, kv.Value)
}
receiptDate = &types.ReceiptData{Ty: receipt.Ty, Logs: receipt.Logs}
set, err = exec.ExecLocal(tx, receiptDate, int(1))
if err != nil {
t.Error(err)
}
for _, kv := range set.KV {
kvdb.Set(kv.Key, kv.Value)
}
txhash = common.ToHex(tx.Hash()) txhash = common.ToHex(tx.Hash())
t.Log("txhash:", txhash) reply, err = QueryStorageByKey(stateDB, kvdb, txhash, cfg)
//根据hash查询存储得明文内容 assert.Nil(t, err)
msg, err = exec.Query(oty.FuncNameQueryStorage, types.Encode(&oty.QueryStorage{
TxHash: txhash}))
if err != nil {
t.Error(err)
}
t.Log(msg)
reply = msg.(*oty.Storage)
assert.Equal(t, common.Sha256(contents[0]), reply.GetEncryptStorage().ContentHash) assert.Equal(t, common.Sha256(contents[0]), reply.GetEncryptStorage().ContentHash)
assert.Equal(t, crypted, reply.GetEncryptStorage().EncryptContent) assert.Equal(t, crypted, reply.GetEncryptStorage().EncryptContent)
assert.Equal(t, ivs[0], reply.GetEncryptStorage().Nonce) assert.Equal(t, ivs[0], reply.GetEncryptStorage().Nonce)
} }
...@@ -324,3 +185,96 @@ func signTx(tx *types.Transaction, hexPrivKey string) (*types.Transaction, error ...@@ -324,3 +185,96 @@ func signTx(tx *types.Transaction, hexPrivKey string) (*types.Transaction, error
tx.Sign(int32(signType), privKey) tx.Sign(int32(signType), privKey)
return tx, nil return tx, nil
} }
func QueryStorageByKey(stateDB dbm.DB, kvdb dbm.KVDB, key string, cfg *types.Chain33Config) (*oty.Storage, error) {
exec := newStorage()
q := queue.New("channel")
q.SetConfig(cfg)
api, _ := client.New(q.Client(), nil)
exec.SetAPI(api)
exec.SetStateDB(stateDB)
exec.SetLocalDB(kvdb)
//根据hash查询存储得明文内容
msg, err := exec.Query(oty.FuncNameQueryStorage, types.Encode(&oty.QueryStorage{
TxHash: key}))
if err != nil {
return nil, err
}
return msg.(*oty.Storage), nil
}
func QueryBatchStorageByKey(stateDB dbm.DB, kvdb dbm.KVDB, para *oty.BatchQueryStorage, cfg *types.Chain33Config) (*oty.BatchReplyStorage, error) {
exec := newStorage()
q := queue.New("channel")
q.SetConfig(cfg)
api, _ := client.New(q.Client(), nil)
exec.SetAPI(api)
exec.SetStateDB(stateDB)
exec.SetLocalDB(kvdb)
//根据hash查询存储得明文内容
msg, err := exec.Query(oty.FuncNameBatchQueryStorage, types.Encode(para))
if err != nil {
return nil, err
}
return msg.(*oty.BatchReplyStorage), nil
}
func CreateTx(action string, message types.Message, priv string, cfg *types.Chain33Config) (*types.Transaction, error) {
ety := types.LoadExecutorType(oty.StorageX)
tx, err := ety.Create(action, message)
if err != nil {
return nil, err
}
tx, err = types.FormatTx(cfg, oty.StorageX, tx)
if err != nil {
return nil, err
}
tx, err = signTx(tx, PrivKeyA)
return tx, err
}
//模拟区块中交易得执行过程
func Exec_Block(t *testing.T, stateDB dbm.DB, kvdb dbm.KVDB, env *execEnv, txs ...*types.Transaction) error {
cfg := types.NewChain33Config(types.GetDefaultCfgstring())
cfg.SetTitleOnlyForTest("chain33")
exec := newStorage()
e := exec.(*storage)
for index, tx := range txs {
err := e.CheckTx(tx, index)
if err != nil {
t.Log(err.Error())
return err
}
}
q := queue.New("channel")
q.SetConfig(cfg)
api, _ := client.New(q.Client(), nil)
exec.SetAPI(api)
exec.SetStateDB(stateDB)
exec.SetLocalDB(kvdb)
env.blockHeight = env.blockHeight + 1
env.blockTime = env.blockTime + 20
env.difficulty = env.difficulty + 1
exec.SetEnv(env.blockHeight, env.blockTime, env.difficulty)
for index, tx := range txs {
receipt, err := exec.Exec(tx, index)
if err != nil {
t.Log(err.Error())
return err
}
for _, kv := range receipt.KV {
stateDB.Set(kv.Key, kv.Value)
}
receiptData := &types.ReceiptData{Ty: receipt.Ty, Logs: receipt.Logs}
set, err := exec.ExecLocal(tx, receiptData, index)
if err != nil {
t.Log(err.Error())
return err
}
for _, kv := range set.KV {
kvdb.Set(kv.Key, kv.Value)
}
//save to database
util.SaveKVList(stateDB, set.KV)
assert.Equal(t, types.ExecOk, int(receipt.Ty))
}
return nil
}
...@@ -6,12 +6,13 @@ import ( ...@@ -6,12 +6,13 @@ import (
"github.com/33cn/chain33/common" "github.com/33cn/chain33/common"
dbm "github.com/33cn/chain33/common/db" dbm "github.com/33cn/chain33/common/db"
"github.com/33cn/chain33/types" "github.com/33cn/chain33/types"
storagetypes "github.com/33cn/plugin/plugin/dapp/storage/types" ety "github.com/33cn/plugin/plugin/dapp/storage/types"
"github.com/golang/protobuf/proto" "github.com/golang/protobuf/proto"
) )
type StorageAction struct { type StorageAction struct {
db dbm.KV db dbm.KV
localdb dbm.KV
txhash []byte txhash []byte
fromaddr string fromaddr string
blocktime int64 blocktime int64
...@@ -22,7 +23,7 @@ type StorageAction struct { ...@@ -22,7 +23,7 @@ type StorageAction struct {
func newStorageAction(s *storage, tx *types.Transaction, index int) *StorageAction { func newStorageAction(s *storage, tx *types.Transaction, index int) *StorageAction {
hash := tx.Hash() hash := tx.Hash()
fromaddr := tx.From() fromaddr := tx.From()
return &StorageAction{s.GetStateDB(), hash, fromaddr, return &StorageAction{s.GetStateDB(), s.GetLocalDB(), hash, fromaddr,
s.GetBlockTime(), s.GetHeight(), index} s.GetBlockTime(), s.GetHeight(), index}
} }
func (s *StorageAction) GetKVSet(payload proto.Message) (kvset []*types.KeyValue) { func (s *StorageAction) GetKVSet(payload proto.Message) (kvset []*types.KeyValue) {
...@@ -30,54 +31,114 @@ func (s *StorageAction) GetKVSet(payload proto.Message) (kvset []*types.KeyValue ...@@ -30,54 +31,114 @@ func (s *StorageAction) GetKVSet(payload proto.Message) (kvset []*types.KeyValue
return kvset return kvset
} }
func (s *StorageAction) ContentStorage(payload proto.Message) (*types.Receipt, error) { func (s *StorageAction) ContentStorage(payload *ety.ContentOnlyNotaryStorage) (*types.Receipt, error) {
//TODO 这里可以加具体得文本内容限制,超过指定大小的数据不容许写到状态数据库中 //TODO 这里可以加具体得文本内容限制,超过指定大小的数据不容许写到状态数据库中
var logs []*types.ReceiptLog var logs []*types.ReceiptLog
log := &types.ReceiptLog{Ty: storagetypes.TyContentStorageLog} var kvs []*types.KeyValue
key := payload.Key
op := payload.Op
if key == "" {
key = common.ToHex(s.txhash)
}
payload.Key = key
storage, err := QueryStorageFromLocalDB(s.localdb, key)
if op == ety.OpCreate {
if err != types.ErrNotFound {
return nil, ety.ErrKeyExisted
}
} else {
if err == nil && storage.Ty != ety.TyContentStorageAction {
return nil, ety.ErrStorageType
}
content := append(storage.GetContentStorage().Content, []byte(",")...)
payload.Content = append(content, payload.Content...)
}
stg := &ety.Storage{Value: &ety.Storage_ContentStorage{ContentStorage: payload}, Ty: ety.TyContentStorageAction}
log := &types.ReceiptLog{Ty: ety.TyContentStorageLog, Log: types.Encode(stg)}
logs = append(logs, log) logs = append(logs, log)
kv := s.GetKVSet(payload) receipt := &types.Receipt{Ty: types.ExecOk, KV: kvs, Logs: logs}
receipt := &types.Receipt{Ty: types.ExecOk, KV: kv, Logs: logs}
return receipt, nil return receipt, nil
} }
func (s *StorageAction) HashStorage(payload proto.Message) (*types.Receipt, error) { func (s *StorageAction) HashStorage(payload *ety.HashOnlyNotaryStorage) (*types.Receipt, error) {
var logs []*types.ReceiptLog var logs []*types.ReceiptLog
log := &types.ReceiptLog{Ty: storagetypes.TyHashStorageLog} var kvs []*types.KeyValue
key := payload.Key
if key == "" {
key = common.ToHex(s.txhash)
}
_, err := QueryStorageFromLocalDB(s.localdb, key)
if err != types.ErrNotFound {
return nil, ety.ErrKeyExisted
}
payload.Key = key
stg := &ety.Storage{Value: &ety.Storage_HashStorage{HashStorage: payload}, Ty: ety.TyHashStorageAction}
log := &types.ReceiptLog{Ty: ety.TyHashStorageLog, Log: types.Encode(stg)}
logs = append(logs, log) logs = append(logs, log)
kv := s.GetKVSet(payload) receipt := &types.Receipt{Ty: types.ExecOk, KV: kvs, Logs: logs}
receipt := &types.Receipt{Ty: types.ExecOk, KV: kv, Logs: logs}
return receipt, nil return receipt, nil
} }
func (s *StorageAction) LinkStorage(payload proto.Message) (*types.Receipt, error) { func (s *StorageAction) LinkStorage(payload *ety.LinkNotaryStorage) (*types.Receipt, error) {
var logs []*types.ReceiptLog var logs []*types.ReceiptLog
log := &types.ReceiptLog{Ty: storagetypes.TyLinkStorageLog} var kvs []*types.KeyValue
key := payload.Key
if key == "" {
key = common.ToHex(s.txhash)
}
payload.Key = key
_, err := QueryStorageFromLocalDB(s.localdb, key)
if err != types.ErrNotFound {
return nil, ety.ErrKeyExisted
}
stg := &ety.Storage{Value: &ety.Storage_LinkStorage{LinkStorage: payload}, Ty: ety.TyLinkStorageAction}
log := &types.ReceiptLog{Ty: ety.TyLinkStorageLog, Log: types.Encode(stg)}
logs = append(logs, log) logs = append(logs, log)
kv := s.GetKVSet(payload) receipt := &types.Receipt{Ty: types.ExecOk, KV: kvs, Logs: logs}
receipt := &types.Receipt{Ty: types.ExecOk, KV: kv, Logs: logs}
return receipt, nil return receipt, nil
} }
func (s *StorageAction) EncryptStorage(payload proto.Message) (*types.Receipt, error) { func (s *StorageAction) EncryptStorage(payload *ety.EncryptNotaryStorage) (*types.Receipt, error) {
var logs []*types.ReceiptLog var logs []*types.ReceiptLog
log := &types.ReceiptLog{Ty: storagetypes.TyEncryptStorageLog} var kvs []*types.KeyValue
key := payload.Key
if key == "" {
key = common.ToHex(s.txhash)
}
payload.Key = key
_, err := QueryStorageFromLocalDB(s.localdb, key)
if err != types.ErrNotFound {
return nil, ety.ErrKeyExisted
}
stg := &ety.Storage{Value: &ety.Storage_EncryptStorage{EncryptStorage: payload}, Ty: ety.TyEncryptStorageAction}
log := &types.ReceiptLog{Ty: ety.TyEncryptStorageLog, Log: types.Encode(stg)}
logs = append(logs, log) logs = append(logs, log)
kv := s.GetKVSet(payload) receipt := &types.Receipt{Ty: types.ExecOk, KV: kvs, Logs: logs}
receipt := &types.Receipt{Ty: types.ExecOk, KV: kv, Logs: logs}
return receipt, nil return receipt, nil
} }
func (s *StorageAction) EncryptShareStorage(payload proto.Message) (*types.Receipt, error) { func (s *StorageAction) EncryptShareStorage(payload *ety.EncryptShareNotaryStorage) (*types.Receipt, error) {
var logs []*types.ReceiptLog var logs []*types.ReceiptLog
log := &types.ReceiptLog{Ty: storagetypes.TyEncryptShareStorageLog} var kvs []*types.KeyValue
key := payload.Key
if key == "" {
key = common.ToHex(s.txhash)
}
payload.Key = key
_, err := QueryStorageFromLocalDB(s.localdb, key)
if err != types.ErrNotFound {
return nil, ety.ErrKeyExisted
}
stg := &ety.Storage{Value: &ety.Storage_EncryptShareStorage{EncryptShareStorage: payload}, Ty: ety.TyEncryptStorageAction}
log := &types.ReceiptLog{Ty: ety.TyEncryptShareStorageLog, Log: types.Encode(stg)}
logs = append(logs, log) logs = append(logs, log)
kv := s.GetKVSet(payload) receipt := &types.Receipt{Ty: types.ExecOk, KV: kvs, Logs: logs}
receipt := &types.Receipt{Ty: types.ExecOk, KV: kv, Logs: logs}
return receipt, nil return receipt, nil
} }
func QueryStorageByTxHash(db dbm.KV, txhash string) (*storagetypes.Storage, error) { func QueryStorageByTxHash(db dbm.KV, txhash string) (*ety.Storage, error) {
data, err := db.Get(Key(txhash)) data, err := db.Get(Key(txhash))
if err != nil { if err != nil {
elog.Debug("QueryStorage", "get", err) elog.Debug("QueryStorage", "get", err)
return nil, err return nil, err
} }
var storage storagetypes.Storage var storage ety.Storage
//decode //decode
err = types.Decode(data, &storage) err = types.Decode(data, &storage)
if err != nil { if err != nil {
...@@ -86,19 +147,24 @@ func QueryStorageByTxHash(db dbm.KV, txhash string) (*storagetypes.Storage, erro ...@@ -86,19 +147,24 @@ func QueryStorageByTxHash(db dbm.KV, txhash string) (*storagetypes.Storage, erro
} }
return &storage, nil return &storage, nil
} }
func QueryStorage(db dbm.KV, in *storagetypes.QueryStorage) (types.Message, error) { func QueryStorage(statedb, localdb dbm.KV, txHash string) (*ety.Storage, error) {
if in.TxHash == "" { if txHash == "" {
return nil, fmt.Errorf("txhash can't equail nil") return nil, fmt.Errorf("txhash can't equail nil")
} }
return QueryStorageByTxHash(db, in.TxHash) //先去localdb中查询,如果没有,则再去状态数据库中查询
storage, err := QueryStorageFromLocalDB(localdb, txHash)
if err != nil {
return QueryStorageByTxHash(statedb, txHash)
}
return storage, nil
} }
func BatchQueryStorage(db dbm.KV, in *storagetypes.BatchQueryStorage) (types.Message, error) { func BatchQueryStorage(statedb, localdb dbm.KV, in *ety.BatchQueryStorage) (types.Message, error) {
if len(in.TxHashs) > 10 { if len(in.TxHashs) > 10 {
return nil, fmt.Errorf("The number of batch queries is too large! the maximux is %d,but current num %d", 10, len(in.TxHashs)) return nil, fmt.Errorf("The number of batch queries is too large! the maximux is %d,but current num %d", 10, len(in.TxHashs))
} }
var storage storagetypes.BatchReplyStorage var storage ety.BatchReplyStorage
for _, txhash := range in.TxHashs { for _, txhash := range in.TxHashs {
msg, err := QueryStorageByTxHash(db, txhash) msg, err := QueryStorage(statedb, localdb, txhash)
if err != nil { if err != nil {
return msg, err return msg, err
} }
...@@ -106,3 +172,27 @@ func BatchQueryStorage(db dbm.KV, in *storagetypes.BatchQueryStorage) (types.Mes ...@@ -106,3 +172,27 @@ func BatchQueryStorage(db dbm.KV, in *storagetypes.BatchQueryStorage) (types.Mes
} }
return &storage, nil return &storage, nil
} }
//因为table表不支持嵌套多种数据存储结构,改成手动KV存储
func QueryStorageFromLocalDB(localdb dbm.KV, key string) (*ety.Storage, error) {
data, err := localdb.Get(getLocalDBKey(key))
if err != nil {
return nil, err
}
var storage ety.Storage
err = types.Decode(data, &storage)
if err != nil {
return nil, err
}
return &storage, nil
}
//func QueryStorageFromLocalDB(localdb dbm.KV, key string) (*ety.Storage, error) {
// storageTable := NewStorageTable(localdb)
// row, err := storageTable.GetData([]byte(key))
// if err != nil {
// return nil, err
// }
// fmt.Println(row)
// return row.Data.(*ety.Storage), nil
//}
...@@ -9,6 +9,7 @@ message Storage { ...@@ -9,6 +9,7 @@ message Storage {
EncryptNotaryStorage encryptStorage = 4; EncryptNotaryStorage encryptStorage = 4;
EncryptShareNotaryStorage encryptShareStorage = 5; EncryptShareNotaryStorage encryptShareStorage = 5;
} }
int32 ty = 6;
} }
message StorageAction { message StorageAction {
...@@ -23,8 +24,12 @@ message StorageAction { ...@@ -23,8 +24,12 @@ message StorageAction {
} }
// 内容存证模型 // 内容存证模型
message ContentOnlyNotaryStorage { message ContentOnlyNotaryStorage {
// Op 0表示创建 1表示追加add
int32 op = 1;
//长度需要小于512k //长度需要小于512k
bytes content = 1; bytes content = 2;
//自定义的主键,可以为空,如果没传,则用txhash为key
string key = 3;
} }
//哈希存证模型,推荐使用sha256哈希,限制256位得摘要值 //哈希存证模型,推荐使用sha256哈希,限制256位得摘要值
...@@ -32,6 +37,8 @@ message HashOnlyNotaryStorage { ...@@ -32,6 +37,8 @@ message HashOnlyNotaryStorage {
//长度固定为32字节 //长度固定为32字节
bytes hash = 1; bytes hash = 1;
//自定义的主键,可以为空,如果没传,则用txhash为key
string key = 2;
} }
// 链接存证模型 // 链接存证模型
...@@ -40,6 +47,8 @@ message LinkNotaryStorage { ...@@ -40,6 +47,8 @@ message LinkNotaryStorage {
bytes link = 1; bytes link = 1;
//源文件得hash值,推荐使用sha256哈希,限制256位得摘要值 //源文件得hash值,推荐使用sha256哈希,限制256位得摘要值
bytes hash = 2; bytes hash = 2;
//自定义的主键,可以为空,如果没传,则用txhash为key
string key = 3;
} }
// 隐私存证模型,如果一个文件需要存证,且不公开内容,可以选择将源文件通过对称加密算法加密后上链 // 隐私存证模型,如果一个文件需要存证,且不公开内容,可以选择将源文件通过对称加密算法加密后上链
...@@ -50,30 +59,20 @@ message EncryptNotaryStorage { ...@@ -50,30 +59,20 @@ message EncryptNotaryStorage {
bytes encryptContent = 2; bytes encryptContent = 2;
//加密iv,通过AES进行加密时制定随机生成的iv,解密时需要使用该值 //加密iv,通过AES进行加密时制定随机生成的iv,解密时需要使用该值
bytes nonce = 3; bytes nonce = 3;
} //自定义的主键,可以为空,如果没传,则用txhash为key
// 隐私存证模型 string key = 4;
message EncryptContentOnlyNotaryStorage {
//存证内容的hash值,推荐使用sha256哈希,限制256位得摘要值
// bytes contentHash = 1;
//源文件得密文。
bytes encryptContent = 1;
//加密iv,通过AES进行加密时制定随机生成的iv,解密时需要使用该值
bytes nonce = 2;
} }
// 分享隐私存证模型,需要完备的sdk或者相应的密钥库支持 // 分享隐私存证模型,需要完备的sdk或者相应的密钥库支持
message EncryptShareNotaryStorage { message EncryptShareNotaryStorage {
//存证明文内容的hash值,推荐使用sha256哈希,限制256位得摘要值 //存证明文内容的hash值,推荐使用sha256哈希,限制256位得摘要值
bytes contentHash = 1; bytes contentHash = 1;
//源文件得密文。 //源文件得密文。,用公钥地址加密
bytes encryptContent = 2; bytes encryptContent = 2;
//密钥的kdf推导路径。密钥tree父节点根据该路径可以推导出私钥key //公钥
bytes keyName = 3; bytes pubKey = 3;
//加密key的wrap key。加密key随机生成,对明文进行加密,该key有私密key进行key wrap后公开。 //自定义的主键,可以为空,如果没传,则用txhash为key
//使用时,通过私密key对wrap key解密得到加密key对密文进行解密。 string key = 4;
bytes keyWrap = 4;
//加密iv,通过AES进行加密时制定随机生成的iv,解密时需要使用该值
bytes nonce = 5;
} }
service storage {} service storage {}
......
package types
import "fmt"
// some errors definition
var (
ErrKeyExisted = fmt.Errorf("%s", "The key has already existed!")
ErrStorageType = fmt.Errorf("%s", "The key has used storage another type!")
)
...@@ -41,6 +41,11 @@ const ( ...@@ -41,6 +41,11 @@ const (
TyEncryptShareStorageLog TyEncryptShareStorageLog
) )
const (
OpCreate = int32(iota)
OpAdd
)
var ( var (
//StorageX 执行器名称定义 //StorageX 执行器名称定义
StorageX = "storage" StorageX = "storage"
...@@ -54,11 +59,11 @@ var ( ...@@ -54,11 +59,11 @@ var (
} }
//定义log的id和具体log类型及名称,填入具体自定义log类型 //定义log的id和具体log类型及名称,填入具体自定义log类型
logMap = map[int64]*types.LogInfo{ logMap = map[int64]*types.LogInfo{
TyContentStorageLog: {Ty: reflect.TypeOf(ReceiptStorage{}), Name: "LogContentStorage"}, TyContentStorageLog: {Ty: reflect.TypeOf(Storage{}), Name: "LogContentStorage"},
TyHashStorageLog: {Ty: reflect.TypeOf(ReceiptStorage{}), Name: "LogHashStorage"}, TyHashStorageLog: {Ty: reflect.TypeOf(Storage{}), Name: "LogHashStorage"},
TyLinkStorageLog: {Ty: reflect.TypeOf(ReceiptStorage{}), Name: "LogLinkStorage"}, TyLinkStorageLog: {Ty: reflect.TypeOf(Storage{}), Name: "LogLinkStorage"},
TyEncryptStorageLog: {Ty: reflect.TypeOf(ReceiptStorage{}), Name: "LogEncryptStorage"}, TyEncryptStorageLog: {Ty: reflect.TypeOf(Storage{}), Name: "LogEncryptStorage"},
TyEncryptShareStorageLog: {Ty: reflect.TypeOf(ReceiptStorage{}), Name: "LogEncryptShareStorage"}, TyEncryptShareStorageLog: {Ty: reflect.TypeOf(Storage{}), Name: "LogEncryptShareStorage"},
} }
) )
......
...@@ -6,10 +6,9 @@ package types ...@@ -6,10 +6,9 @@ package types
import ( import (
context "context" context "context"
fmt "fmt" fmt "fmt"
math "math"
proto "github.com/golang/protobuf/proto" proto "github.com/golang/protobuf/proto"
grpc "google.golang.org/grpc" grpc "google.golang.org/grpc"
math "math"
) )
// Reference imports to suppress errors if they are not otherwise used. // Reference imports to suppress errors if they are not otherwise used.
...@@ -32,6 +31,7 @@ type Storage struct { ...@@ -32,6 +31,7 @@ type Storage struct {
// *Storage_EncryptStorage // *Storage_EncryptStorage
// *Storage_EncryptShareStorage // *Storage_EncryptShareStorage
Value isStorage_Value `protobuf_oneof:"value"` Value isStorage_Value `protobuf_oneof:"value"`
Ty int32 `protobuf:"varint,6,opt,name=ty,proto3" json:"ty,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"` XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"` XXX_sizecache int32 `json:"-"`
...@@ -138,6 +138,13 @@ func (m *Storage) GetEncryptShareStorage() *EncryptShareNotaryStorage { ...@@ -138,6 +138,13 @@ func (m *Storage) GetEncryptShareStorage() *EncryptShareNotaryStorage {
return nil return nil
} }
func (m *Storage) GetTy() int32 {
if m != nil {
return m.Ty
}
return 0
}
// XXX_OneofWrappers is for the internal use of the proto package. // XXX_OneofWrappers is for the internal use of the proto package.
func (*Storage) XXX_OneofWrappers() []interface{} { func (*Storage) XXX_OneofWrappers() []interface{} {
return []interface{}{ return []interface{}{
...@@ -284,8 +291,12 @@ func (*StorageAction) XXX_OneofWrappers() []interface{} { ...@@ -284,8 +291,12 @@ func (*StorageAction) XXX_OneofWrappers() []interface{} {
// 内容存证模型 // 内容存证模型
type ContentOnlyNotaryStorage struct { type ContentOnlyNotaryStorage struct {
// Op 0表示创建 1表示追加add
Op int32 `protobuf:"varint,1,opt,name=op,proto3" json:"op,omitempty"`
//长度需要小于512k //长度需要小于512k
Content []byte `protobuf:"bytes,1,opt,name=content,proto3" json:"content,omitempty"` Content []byte `protobuf:"bytes,2,opt,name=content,proto3" json:"content,omitempty"`
//自定义的主键,可以为空,如果没传,则用txhash为key
Key string `protobuf:"bytes,3,opt,name=key,proto3" json:"key,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"` XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"` XXX_sizecache int32 `json:"-"`
...@@ -316,6 +327,13 @@ func (m *ContentOnlyNotaryStorage) XXX_DiscardUnknown() { ...@@ -316,6 +327,13 @@ func (m *ContentOnlyNotaryStorage) XXX_DiscardUnknown() {
var xxx_messageInfo_ContentOnlyNotaryStorage proto.InternalMessageInfo var xxx_messageInfo_ContentOnlyNotaryStorage proto.InternalMessageInfo
func (m *ContentOnlyNotaryStorage) GetOp() int32 {
if m != nil {
return m.Op
}
return 0
}
func (m *ContentOnlyNotaryStorage) GetContent() []byte { func (m *ContentOnlyNotaryStorage) GetContent() []byte {
if m != nil { if m != nil {
return m.Content return m.Content
...@@ -323,10 +341,19 @@ func (m *ContentOnlyNotaryStorage) GetContent() []byte { ...@@ -323,10 +341,19 @@ func (m *ContentOnlyNotaryStorage) GetContent() []byte {
return nil return nil
} }
func (m *ContentOnlyNotaryStorage) GetKey() string {
if m != nil {
return m.Key
}
return ""
}
//哈希存证模型,推荐使用sha256哈希,限制256位得摘要值 //哈希存证模型,推荐使用sha256哈希,限制256位得摘要值
type HashOnlyNotaryStorage struct { type HashOnlyNotaryStorage struct {
//长度固定为32字节 //长度固定为32字节
Hash []byte `protobuf:"bytes,1,opt,name=hash,proto3" json:"hash,omitempty"` Hash []byte `protobuf:"bytes,1,opt,name=hash,proto3" json:"hash,omitempty"`
//自定义的主键,可以为空,如果没传,则用txhash为key
Key string `protobuf:"bytes,2,opt,name=key,proto3" json:"key,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"` XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"` XXX_sizecache int32 `json:"-"`
...@@ -364,12 +391,21 @@ func (m *HashOnlyNotaryStorage) GetHash() []byte { ...@@ -364,12 +391,21 @@ func (m *HashOnlyNotaryStorage) GetHash() []byte {
return nil return nil
} }
func (m *HashOnlyNotaryStorage) GetKey() string {
if m != nil {
return m.Key
}
return ""
}
// 链接存证模型 // 链接存证模型
type LinkNotaryStorage struct { type LinkNotaryStorage struct {
//存证内容的链接,可以写入URL,或者其他可用于定位源文件得线索. //存证内容的链接,可以写入URL,或者其他可用于定位源文件得线索.
Link []byte `protobuf:"bytes,1,opt,name=link,proto3" json:"link,omitempty"` Link []byte `protobuf:"bytes,1,opt,name=link,proto3" json:"link,omitempty"`
//源文件得hash值,推荐使用sha256哈希,限制256位得摘要值 //源文件得hash值,推荐使用sha256哈希,限制256位得摘要值
Hash []byte `protobuf:"bytes,2,opt,name=hash,proto3" json:"hash,omitempty"` Hash []byte `protobuf:"bytes,2,opt,name=hash,proto3" json:"hash,omitempty"`
//自定义的主键,可以为空,如果没传,则用txhash为key
Key string `protobuf:"bytes,3,opt,name=key,proto3" json:"key,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"` XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"` XXX_sizecache int32 `json:"-"`
...@@ -414,6 +450,13 @@ func (m *LinkNotaryStorage) GetHash() []byte { ...@@ -414,6 +450,13 @@ func (m *LinkNotaryStorage) GetHash() []byte {
return nil return nil
} }
func (m *LinkNotaryStorage) GetKey() string {
if m != nil {
return m.Key
}
return ""
}
// 隐私存证模型,如果一个文件需要存证,且不公开内容,可以选择将源文件通过对称加密算法加密后上链 // 隐私存证模型,如果一个文件需要存证,且不公开内容,可以选择将源文件通过对称加密算法加密后上链
type EncryptNotaryStorage struct { type EncryptNotaryStorage struct {
//存证明文内容的hash值,推荐使用sha256哈希,限制256位得摘要值 //存证明文内容的hash值,推荐使用sha256哈希,限制256位得摘要值
...@@ -422,6 +465,8 @@ type EncryptNotaryStorage struct { ...@@ -422,6 +465,8 @@ type EncryptNotaryStorage struct {
EncryptContent []byte `protobuf:"bytes,2,opt,name=encryptContent,proto3" json:"encryptContent,omitempty"` EncryptContent []byte `protobuf:"bytes,2,opt,name=encryptContent,proto3" json:"encryptContent,omitempty"`
//加密iv,通过AES进行加密时制定随机生成的iv,解密时需要使用该值 //加密iv,通过AES进行加密时制定随机生成的iv,解密时需要使用该值
Nonce []byte `protobuf:"bytes,3,opt,name=nonce,proto3" json:"nonce,omitempty"` Nonce []byte `protobuf:"bytes,3,opt,name=nonce,proto3" json:"nonce,omitempty"`
//自定义的主键,可以为空,如果没传,则用txhash为key
Key string `protobuf:"bytes,4,opt,name=key,proto3" json:"key,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"` XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"` XXX_sizecache int32 `json:"-"`
...@@ -473,71 +518,23 @@ func (m *EncryptNotaryStorage) GetNonce() []byte { ...@@ -473,71 +518,23 @@ func (m *EncryptNotaryStorage) GetNonce() []byte {
return nil return nil
} }
// 隐私存证模型 func (m *EncryptNotaryStorage) GetKey() string {
type EncryptContentOnlyNotaryStorage struct {
//存证内容的hash值,推荐使用sha256哈希,限制256位得摘要值
// bytes contentHash = 1;
//源文件得密文。
EncryptContent []byte `protobuf:"bytes,1,opt,name=encryptContent,proto3" json:"encryptContent,omitempty"`
//加密iv,通过AES进行加密时制定随机生成的iv,解密时需要使用该值
Nonce []byte `protobuf:"bytes,2,opt,name=nonce,proto3" json:"nonce,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *EncryptContentOnlyNotaryStorage) Reset() { *m = EncryptContentOnlyNotaryStorage{} }
func (m *EncryptContentOnlyNotaryStorage) String() string { return proto.CompactTextString(m) }
func (*EncryptContentOnlyNotaryStorage) ProtoMessage() {}
func (*EncryptContentOnlyNotaryStorage) Descriptor() ([]byte, []int) {
return fileDescriptor_0d2c4ccf1453ffdb, []int{6}
}
func (m *EncryptContentOnlyNotaryStorage) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_EncryptContentOnlyNotaryStorage.Unmarshal(m, b)
}
func (m *EncryptContentOnlyNotaryStorage) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_EncryptContentOnlyNotaryStorage.Marshal(b, m, deterministic)
}
func (m *EncryptContentOnlyNotaryStorage) XXX_Merge(src proto.Message) {
xxx_messageInfo_EncryptContentOnlyNotaryStorage.Merge(m, src)
}
func (m *EncryptContentOnlyNotaryStorage) XXX_Size() int {
return xxx_messageInfo_EncryptContentOnlyNotaryStorage.Size(m)
}
func (m *EncryptContentOnlyNotaryStorage) XXX_DiscardUnknown() {
xxx_messageInfo_EncryptContentOnlyNotaryStorage.DiscardUnknown(m)
}
var xxx_messageInfo_EncryptContentOnlyNotaryStorage proto.InternalMessageInfo
func (m *EncryptContentOnlyNotaryStorage) GetEncryptContent() []byte {
if m != nil { if m != nil {
return m.EncryptContent return m.Key
} }
return nil return ""
}
func (m *EncryptContentOnlyNotaryStorage) GetNonce() []byte {
if m != nil {
return m.Nonce
}
return nil
} }
// 分享隐私存证模型,需要完备的sdk或者相应的密钥库支持 // 分享隐私存证模型,需要完备的sdk或者相应的密钥库支持
type EncryptShareNotaryStorage struct { type EncryptShareNotaryStorage struct {
//存证明文内容的hash值,推荐使用sha256哈希,限制256位得摘要值 //存证明文内容的hash值,推荐使用sha256哈希,限制256位得摘要值
ContentHash []byte `protobuf:"bytes,1,opt,name=contentHash,proto3" json:"contentHash,omitempty"` ContentHash []byte `protobuf:"bytes,1,opt,name=contentHash,proto3" json:"contentHash,omitempty"`
//源文件得密文。 //源文件得密文。,用公钥地址加密
EncryptContent []byte `protobuf:"bytes,2,opt,name=encryptContent,proto3" json:"encryptContent,omitempty"` EncryptContent []byte `protobuf:"bytes,2,opt,name=encryptContent,proto3" json:"encryptContent,omitempty"`
//密钥的kdf推导路径。密钥tree父节点根据该路径可以推导出私钥key //公钥
KeyName []byte `protobuf:"bytes,3,opt,name=keyName,proto3" json:"keyName,omitempty"` PubKey []byte `protobuf:"bytes,3,opt,name=pubKey,proto3" json:"pubKey,omitempty"`
//加密key的wrap key。加密key随机生成,对明文进行加密,该key有私密key进行key wrap后公开。 //自定义的主键,可以为空,如果没传,则用txhash为key
//使用时,通过私密key对wrap key解密得到加密key对密文进行解密。 Key string `protobuf:"bytes,4,opt,name=key,proto3" json:"key,omitempty"`
KeyWrap []byte `protobuf:"bytes,4,opt,name=keyWrap,proto3" json:"keyWrap,omitempty"`
//加密iv,通过AES进行加密时制定随机生成的iv,解密时需要使用该值
Nonce []byte `protobuf:"bytes,5,opt,name=nonce,proto3" json:"nonce,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"` XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"` XXX_sizecache int32 `json:"-"`
...@@ -547,7 +544,7 @@ func (m *EncryptShareNotaryStorage) Reset() { *m = EncryptShareNotarySto ...@@ -547,7 +544,7 @@ func (m *EncryptShareNotaryStorage) Reset() { *m = EncryptShareNotarySto
func (m *EncryptShareNotaryStorage) String() string { return proto.CompactTextString(m) } func (m *EncryptShareNotaryStorage) String() string { return proto.CompactTextString(m) }
func (*EncryptShareNotaryStorage) ProtoMessage() {} func (*EncryptShareNotaryStorage) ProtoMessage() {}
func (*EncryptShareNotaryStorage) Descriptor() ([]byte, []int) { func (*EncryptShareNotaryStorage) Descriptor() ([]byte, []int) {
return fileDescriptor_0d2c4ccf1453ffdb, []int{7} return fileDescriptor_0d2c4ccf1453ffdb, []int{6}
} }
func (m *EncryptShareNotaryStorage) XXX_Unmarshal(b []byte) error { func (m *EncryptShareNotaryStorage) XXX_Unmarshal(b []byte) error {
...@@ -582,25 +579,18 @@ func (m *EncryptShareNotaryStorage) GetEncryptContent() []byte { ...@@ -582,25 +579,18 @@ func (m *EncryptShareNotaryStorage) GetEncryptContent() []byte {
return nil return nil
} }
func (m *EncryptShareNotaryStorage) GetKeyName() []byte { func (m *EncryptShareNotaryStorage) GetPubKey() []byte {
if m != nil { if m != nil {
return m.KeyName return m.PubKey
} }
return nil return nil
} }
func (m *EncryptShareNotaryStorage) GetKeyWrap() []byte { func (m *EncryptShareNotaryStorage) GetKey() string {
if m != nil { if m != nil {
return m.KeyWrap return m.Key
}
return nil
}
func (m *EncryptShareNotaryStorage) GetNonce() []byte {
if m != nil {
return m.Nonce
} }
return nil return ""
} }
//根据txhash去状态数据库中查询存储内容 //根据txhash去状态数据库中查询存储内容
...@@ -615,7 +605,7 @@ func (m *QueryStorage) Reset() { *m = QueryStorage{} } ...@@ -615,7 +605,7 @@ func (m *QueryStorage) Reset() { *m = QueryStorage{} }
func (m *QueryStorage) String() string { return proto.CompactTextString(m) } func (m *QueryStorage) String() string { return proto.CompactTextString(m) }
func (*QueryStorage) ProtoMessage() {} func (*QueryStorage) ProtoMessage() {}
func (*QueryStorage) Descriptor() ([]byte, []int) { func (*QueryStorage) Descriptor() ([]byte, []int) {
return fileDescriptor_0d2c4ccf1453ffdb, []int{8} return fileDescriptor_0d2c4ccf1453ffdb, []int{7}
} }
func (m *QueryStorage) XXX_Unmarshal(b []byte) error { func (m *QueryStorage) XXX_Unmarshal(b []byte) error {
...@@ -655,7 +645,7 @@ func (m *BatchQueryStorage) Reset() { *m = BatchQueryStorage{} } ...@@ -655,7 +645,7 @@ func (m *BatchQueryStorage) Reset() { *m = BatchQueryStorage{} }
func (m *BatchQueryStorage) String() string { return proto.CompactTextString(m) } func (m *BatchQueryStorage) String() string { return proto.CompactTextString(m) }
func (*BatchQueryStorage) ProtoMessage() {} func (*BatchQueryStorage) ProtoMessage() {}
func (*BatchQueryStorage) Descriptor() ([]byte, []int) { func (*BatchQueryStorage) Descriptor() ([]byte, []int) {
return fileDescriptor_0d2c4ccf1453ffdb, []int{9} return fileDescriptor_0d2c4ccf1453ffdb, []int{8}
} }
func (m *BatchQueryStorage) XXX_Unmarshal(b []byte) error { func (m *BatchQueryStorage) XXX_Unmarshal(b []byte) error {
...@@ -694,7 +684,7 @@ func (m *BatchReplyStorage) Reset() { *m = BatchReplyStorage{} } ...@@ -694,7 +684,7 @@ func (m *BatchReplyStorage) Reset() { *m = BatchReplyStorage{} }
func (m *BatchReplyStorage) String() string { return proto.CompactTextString(m) } func (m *BatchReplyStorage) String() string { return proto.CompactTextString(m) }
func (*BatchReplyStorage) ProtoMessage() {} func (*BatchReplyStorage) ProtoMessage() {}
func (*BatchReplyStorage) Descriptor() ([]byte, []int) { func (*BatchReplyStorage) Descriptor() ([]byte, []int) {
return fileDescriptor_0d2c4ccf1453ffdb, []int{10} return fileDescriptor_0d2c4ccf1453ffdb, []int{9}
} }
func (m *BatchReplyStorage) XXX_Unmarshal(b []byte) error { func (m *BatchReplyStorage) XXX_Unmarshal(b []byte) error {
...@@ -732,7 +722,7 @@ func (m *ReceiptStorage) Reset() { *m = ReceiptStorage{} } ...@@ -732,7 +722,7 @@ func (m *ReceiptStorage) Reset() { *m = ReceiptStorage{} }
func (m *ReceiptStorage) String() string { return proto.CompactTextString(m) } func (m *ReceiptStorage) String() string { return proto.CompactTextString(m) }
func (*ReceiptStorage) ProtoMessage() {} func (*ReceiptStorage) ProtoMessage() {}
func (*ReceiptStorage) Descriptor() ([]byte, []int) { func (*ReceiptStorage) Descriptor() ([]byte, []int) {
return fileDescriptor_0d2c4ccf1453ffdb, []int{11} return fileDescriptor_0d2c4ccf1453ffdb, []int{10}
} }
func (m *ReceiptStorage) XXX_Unmarshal(b []byte) error { func (m *ReceiptStorage) XXX_Unmarshal(b []byte) error {
...@@ -760,7 +750,6 @@ func init() { ...@@ -760,7 +750,6 @@ func init() {
proto.RegisterType((*HashOnlyNotaryStorage)(nil), "types.HashOnlyNotaryStorage") proto.RegisterType((*HashOnlyNotaryStorage)(nil), "types.HashOnlyNotaryStorage")
proto.RegisterType((*LinkNotaryStorage)(nil), "types.LinkNotaryStorage") proto.RegisterType((*LinkNotaryStorage)(nil), "types.LinkNotaryStorage")
proto.RegisterType((*EncryptNotaryStorage)(nil), "types.EncryptNotaryStorage") proto.RegisterType((*EncryptNotaryStorage)(nil), "types.EncryptNotaryStorage")
proto.RegisterType((*EncryptContentOnlyNotaryStorage)(nil), "types.EncryptContentOnlyNotaryStorage")
proto.RegisterType((*EncryptShareNotaryStorage)(nil), "types.EncryptShareNotaryStorage") proto.RegisterType((*EncryptShareNotaryStorage)(nil), "types.EncryptShareNotaryStorage")
proto.RegisterType((*QueryStorage)(nil), "types.QueryStorage") proto.RegisterType((*QueryStorage)(nil), "types.QueryStorage")
proto.RegisterType((*BatchQueryStorage)(nil), "types.BatchQueryStorage") proto.RegisterType((*BatchQueryStorage)(nil), "types.BatchQueryStorage")
...@@ -773,37 +762,37 @@ func init() { ...@@ -773,37 +762,37 @@ func init() {
} }
var fileDescriptor_0d2c4ccf1453ffdb = []byte{ var fileDescriptor_0d2c4ccf1453ffdb = []byte{
// 471 bytes of a gzipped FileDescriptorProto // 470 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x54, 0xcf, 0x8b, 0xd3, 0x40, 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x54, 0x4d, 0x8b, 0xd4, 0x40,
0x14, 0x36, 0xe9, 0xa6, 0xb1, 0x2f, 0xdd, 0xe0, 0x8e, 0xab, 0x8c, 0x28, 0x6c, 0x98, 0xc3, 0x52, 0x10, 0x35, 0xc9, 0x64, 0xe2, 0x54, 0xb2, 0x61, 0xb7, 0x5d, 0x97, 0x88, 0x82, 0x21, 0x87, 0x65,
0x14, 0x7b, 0xa8, 0xde, 0x14, 0xd4, 0x95, 0x42, 0x05, 0x59, 0x71, 0x14, 0x3c, 0xca, 0x18, 0x06, 0x10, 0x9c, 0xc3, 0x78, 0x55, 0xd4, 0x5d, 0x16, 0x46, 0xfc, 0xc2, 0x56, 0xbc, 0x67, 0x43, 0x63,
0x53, 0x5a, 0x27, 0x21, 0x99, 0x5d, 0xcc, 0x7f, 0xe1, 0x7f, 0xe2, 0xff, 0xe7, 0x49, 0x32, 0xf3, 0x86, 0x09, 0xdd, 0x21, 0xe9, 0x11, 0xf3, 0x0f, 0xc4, 0x8b, 0xfe, 0x64, 0x49, 0xa7, 0x3a, 0x1f,
0x26, 0x4d, 0x9b, 0xd6, 0x93, 0x78, 0xf2, 0x96, 0xf7, 0xbe, 0xef, 0x7d, 0xef, 0xc7, 0x97, 0x04, 0x93, 0xec, 0x4d, 0xf0, 0xb2, 0xb7, 0xae, 0xaa, 0xf7, 0x5e, 0xaa, 0x5e, 0x75, 0x1a, 0x8e, 0x4a,
0x8e, 0x2b, 0x9d, 0x97, 0xe2, 0xab, 0x9c, 0x16, 0x65, 0xae, 0x73, 0x12, 0xe8, 0xba, 0x90, 0x15, 0x29, 0x8a, 0xf8, 0x1b, 0x5b, 0xe5, 0x85, 0x90, 0x82, 0xd8, 0xb2, 0xca, 0x59, 0x19, 0xfd, 0xb2,
0xfb, 0xe5, 0x43, 0xf8, 0xc1, 0x02, 0xe4, 0x0d, 0xc4, 0x69, 0xae, 0xb4, 0x54, 0x1a, 0x33, 0xd4, 0xc0, 0xf9, 0xdc, 0x14, 0xc8, 0x1b, 0xf0, 0x13, 0xc1, 0x25, 0xe3, 0x12, 0x33, 0x81, 0x11, 0x1a,
0x4b, 0xbc, 0x49, 0x34, 0x3b, 0x9b, 0x1a, 0xee, 0xf4, 0xb5, 0x05, 0xdf, 0xa9, 0x75, 0x7d, 0x99, 0x4b, 0x77, 0xfd, 0x78, 0xa5, 0xb0, 0xab, 0xcb, 0xa6, 0xf8, 0x91, 0x67, 0xd5, 0x07, 0x21, 0xe3,
0x6b, 0x51, 0xd6, 0x48, 0x5b, 0xdc, 0xe0, 0x3b, 0x85, 0xe4, 0x25, 0x44, 0x99, 0xa8, 0x32, 0xa7, 0xa2, 0x42, 0xd8, 0xe6, 0x0e, 0x3d, 0x20, 0x92, 0x57, 0xe0, 0xa6, 0x71, 0x99, 0x6a, 0x1d, 0x53,
0xe3, 0x1b, 0x9d, 0x07, 0xa8, 0xb3, 0x10, 0x55, 0xb6, 0x4f, 0xa4, 0x5b, 0x42, 0x9e, 0x43, 0xb4, 0xe9, 0x3c, 0x42, 0x9d, 0x4d, 0x5c, 0xa6, 0x53, 0x22, 0x7d, 0x0a, 0x79, 0x0e, 0x6e, 0xb6, 0xe5,
0x5e, 0xaa, 0x95, 0x53, 0x18, 0x18, 0x05, 0x8a, 0x0a, 0x6f, 0x97, 0x6a, 0xd5, 0xab, 0xee, 0xd0, 0x3b, 0xad, 0x60, 0x29, 0x85, 0x00, 0x15, 0xde, 0x6d, 0xf9, 0x6e, 0xc4, 0xee, 0xc1, 0xc9, 0x15,
0xc9, 0x1c, 0x62, 0xa9, 0xd2, 0xb2, 0x2e, 0xda, 0x55, 0x8e, 0x8c, 0xc0, 0x7d, 0x14, 0x98, 0x5b, 0xf8, 0x8c, 0x27, 0x45, 0x95, 0xb7, 0xa3, 0xcc, 0x94, 0xc0, 0x43, 0x14, 0xb8, 0x6a, 0x8a, 0xa3,
0xb0, 0xb7, 0xc6, 0x76, 0x11, 0xf9, 0x08, 0xb7, 0x5d, 0x26, 0x13, 0xa5, 0x74, 0x5a, 0x81, 0xd1, 0x31, 0x86, 0x24, 0xf2, 0x05, 0xee, 0xe9, 0x4c, 0x1a, 0x17, 0x4c, 0x6b, 0xd9, 0x4a, 0x2b, 0x1c,
0x4a, 0xb6, 0xb5, 0x0c, 0x63, 0x57, 0x70, 0x5f, 0xf9, 0x45, 0x08, 0xc1, 0xb5, 0x58, 0x5f, 0x49, 0x6a, 0x29, 0xc4, 0xa1, 0xe0, 0x14, 0x9d, 0xf8, 0x60, 0xca, 0x2a, 0x98, 0x87, 0xc6, 0xd2, 0xa6,
0xf6, 0x63, 0x00, 0xc7, 0x98, 0x7c, 0x95, 0xea, 0x65, 0xae, 0xfe, 0x5b, 0xf0, 0x6f, 0x2c, 0x20, 0xa6, 0xac, 0x2e, 0x1c, 0xb0, 0xbf, 0xc7, 0xd9, 0x9e, 0x45, 0x7f, 0x2c, 0x38, 0x42, 0xd0, 0xeb,
0x31, 0xf8, 0xba, 0xa6, 0xc3, 0xc4, 0x9b, 0x04, 0xdc, 0xd7, 0xf5, 0xc6, 0x92, 0xa7, 0x40, 0x0f, 0x44, 0x6e, 0x05, 0xbf, 0x5d, 0xc9, 0xff, 0x5e, 0xc9, 0x57, 0x08, 0x6e, 0xf2, 0xb8, 0x26, 0x89,
0xdd, 0x98, 0x50, 0x08, 0xf1, 0xc6, 0xc6, 0x95, 0x31, 0x77, 0x21, 0x7b, 0x04, 0x77, 0xf6, 0x5e, 0x5c, 0x2d, 0xc4, 0xa6, 0xa6, 0xc8, 0x49, 0x00, 0x0e, 0x7a, 0xae, 0xdc, 0xf5, 0xa8, 0x0e, 0xc9,
0x94, 0x10, 0x38, 0x6a, 0x2e, 0x8a, 0x7c, 0xf3, 0xcc, 0x9e, 0xc1, 0x49, 0xef, 0x78, 0x0d, 0xb1, 0x31, 0x58, 0x3b, 0x56, 0x29, 0xc7, 0x16, 0xb4, 0x3e, 0x46, 0x2f, 0xe0, 0xfe, 0xa4, 0xe7, 0x84,
0x39, 0x9e, 0x23, 0x36, 0xcf, 0x6d, 0xb1, 0xdf, 0x29, 0xbe, 0x86, 0xd3, 0x7d, 0x87, 0x23, 0x09, 0xc0, 0xac, 0xf6, 0x5c, 0xc9, 0x7a, 0x54, 0x9d, 0x35, 0xdd, 0xec, 0xe8, 0xef, 0xe1, 0x64, 0x64,
0x44, 0x38, 0xcc, 0x62, 0xd3, 0xaf, 0x9b, 0x22, 0xe7, 0xad, 0x1f, 0xb8, 0x20, 0xea, 0xee, 0x64, 0x78, 0x4d, 0xad, 0x0d, 0xd7, 0xd4, 0xfa, 0xdc, 0xca, 0x99, 0x63, 0xb9, 0x5e, 0x37, 0x3f, 0x0d,
0xc9, 0x29, 0x04, 0x2a, 0x57, 0xa9, 0xf5, 0x7b, 0xcc, 0x6d, 0xc0, 0x3e, 0xc3, 0xd9, 0x7c, 0x8b, 0x38, 0x9d, 0xf2, 0x9f, 0x84, 0xe0, 0xe2, 0x0c, 0x9b, 0xae, 0xa9, 0x7e, 0x8a, 0x9c, 0xb7, 0x6b,
0xd7, 0xdf, 0xb5, 0xdf, 0xc0, 0xfb, 0x73, 0x03, 0xbf, 0xdb, 0xe0, 0xa7, 0x07, 0xf7, 0x0e, 0xda, 0xbd, 0x1c, 0xcc, 0x7e, 0x90, 0x25, 0xa7, 0x60, 0x73, 0xc1, 0x93, 0xe6, 0xda, 0x78, 0xb4, 0x09,
0xf8, 0x17, 0xd7, 0xa3, 0x10, 0xae, 0x64, 0x7d, 0x29, 0xbe, 0xb9, 0x05, 0x5d, 0x88, 0xc8, 0xa7, 0x74, 0x2b, 0xb3, 0xae, 0x95, 0xdf, 0x06, 0x3c, 0xb8, 0x71, 0x7d, 0xff, 0xb0, 0x9f, 0x33, 0x98,
0x52, 0x14, 0xe6, 0x4d, 0xb5, 0x48, 0x13, 0x6e, 0x26, 0x0e, 0xba, 0x13, 0x9f, 0xc3, 0xf8, 0xfd, 0xe7, 0xfb, 0xeb, 0xb7, 0xe8, 0x83, 0x47, 0x31, 0x9a, 0xe8, 0xe8, 0x1c, 0xbc, 0x4f, 0x7b, 0xd6,
0x95, 0xdc, 0xcc, 0x78, 0x17, 0x86, 0xfa, 0x7b, 0x3b, 0xde, 0x88, 0x63, 0xc4, 0x1e, 0xc3, 0xc9, 0xf5, 0x70, 0x06, 0x73, 0xf9, 0xa3, 0xfd, 0xfc, 0x82, 0x62, 0x14, 0x3d, 0x85, 0x93, 0x8b, 0x58,
0x85, 0xd0, 0x69, 0xb6, 0x45, 0xa6, 0x10, 0x5a, 0xb8, 0xa2, 0x5e, 0x32, 0x98, 0x8c, 0xb8, 0x0b, 0x26, 0xe9, 0x00, 0x1c, 0x80, 0xd3, 0x94, 0xcb, 0xc0, 0x08, 0xad, 0xe5, 0x82, 0xea, 0x30, 0x7a,
0xd9, 0x0b, 0xa4, 0x73, 0x59, 0xac, 0x5b, 0xfa, 0x43, 0xb8, 0x89, 0xbf, 0x6f, 0xcb, 0x8f, 0x66, 0x89, 0x70, 0xca, 0xf2, 0xac, 0x85, 0x3f, 0x81, 0xbb, 0xf8, 0x4c, 0x37, 0x78, 0x77, 0xed, 0xe3,
0x31, 0xbe, 0xfa, 0xc8, 0xe0, 0x2d, 0xce, 0x6e, 0x41, 0xcc, 0x65, 0x2a, 0x97, 0xed, 0x37, 0x34, 0x95, 0x46, 0x04, 0x6d, 0xeb, 0xd1, 0x31, 0xf8, 0x94, 0x25, 0x6c, 0xdb, 0xfe, 0x1b, 0xeb, 0x05,
0x1b, 0x41, 0x88, 0xe8, 0x97, 0xa1, 0xf9, 0xfb, 0x3f, 0xf9, 0x1d, 0x00, 0x00, 0xff, 0xff, 0x9e, 0x38, 0x58, 0xbd, 0x9e, 0xab, 0x57, 0xfe, 0xd9, 0xdf, 0x00, 0x00, 0x00, 0xff, 0xff, 0x2c, 0xe3,
0x3b, 0x2b, 0xb0, 0x0e, 0x06, 0x00, 0x00, 0xe3, 0x53, 0xf6, 0x05, 0x00, 0x00,
} }
// Reference imports to suppress errors if they are not otherwise used. // Reference imports to suppress errors if they are not otherwise used.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment