使用fabric模仿代币流程

package main

import (
	"github.com/hyperledger/fabric/core/chaincode/shim"
	"fmt"
	pb "github.com/hyperledger/fabric/protos/peer"
	"encoding/pem"
	"crypto/x509"
	"bytes"
	"crypto/sha1"
	"crypto/rand"
	"crypto/rsa"
	"errors"
	"encoding/json"
	"strconv"
	"time"
	"encoding/base64"
	"crypto/aes"
	"crypto/cipher"
	"encoding/hex"
	"strings"
)

type Trans struct {				// 交易记录(交易主)
	Name string `json:"name"`	// account 使用 name + from + nonce 锁定一条交易历史记录
	From string `json:"from"`
	To string `json:"to"`
	Value int `json:"value"`
	Nonce int `json:"nonce"`
}

type Account struct {
	Balance map[string]int `json:"tokens"`				// 记录该账户下每个代币的余额
	Allowance map[string]map[string]int `json:"allowance"`	// 记录账户下每种代币中账户的代理额度
	//Locked map[string]bool `json:"locked"`				// 该账户在哪个代币被锁定
	Nonce int `json:"nonce"`		// 防止重放攻击,该nonce在trans和tokens只能锁定一条记录
	Time time.Time `json:"time"`	// 用于快速定位未花费的交易输出
}

type Data struct {						// 最终存储的账户数据结构(主)
	Account Account `json:"account"`
	PreHash string `json:"preHash"`
	Hash string `json:"hash"`
}

type Tokens struct {				// 存储的代币信息(副)
	Name string `json:"name"`			// 代币名称
	Supply int `json:"supply"`		// 发行总量
	Owner string `json:"owner"`			// 所有人(受益人,发行人)
	Lock bool `json:"lock"`			// 代币状态
	Nonce int `json:"nonce"`	// 账户 nonce
	AccountLock map[string]bool `json:"accountLock"`
}

type TokenChaincode struct {
}

var log *shim.ChaincodeLogger

func main() {
	err := shim.Start(new(TokenChaincode))
	if err != nil {
		fmt.Errorf(err.Error())
	}
}

func (t TokenChaincode) Init(stub shim.ChaincodeStubInterface) pb.Response {

	return shim.Success(SUCCESS)
}

func (t TokenChaincode) Invoke(stub shim.ChaincodeStubInterface) pb.Response {

	// 所有读的操作,按需提供参数
	// 所有写的操作,因为携带秘钥,必须解析出来

	function, args := stub.GetFunctionAndParameters()

	log = getLogger(stub)

	log.Infof("args: %s", args)

	if function == "" {
		return shim.Error("no function err")
	} else if function == "balance" {			// 读			获取余额							success
		return t.Balance(stub, args)
	} else if function == "allowance" {			// 读			获取代理额度						success
		return t.Allowance(stub, args)
	} else if function == "getAccount" {		// 读			获取账户信息						success
		return t.GetAccount(stub, args)
	} else if function == "getNonce" {			// 读			获取账户nonce					success
		return t.GetNonce(stub, args)
	} else if function == "getAccountWithSecret" {		// 带秘钥读,可用于登录    获取账户信息		success
		return t.GetAccountWithSecret(stub, args)
	} else if function == "getTransRecord" {	// 读			查询指定账户在合约内的交易记录		success
		return t.GetTransRecord(stub, args)
	} else if function == "newAccount" {			// 写			新建账户						success
		return t.NewAccount(stub, args)
	} else if function == "newToken" {			// 写			新建代币							success
		return t.NewToken(stub, args)
	} else if function == "transfer" {			// 写			发起转账							success
		return t.Transfer(stub, args)
	} else if function == "approve" {			// 写			授权								success
		return t.Approve(stub, args)
	} else if function == "transferFrom" {		// 写			发起代理转账						success
		return t.TransferFrom(stub, args)
	} else if function == "lockToken" {			// 写 			锁定代币							success
		return t.LockToken(stub, args)
	} else if function == "unLockToken" {		// 写			解除代币锁定						success
		return t.UnLockToken(stub, args)
	} else if function == "lockAccount" {		// 写			锁定代币账户						success
		return t.LockAccount(stub, args)
	} else if function == "unLockAccount" {		// 写			解锁代币账户						success
		return t.UnlockAccount(stub, args)
	} else if function == "mint" {				// 写			增发代币							success
		return t.Mint(stub, args)
	} else if function == "burn" {				// 写			回收代币							success
		return t.Burn(stub, args)
	}

	// 总的账户不能锁定,没有自己的秘钥,无法操作自己的数据,如果用户锁定了自己的账户,那么说明他也可以解锁
	// 		如果秘钥泄露了,你锁住了,那肯定也能解锁
	log.Errorf("%s was not found", function)
	return shim.Error(fmt.Sprintf("%s was not found", function))
}

// 前端传递的数据
type Message struct {		// 修改接受方式,不用对象接受
	Key string `json:"key"`			// 交易发起人的key(类似于普通用户的用户名,限制格式)
	Data string `json:"data"`		// 加密的交易参数
	Sign string `json:"sign"`		// 被加密的秘钥,防止被其它方式获取,链上数据不记录该秘钥,秘钥忘记则数据无法修改
}

