一応 gistにも張っておいた。
仕組みは簡単。
- KVSの全ての値の組み合わせをjsonで返す関数 get_all を実装しておく。
- initの引数に、chaincodeのハッシュ値が指定されたら、そのchaincodeのget_allを呼び出し、KVSにコピーする。
- 今の時点では古いchaincodeを無効にするとかそういうことは省略。
これで途中でchaincode書き換えたいってことになっても大丈夫。
なお、jsonの読み書きに際してはgolang は ゆるふわに JSON を扱えまぁす!をめっちゃ参考にさせていただきました。
いろいろ自信ない部分がいっぱいなので突っ込み求めて晒しておきます。
get_all関数
migrate_worldstate.go
func (t *SimpleChaincode) Query(stub *shim.ChaincodeStub, function string, args []string) ([]byte, error) {
if function == "get_all" {
if len(args) != 0 {
fmt.Printf("Incorrect number of arguments passed"); return nil, errors.New("QUERY: Incorrect number of arguments passed")
}
return t.get_all(stub)
}
return nil, errors.New("QUERY: No such function.")
}
func (t *SimpleChaincode) get_all(stub *shim.ChaincodeStub) ([]byte, error) {
var tupples [][]string
keysIter, err := stub.RangeQueryState("", "~")
if err != nil {
return nil, errors.New("Unable to start the iterator")
}
defer keysIter.Close()
for keysIter.HasNext() {
key, val, iterErr := keysIter.Next()
if iterErr != nil {
return nil, fmt.Errorf("keys operation failed. Error accessing state: %s", err)
}
tupple := []string{ key , string(val) }
tupples=append(tupples, tupple)
}
marshalledTupples, err := json.Marshal(tupples)
return []byte(marshalledTupples), nil
}
init部分
migrate_worldstate.go
func (t *SimpleChaincode) Init(stub *shim.ChaincodeStub, function string, args []string) ([]byte, error) {
if len(args) == 1 {
// migrate from old chaincode. args[0] should have chaincode address
val, err := stub.QueryChaincode(args[0],"get_all", []string{} )
if err != nil {
return nil, errors.New("Unable to call chaincode " + args[0])
}
var states interface{}
err = json.Unmarshal(val, &states)
if err != nil {
return nil, errors.New("Unable to marshal chaincode return value " + string(val))
}
for _, stateIf := range states.([]interface{}){
state := stateIf.([]interface{})
stateKey := state[0].(string)
stateVal := state[1].(string)
if stateKey == "" {
return nil, errors.New("Unable to PutState: missing statekey [ " + stateKey +" , "+ string(stateVal) + " ]")
}
err = stub.PutState(stateKey, []byte(stateVal))
if err != nil {
return nil, errors.New("Unable to PutState [ " + stateKey +" , "+ string(stateVal) + " ]")
}
}
}
return nil, nil
}