// success
func (t TokenChaincode) NewAccount(stub shim.ChaincodeStubInterface, args []string) pb.Response {

	if len(args) != 2 {
		return shim.Error(parameterErr.Error())
	}

	// 解出秘钥
	message := &Message{
		Key:  args[0],
		Sign: args[1],
	}
	if message.Key == "" || message.Sign == "" {
		return shim.Error(parameterErr.Error())
	}

	sign, err := base64.StdEncoding.DecodeString(message.Sign)
	if err != nil {
		return shim.Error(err.Error())
	}
	secret, err := PrivateDecrypt(sign, PRIVATE)
	len := len(string(secret))
	if len < 6 || len > 16 {
		return shim.Error("secret length error")
	}
	if err != nil {
		return shim.Error(err.Error())
	}
	// 判断该key是否有数据绑定(是否重复)
	account, _ := getAccount(stub, message.Key)
	if account != nil {
		return shim.Error("key already exists")
	}
	// 当新增账户时,创建一条空的账户数据
	account = &Account{
		Balance:   make(map[string]int),
		Allowance: make(map[string]map[string]int),
		//Locked:    make(map[string]bool),
		Nonce:     0,
		Time:      time.Now(),
	}
	err = setAccount(stub, message.Key, account, secret)
	if err != nil {
		return shim.Error(err.Error())
	}

	return shim.Success([]byte(message.Key))
}

// success
func (t TokenChaincode) NewToken(stub shim.ChaincodeStubInterface, args []string) pb.Response {
	// 新建代币

	// 解析请求信息
	message, tokens, secret, err := messageToTokens(stub, args)
	if err != nil {
		return shim.Error(err.Error())
	}

	// 获取账户信息(连带UTXO一起统计)
	account, err := getTransTo(stub, message.Key)
	if err != nil {
		return shim.Error(err.Error())
	}
	if account == nil {
		return shim.Error("account is nil, please check your key")
	}

	// 判断nonce,防止重放攻击
	if tokens.Nonce-account.Nonce != 1 {
		return shim.Error(nonceError.Error())
	}

	// 如果下面的逻辑写入成功,递增nonce
	account.Nonce += 1

	// 拿到账户信息之后,新建一个token信息
	// 查看token名称是否已存在
	token, _ := getToken(stub, tokens.Name)
	if token != nil {
		return shim.Error("token name already exist")
	}
	token = &Tokens{
		Name:        tokens.Name,
		Supply:      tokens.Supply,
		Owner:       message.Key,
		Lock:        false,
		Nonce:       account.Nonce,
		AccountLock: make(map[string]bool),
	}

	// 创建完成后,增加账户的拥有记录
	account.Balance[token.Name] = token.Supply
	// 改变时间戳
	account.Time = time.Now()

	// 写入数据
	err = setToken(stub, token)
	if err != nil {
		return shim.Error(err.Error())
	}
	err = setAccount(stub, message.Key, account, secret)
	if err != nil {
		return shim.Error(err.Error())
	}

	return shim.Success(SUCCESS)
}

// success
func (t TokenChaincode) Transfer(stub shim.ChaincodeStubInterface, args []string) pb.Response {

	// 解析请求数据
	message, trans, secret, err := messageToTrans(stub, args)
	if err != nil {
		return shim.Error(err.Error())
	}

	// 如果交易数额小于0,视为违规交易
	if trans.Value < 0 {
		return shim.Error(valueErr.Error())
	}

	// 当给自己转账时,会将UTXO数据写在历史的time中,然后修改自己的账户数据,会导致汇总UTXO时,汇总结果不正确
	if trans.From == trans.To {
		return shim.Error("you can't transfer tokens to yourself")
	}

	// 获取账户信息(UTXO)
	accountFrom, err := getTransTo(stub, trans.From)

	// 验证nonce
	if trans.Nonce-accountFrom.Nonce != 1 {
		return shim.Error(nonceError.Error())
	}
	// 验证余额
	if accountFrom.Balance[trans.Name] < trans.Value {
		return shim.Error(balanceErr.Error())
	}

	// 检查合约是否被锁定
	err = checkTokenState(stub, trans.Name, message.Key, trans.From, trans.To)
	if err != nil {
		return shim.Error(err.Error())
	}

	// 递增nonce,只递增from的nonce
	accountFrom.Nonce += 1
	// 修改时间戳
	accountFrom.Time = time.Now()

	// 修改数据
	accountFrom.Balance[trans.Name] -= trans.Value

	// 写入数据(会自动写入UTXO中)
	err = setTrans(stub, message.Key, trans)
	if err != nil {
		return shim.Error(err.Error())
	}
	// 此处由于无法读取用户的最新状态数据,所以当自己给自己转账时,会出现统计异常问题
	err = setAccount(stub, message.Key, accountFrom, secret)
	if err != nil {
		return shim.Error(err.Error())
	}

	return shim.Success(SUCCESS)
}

// success
func (t TokenChaincode) Approve(stub shim.ChaincodeStubInterface, args []string) pb.Response {

	// 解析数据
	message, trans, secret, err := messageToTrans(stub, args)
	if err != nil {
		return shim.Error(err.Error())
	}

	// 获取账户统计信息(所有)
	account, err := getTransTo(stub, message.Key)
	if err != nil {
		return shim.Error(err.Error())
	}

	if trans.Value < 0 {
		return shim.Error(valueErr.Error())
	}

	// 判断合约以及账户锁定
	err = checkTokenState(stub, trans.Name, message.Key)
	if err != nil {
		return shim.Error(err.Error())
	}

	// 验证nonce
	if trans.Nonce - account.Nonce != 1 {
		return shim.Error(nonceError.Error())
	}

	// 验证完成后叠加nonce
	account.Nonce += 1
	// 修改时间
	account.Time = time.Now()

	// 授权操作(添加授权记录,当被授权用户下一次操作时,写入自己的账户信息中)
	err = setApprove(stub, trans)
	if err != nil {
		return shim.Error(err.Error())
	}
	// 写数据
	err = setAccount(stub, message.Key, account, secret)
	if err != nil {
		return shim.Error(err.Error())
	}

	return shim.Success(SUCCESS)
}

func (t TokenChaincode) TransferFrom(stub shim.ChaincodeStubInterface, args []string) pb.Response {

	// 解析参数
	message, trans, secret, err := messageToTrans(stub, args)
	if err != nil {
		return shim.Error(err.Error())
	}
	// 获取账户信息
	account, err := getTransTo(stub, message.Key)
	if err != nil {
		return shim.Error(err.Error())
	}

	// 判断合约以及账户锁定情况
	err = checkTokenState(stub, trans.Name, message.Key, trans.From, trans.To)
	if err != nil {
		return shim.Error(err.Error())
	}
	if trans.Value < 0 {
		return shim.Error(valueErr.Error())
	}
	if message.Key == trans.From {
		return shim.Error(balanceErr.Error())
	}
	// 判断代理额度
	if account.Allowance[trans.Name][trans.From] < trans.Value {
		return shim.Error(approveBalanceErr.Error())
	}
	if trans.Nonce-account.Nonce != 1 {
		return shim.Error(nonceError.Error())
	}

	// 代理额度扣减
	account.Allowance[trans.Name][trans.From] -= trans.Value
	account.Nonce += 1

	// 设置转出方
	err = setTransTo(stub, trans)
	if err != nil {
		return shim.Error(err.Error())
	}

	// 颠倒交易顺序再次记录
	trans.From, trans.To, trans.Value = trans.To, trans.From, -trans.Value
	err = setTransTo(stub, trans)
	if err != nil {
		return shim.Error(err.Error())
	}

	// 保存账户
	err = setAccount(stub, message.Key, account, secret)
	if err != nil {
		return shim.Error(err.Error())
	}

	return shim.Success(SUCCESS)
}

func (t TokenChaincode) LockToken(stub shim.ChaincodeStubInterface, args []string) pb.Response {
	return tokenLock(stub, args, true)
}

func (t TokenChaincode) UnLockToken(stub shim.ChaincodeStubInterface, args []string) pb.Response {
	return tokenLock(stub, args, false)
}

func tokenLock(stub shim.ChaincodeStubInterface, args []string, state bool) pb.Response {

	message, trans, secret, err := messageToTrans(stub, args)
	if err != nil {
		return shim.Error(err.Error())
	}
	account, err := getTransTo(stub, message.Key)
	if err != nil {
		return shim.Error(err.Error())
	}
	token, err := getToken(stub, trans.Name)
	if err != nil {
		return shim.Error(err.Error())
	}

	// 验证nonce
	if trans.Nonce-account.Nonce != 1 {
		return shim.Error(nonceError.Error())
	}
	// 验证所有人
	if token.Owner != message.Key {
		return shim.Error(permissionErr.Error())
	}

	// 修改数据
	account.Nonce += 1

	// 将代币的nonce改成和账户一致
	token.Lock = state
	token.Nonce = account.Nonce

	// 写数据
	err = setToken(stub, token)
	if err != nil {
		return shim.Error(err.Error())
	}
	err = setAccount(stub, message.Key, account, secret)
	if err != nil {
		return shim.Error(err.Error())
	}

	return shim.Success(SUCCESS)
}

func (t TokenChaincode) LockAccount(stub shim.ChaincodeStubInterface, args []string) pb.Response {
	return accountLock(stub, args, true)
}

func (t TokenChaincode) UnlockAccount(stub shim.ChaincodeStubInterface, args []string) pb.Response {
	return accountLock(stub, args, false)
}

func accountLock(stub shim.ChaincodeStubInterface, args []string, state bool) pb.Response {

	// 解析数据
	message, trans, secret, err := messageToTrans(stub, args)
	if err != nil {
		return shim.Error(err.Error())
	}

	token, err := getToken(stub, trans.Name)
	if err != nil {
		return shim.Error(err.Error())
	}
	// 判断权限
	if token.Owner != message.Key {
		return shim.Error(permissionErr.Error())
	}

	// 不能锁住自己
	if trans.From == trans.To {
		return shim.Error(valueErr.Error())
	}

	// 判断nonce
	account, err := getTransTo(stub, message.Key)
	if err != nil {
		return shim.Error(err.Error())
	}
	if trans.Nonce-account.Nonce != 1 {
		return shim.Error(nonceError.Error())
	}

	// 修改数据
	if token.AccountLock == nil {
		token.AccountLock = make(map[string]bool)
	}
	token.AccountLock[trans.To] = state
	account.Nonce += 1

	token.Nonce = account.Nonce

	// 写入数据
	err = setToken(stub, token)
	if err != nil {
		return shim.Error(err.Error())
	}
	err = setAccount(stub, message.Key, account, secret)
	if err != nil {
		return shim.Error(err.Error())
	}

	return shim.Success(SUCCESS)
}

func (t TokenChaincode) Mint(stub shim.ChaincodeStubInterface, args []string) pb.Response {

	// 获取相关数据
	message, trans, secret, err := messageToTrans(stub, args)
	if err != nil {
		return shim.Error(err.Error())
	}
	account, err := getTransTo(stub, message.Key)
	if err != nil {
		return shim.Error(err.Error())
	}
	token, err := getToken(stub, trans.Name)
	if err != nil {
		return shim.Error(err.Error())
	}

	// 判断权限
	if token.Owner != message.Key {
		return shim.Error(permissionErr.Error())
	}
	// 判断数值
	if trans.Value <= 0 {
		return shim.Error(valueErr.Error())
	}
	// 判断nonce
	if trans.Nonce-account.Nonce != 1 {
		return shim.Error(nonceError.Error())
	}


	// 修改数据
	token.Supply += trans.Value
	account.Balance[token.Name] += trans.Value
	account.Nonce += 1
	token.Nonce = account.Nonce

	// 写入数据
	err = setToken(stub, token)
	if err != nil {
		return shim.Error(err.Error())
	}
	err = setAccount(stub, message.Key, account, secret)
	if err != nil {
		return shim.Error(err.Error())
	}

	return shim.Success(SUCCESS)
}
/*
	回收相当于增发的逆向操作
*/
func (t TokenChaincode) Burn(stub shim.ChaincodeStubInterface, args []string) pb.Response {
	message, trans, secret, err := messageToTrans(stub, args)
	if err != nil {
		return shim.Error(err.Error())
	}
	account, err := getTransTo(stub, message.Key)
	if err != nil {
		return shim.Error(err.Error())
	}
	token, err := getToken(stub, trans.Name)
	if err != nil {
		return shim.Error(err.Error())
	}

	// 判断
	if token.Owner != message.Key {
		return shim.Error(permissionErr.Error())
	}
	if trans.Value <= 0 {
		return shim.Error(valueErr.Error())
	}
	if trans.Nonce-account.Nonce != 1 {
		return shim.Error(nonceError.Error())
	}
	// 因为回收的时候只能从本(管理员)账户进行回收操作,如果管理员的拥有额度不足,那么将回收失败
	if account.Balance[trans.Name] < trans.Value {
		return shim.Error(valueErr.Error())
	}
	// 如果回收数值超出发行总量
	if token.Supply <= trans.Value {
		return shim.Error(valueErr.Error())
	}

	//修改数据
	token.Supply -= trans.Value
	account.Balance[token.Name] -= trans.Value
	account.Nonce += 1
	token.Nonce = account.Nonce

	// 写入数据
	err = setToken(stub, token)
	if err != nil {
		return shim.Error(err.Error())
	}
	err = setAccount(stub, message.Key, account, secret)
	if err != nil {
		return shim.Error(err.Error())
	}

	return shim.Success(SUCCESS)
}

// 获取当前账户的nonce,由于一个账号锁定一行数据,不会出现并发情况(多人操作同一账户导致nonce重放) success
func (t TokenChaincode) GetNonce(stub shim.ChaincodeStubInterface, args []string) pb.Response {
	if len(args) != 1 {
		return shim.Error(parameterErr.Error())
	}
	account, err := getAccount(stub, args[0])
	if err != nil {
		return shim.Error(err.Error())
	}
	return shim.Success([]byte(strconv.Itoa(account.Nonce + 1)))
}

// success
func (t TokenChaincode) Balance(stub shim.ChaincodeStubInterface, args []string) pb.Response {

	if len(args) != 2 {
		return shim.Error(parameterErr.Error())
	}
	name, key := args[0], args[1]

	account, err := getTransTo(stub, key)
	if err != nil {
		return shim.Error(err.Error())
	}
	return shim.Success([]byte(strconv.Itoa(account.Balance[name])))
}

// success
func (t TokenChaincode) Allowance(stub shim.ChaincodeStubInterface, args []string) pb.Response {
	if len(args) != 3 {
		return shim.Error(parameterErr.Error())
	}
	name, key, from := args[0], args[1], args[2]
	// 必须获取所有未花费的交易输出,才能保证数据真实
	account, err := getTransTo(stub, key)
	if err != nil {
		return shim.Error(err.Error())
	}
	return shim.Success([]byte(strconv.Itoa(account.Allowance[name][from])))
}

// 测试成功
func (t TokenChaincode) GetAccount(stub shim.ChaincodeStubInterface, args []string) pb.Response {
	if len(args) != 1 {
		return shim.Error(parameterErr.Error())
	}
	key := args[0]
	account, err := getTransTo(stub, key)
	if err != nil {
		return shim.Error(err.Error())
	}
	if account == nil {
		return shim.Error("account is nil, please check your key")
	}
	ab, _ := json.Marshal(account)
	return shim.Success(ab)
}

// 测试成功
func (t TokenChaincode) GetAccountWithSecret(stub shim.ChaincodeStubInterface, args []string) pb.Response {

	if len(args) != 2 {
		return shim.Error(parameterErr.Error())
	}

	// 解出秘钥
	message := &Message{
		Key:  args[0],
		Sign: args[1],
	}
	log.Infof("message: %s", message)
	if message.Key == "" || message.Sign == "" {
		return shim.Error(parameterErr.Error())
	}
	// 计算秘钥
	sign, err := base64.StdEncoding.DecodeString(message.Sign)
	if err != nil {
		return shim.Error(err.Error())
	}
	secret, err := PrivateDecrypt(sign, PRIVATE)
	log.Infof("计算出秘钥: %s", string(secret))
	if err != nil {
		return shim.Error(err.Error())
	}

	// 取数据
	data, err := getData(stub, message.Key)
	log.Infof("获取数据: %s", data)
	if err != nil {
		return shim.Error(err.Error())
	}
	// 验证秘钥
	err = verifySecret(data, secret)
	if err != nil {
		return shim.Error(err.Error())
	}
	log.Info("验证通过")
	// 验证完毕后,重新拉取数据,携带UTXO
	account, err := getTransTo(stub, message.Key)
	log.Info(account)
	if err != nil {
		return shim.Error(err.Error())
	}
	ab, err := json.Marshal(account)
	log.Info(string(ab))
	if err != nil {
		return shim.Error(err.Error())
	}
	return shim.Success(ab)
}

// success
func (t TokenChaincode) GetTransRecord(stub shim.ChaincodeStubInterface, args []string) pb.Response {

	if len(args) != 2 {
		return shim.Error(parameterErr.Error())
	}

	key, name := args[0], args[1]
	if key == "" || name == "" {
		return shim.Error("one of parameter is nil")
	}
	trans, err := getTransRecord(stub, key, name)
	if err != nil {
		return shim.Error(err.Error())
	}

	return shim.Success(trans)
}

func checkTokenState(stub shim.ChaincodeStubInterface, name string, keys ...string) error {
	token, err := getToken(stub, name)
	if err != nil {
		return err
	}
	if token.Lock {
		return tokenLockErr
	}
	for _, key := range keys{
		if token.AccountLock[key] {
			return accountLockErr
		}
	}
	return nil
}

// 使用现有的数据做计算,如果计算结果匹配,说明秘钥正确,如果不匹配,说明秘钥错误
func verifySecret(data *Data, secret []byte) error {			// 该方法报空指针
	log.Info("开始验证秘钥")
	ab, err := json.Marshal(data.Account)
	if err != nil {
		return err
	}
	hashes := Hash(ab)
	res, err := AesEncrypt(hashes, secret)
	//log.Infof("进行正向加密: %s", string(res))
	//log.Info(res)
	//log.Info(hex.EncodeToString(res))
	//log.Infof("状态数据的hash: %s", data.Hash)
	//log.Info([]byte(data.Hash))
	//log.Info(hex.EncodeToString([]byte(data.Hash)))
	if err != nil {
		return err
	}
	// bytes.Compare([]byte(data.Hash), res) == 0   该方法比较失败
	// data.Hash == string(res) 					比较失败
	// bytes.Equal([]byte(data.Hash), res)			失败
	// strings.Compare(data.Hash, string(res)) == 0	失败

	if strings.EqualFold(data.Hash, string(res)) {		// 成功
		log.Info("秘钥验证通过")
		return nil
	} else {
		log.Info("秘钥验证失败")
		return verifyKeyErr
	}
}

/*
	封装读写数据
*/

// 获取state 已花费记录
func getTransRecord(stub shim.ChaincodeStubInterface, key string, name string) ([]byte, error) {
	log.Info("查询交易记录")
	transKey := fmt.Sprintf("trans.%s.%s", name, key)
	res, err := stub.GetHistoryForKey(transKey)
	if err != nil {
		return nil, err
	}
	trans, err := getHisResult(res)
	if err != nil {
		return nil, err
	}
	return trans.Bytes(), nil
}

// 设置state 已花费
func setTrans(stub shim.ChaincodeStubInterface, key string, trans *Trans) error {
	log.Info("保存已花费记录")
	transKey := fmt.Sprintf("trans.%s.%s", trans.Name, key)
	ab, err := json.Marshal(trans)
	if err != nil {
		return err
	}
	// 保存正常的交易流水
	log.Info("记录流水")
	err = stub.PutState(transKey, ab)
	if err != nil {
		return err
	}
	// 保存未花费的交易输出
	// 此处操作的是to的账户时间戳,跟from无关,所以不用担心时间戳问题
	err = setTransTo(stub, trans)
	if err != nil {
		return err
	}

	//err = setApprove(stub, trans)
	//if err != nil {
	//	return err
	//}
	return nil
}

// 获取所有未花费的记录(与getAccount区别在于,此处统计了未花费的交易输出)
func getTransTo(stub shim.ChaincodeStubInterface, to string) (*Account, error) {
	log.Info("获取账户未花费的交易输出")
	// 记录当前时间点,所有在当前事件点后写进的数据不纳入统计
	account, err := getAccount(stub, to)
	if err != nil {
		return nil, err
	}
	log.Infof("获取状态数据: %s", account)
	if account.Balance == nil {
		account.Balance = make(map[string]int)
	}
	// 这个key设计的不分币种,只要是未花费全部统计,怎么让每次获取utxo都不会全量循环?带上时间戳作为key,保证每次key都不同
	transToKey := "trans.to." + to + account.Time.String()		// 以账户的时间戳作为后缀,防止每次都读取重复的未花费记录
	// 获取所有历史记录
	tb, err := stub.GetHistoryForKey(transToKey)
	if err != nil {
		return nil, err
	}
	for tb.HasNext() {
		tx, err := tb.Next()
		if err != nil {
			return nil, err
		}
		var trans Trans
		json.Unmarshal(tx.Value, &trans)
		// 叠加未花费输出
		account.Balance[trans.Name] += trans.Value
	}
	log.Infof("account: %s", account)
	// 获取代理额度
	return getApprove(stub, to, account)
}

// 设置state 未花费的记录
func setTransTo(stub shim.ChaincodeStubInterface, trans *Trans) error {
	log.Info("记录未花费交易输出")
	account, err := getAccount(stub, trans.To)
	if err != nil {
		return err
	}
	transToKey := "trans.to." + trans.To + account.Time.String()
	tb, err := json.Marshal(trans)
	if err != nil {
		return err
	}
	err = stub.PutState(transToKey, tb)
	if err != nil {
		return err
	}
	return nil
}

// 获取代理额度
func getApprove(stub shim.ChaincodeStubInterface, key string, account *Account) (*Account, error) {
	log.Info("整理代理额度")
	if account.Allowance == nil {
		account.Allowance = make(map[string]map[string]int)
	}
	approveKey := "approve." + key + account.Time.String()
	atb, err := stub.GetHistoryForKey(approveKey)
	if err != nil {
		return nil, err
	}
	for atb.HasNext() {
		ab, err := atb.Next()
		if err != nil {
			return nil, err
		}
		var trans Trans
		json.Unmarshal(ab.Value, &trans)
		// 叠加代理额度
		if account.Allowance[trans.Name] == nil {
			account.Allowance[trans.Name] = make(map[string]int)
			account.Allowance[trans.Name][trans.From] = trans.Value
		} else {
			account.Allowance[trans.Name][trans.From] += trans.Value
		}
	}
	log.Infof("account: %s", account)
	return account, nil
}

// 设置代理记录
func setApprove(stub shim.ChaincodeStubInterface, trans *Trans) error {
	account, err := getAccount(stub, trans.To)
	if err != nil {
		return err
	}
	approveKey := "approve." + trans.To + account.Time.String()
	ab, err := json.Marshal(trans)
	if err != nil {
		return err
	}
	err = stub.PutState(approveKey, ab)
	return err
}

// 此处不统计UTXO数据
func getAccount(stub shim.ChaincodeStubInterface, key string) (*Account, error) {
	data, err := getData(stub, key)
	if err != nil {
		return nil, err
	}

	return &data.Account, nil
}

func setAccount(stub shim.ChaincodeStubInterface, key string, account *Account, secret []byte) error {
	log.Info("开始设置账户")
	accountKey := "account." + key
	data := &Data{
		Account: *account,
		PreHash: "",
		Hash:    "",
	}

	// 更新账户的操作时间
	data.Account.Time = time.Now()

	// 设置preHash
	pd, err := stub.GetState(accountKey)
	if err != nil {
		return err
	}
	// 如果不存在,到底是数据不存在还是首条数据》?
	if pd != nil {
		var preData Data
		err = json.Unmarshal(pd, &preData)
		if err != nil {
			return err
		}
		// 记录上一个数据的hash
		data.PreHash = preData.Hash
	}

	// 设置hash
	ab, err := json.Marshal(data.Account)
	if err != nil {
		return err
	}

	hashes := Hash(ab)

	log.Infof("hash结果: %s", string(hashes))

	res, err := AesEncrypt(hashes, secret)
	if err != nil {
		return err
	}

	data.Hash = string(res)

	log.Infof("加密后的hash: %s", data.Hash)

	db, err := json.Marshal(data)
	if err != nil {
		return err
	}

	err = stub.PutState(accountKey, db)
	return nil
}

func getData(stub shim.ChaincodeStubInterface, key string) (*Data, error) {
	accountKey := "account." + key
	db, err := stub.GetState(accountKey)
	if err != nil {
		return nil, err
	}
	// 如果数据为空,直接返回出去
	if db == nil {
		return nil, errors.New("account data is nil")
	}
	var data Data
	err = json.Unmarshal(db, &data)
	if err != nil {
		return nil, err
	}
	return &data, nil
}

func getToken(stub shim.ChaincodeStubInterface, name string) (*Tokens, error) {
	tokenKey := "token." + name
	tb, err := stub.GetState(tokenKey)
	if err != nil {
		return nil, err
	}
	var token Tokens
	err = json.Unmarshal(tb, &token)
	if err != nil {
		return nil, err
	}
	return &token, nil
}

func setToken(stub shim.ChaincodeStubInterface, token *Tokens) error {
	tokenKey := "token." + token.Name
	tb, err := json.Marshal(token)
	if err != nil {
		return err
	}
	err = stub.PutState(tokenKey, tb)
	if err != nil {
		return err
	}
	return nil
}

func messageToTokens(stub shim.ChaincodeStubInterface, args []string) (*Message, *Tokens, []byte, error) {

	log.Info("begin message to tokens")

	if len(args) != 3 {
		return nil, nil, nil, parameterErr
	}
	message := &Message{
		Key:  args[0],
		Data: args[1],
		Sign: args[2],
	}
	if message.Key == "" || message.Sign == "" || message.Data == "" {
		return nil, nil, nil, parameterErr
	}
	log.Infof("message: %s", message)

	secret, tb, err := parseMessage(stub, message)
	if err != nil {
		return nil, nil, nil, err
	}
	var tokens Tokens
	err = json.Unmarshal(tb, &tokens)
	if err != nil {
		return nil, nil, nil, err
	}
	return message, &tokens, secret, nil
}

func messageToTrans(stub shim.ChaincodeStubInterface, args []string) (*Message, *Trans, []byte, error) {
	log.Info("")
	if len(args) != 3 {
		return nil, nil, nil, parameterErr
	}
	message := &Message{
		Key:  args[0],
		Data: args[1],
		Sign: args[2],
	}
	if message.Key == "" || message.Sign == "" || message.Data == "" {
		return nil, nil, nil, parameterErr
	}
	secret, tb, err := parseMessage(stub, message)
	if err != nil {
		return nil, nil, nil, err
	}
	var trans Trans
	err = json.Unmarshal(tb, &trans)
	if err != nil {
		return nil, nil, nil, err
	}
	return message, &trans, secret, nil
}

// 解析请求消息		success
func parseMessage(stub shim.ChaincodeStubInterface, message *Message) ([]byte, []byte, error) {

	log.Info("开始转换消息数据")

	// 计算秘钥
	sign, err := base64.StdEncoding.DecodeString(message.Sign)
	if err != nil {
		return nil, nil, err
	}
	secret, err := PrivateDecrypt(sign, PRIVATE)
	if err != nil {
		return nil, nil, err
	}
	log.Infof("获取秘钥: %s", string(secret))

	// 获取当前记录数据,验证秘钥
	data, err := getData(stub, message.Key)
	if err != nil {
		return nil, nil, err
	}
	err = verifySecret(data, secret)
	if err != nil {
		return nil, nil, err
	}

	// 秘钥正确,则解析交易信息
	// 这里属于外来加密数据,需要进行16进制转换
	content, err := hex.DecodeString(message.Data)
	if err != nil {
		return nil, nil, err
	}
	tb, err := AesDecrypt(content, secret)
	if err != nil {
		return nil, nil, err
	}
	return secret, tb, nil
}


func getLogger(stub shim.ChaincodeStubInterface) (c *shim.ChaincodeLogger) {
	fcn, _ := stub.GetFunctionAndParameters()
	c = shim.NewLogger(fmt.Sprintf("%s.%s.%s", stub.GetChannelID(), "token", fcn))
	c.SetLevel(shim.LogDebug)
	return
}
/*
	常量以及无关数据读写的方法
*/
var SUCCESS = []byte("success")

var parameterErr = errors.New("parameter err")
var privateDecodeErr = errors.New("private decrypt error")
var verifyKeyErr = errors.New("verify key error")
var nonceError = errors.New("nonce error")
var balanceErr = errors.New("insufficient balance")
var tokenLockErr = errors.New("token was locked")
var accountLockErr = errors.New("account was locked")
var valueErr = errors.New("does not suppert this transaction")
var approveBalanceErr = errors.New("allowance approve balance error")
var permissionErr = errors.New("permission denied")

func Hash(text []byte) []byte {
	shaInst := sha1.New()
	shaInst.Write(text)
	result := shaInst.Sum(nil)
	return result
}

var PUBLIC = []byte(`
-----BEGIN PUBLIC KEY-----
MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBALAEZjmAtbVl5534yrDD4n5UUcH1NdNL
TQzEPojUvf4/o7cv2dGZJ5QdJ/ciUjIwWZpF2qtBKQpye/LwAYC5WLUCAwEAAQ==
-----END PUBLIC KEY-----
`)

var PRIVATE = []byte(`
-----BEGIN RSA PRIVATE KEY-----
MIIBOQIBAAJBALAEZjmAtbVl5534yrDD4n5UUcH1NdNLTQzEPojUvf4/o7cv2dGZ
J5QdJ/ciUjIwWZpF2qtBKQpye/LwAYC5WLUCAwEAAQJALugtOdvEEOBkViPsGClL
nbDozNCFFJb3pJRTufE/5JYt7hM1rGinPvBO4eTzjz38Iw6Aa2nIfgaULlRa+Lht
7QIhANSBEy9bO0ugbYPIyEHOfQYWyFARxnnMHZDdSrSE4K2jAiEA1At0misbtpSM
XMeO+OtZ7BZD3suxti3xcmSSEK4cFccCIF/KR0GjmFkA2hz7lvnDAKyL/IPLX3Jr
xjAU8KXq9/SNAiBEXbUoh8GVqmte9pBoPSlu7vbO/Im9nS59nWNisWAovQIgVD8g
I93EUVHy2gAskSSoh1q4EYbGxNUSyO6Y3hU0ApA=
-----END RSA PRIVATE KEY-----
`)

var iv = []byte("abcdefghijk1mnop")

// aes 解密
func AesDecrypt(crypted, key []byte) ([]byte, error) {
	key = addSuffix(key)
	block, err := aes.NewCipher(key)
	if err != nil {
		return nil, err
	}

	blockMode := cipher.NewCBCDecrypter(block, iv)
	origData := make([]byte, len(crypted))
	blockMode.CryptBlocks(origData, crypted)
	origData = PKCS5UnPadding(origData)
	return origData, nil
}

// aes 加密
func AesEncrypt(origData, key []byte) ([]byte, error) {
	key = addSuffix(key)
	block, err := aes.NewCipher(key)
	if err != nil {
		return nil, err
	}

	blockSize := block.BlockSize()
	origData = PKCS5Padding(origData, blockSize)
	blockMode := cipher.NewCBCEncrypter(block, iv)
	crypted := make([]byte, len(origData))
	blockMode.CryptBlocks(crypted, origData)
	return crypted, nil
}

// aes规定秘钥必须是8的倍数,8还不行,所以在这里固定成16
func addSuffix(secret []byte) []byte {
	s := string(secret)
	len := len(s)
	for i:=0; i<16-len; i++ {
		s += "="
	}
	return []byte(s)
}

func PKCS5Padding(ciphertext []byte, blockSize int) []byte {
	padding := blockSize - len(ciphertext)%blockSize
	padtext := bytes.Repeat([]byte{byte(padding)}, padding)
	return append(ciphertext, padtext...)
}

func PKCS5UnPadding(origData []byte) []byte {
	length := len(origData)
	unpadding := int(origData[length-1])
	return origData[:(length - unpadding)]
}


func ParsePrivateKey(private []byte) (*rsa.PrivateKey, error) {
	block, _ := pem.Decode(private)
	if block == nil {
		return nil, privateDecodeErr
	}
	priv, err := x509.ParsePKCS1PrivateKey(block.Bytes)
	if err != nil {
		return nil, err
	}
	return priv, nil
}

// 解密
func PrivateDecrypt(ciphertext, privateKey []byte) ([]byte, error) {
	priv, err := ParsePrivateKey(privateKey)
	if err != nil {
		return nil, err
	}

	var b bytes.Buffer

	begin, size, end := 0, 128, len(ciphertext)

	for end-begin > 0 {
		var temp []byte
		if end <= begin+size {
			temp = ciphertext[begin:end]
		} else {
			temp = ciphertext[begin : begin+size]
		}
		tres, err := rsa.DecryptPKCS1v15(rand.Reader, priv, temp)
		if err != nil {
			return nil, err
		}
		b.Write(tres)
		begin += size
	}

	return b.Bytes(), err
}

func getHisResult(result shim.HistoryQueryIteratorInterface) (bytes.Buffer, error) {
	//由于查询的结果是一个集合,所以要将结果集转成字符串,方便传输
	var buffer bytes.Buffer
	buffer.WriteString("[")

	bArrayMemberAlreadyWritten := false

	for result.HasNext() {

		response, err := result.Next()
		if err != nil {
			return buffer, err
		}

		if bArrayMemberAlreadyWritten {
			buffer.WriteString(",")
		}

		buffer.WriteString("{\"TxId\":\"")
		buffer.WriteString(response.TxId)
		buffer.WriteString("\",\"value\":")

		//if response.IsDelete {
		//	buffer.WriteString("null")
		//} else {
			buffer.WriteString(string(response.Value))
		//}

		buffer.WriteString(", \"Timestamp\":\"")
		buffer.WriteString(time.Unix(response.Timestamp.Seconds, int64(response.Timestamp.Nanos)).Format("2006-01-02 15:04:05"))
		buffer.WriteString("\"")

		buffer.WriteString(", \"IsDelete\":\"")
		buffer.WriteString(strconv.FormatBool(response.IsDelete))
		buffer.WriteString("\"")

		buffer.WriteString("}")

		//item,_:= json.Marshal(response)
		//buffer.Write(item)

		bArrayMemberAlreadyWritten = true
	}

	buffer.WriteString("]")
	return buffer, nil
}

你可能感兴趣的:(blockChain)