This repository has been archived by the owner on Jan 30, 2021. It is now read-only.
/
trade.go
83 lines (67 loc) · 2.45 KB
/
trade.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
package tfc
import (
"fmt"
"regexp"
"github.com/hyperledger/fabric/core/chaincode/shim"
tfcPb "github.com/stefanprisca/strategy-protobufs/tfc"
)
func handleTrade(APIstub shim.ChaincodeStubInterface, creatorSign []byte,
gameData tfcPb.GameData, payload tfcPb.TradeTrxPayload) (tfcPb.GameData, error) {
err := assertTradePrecond(APIstub, gameData, creatorSign, payload)
if err != nil {
return gameData, fmt.Errorf(
"trade preconditions not met: %s", err)
}
srcID := GetPlayerId(payload.Source)
destID := GetPlayerId(payload.Dest)
resID := GetResourceId(payload.Resource)
srcProfile := gameData.Profiles[srcID]
destProfile := gameData.Profiles[destID]
srcProfile.Resources[resID] -= payload.Amount
destProfile.Resources[resID] += payload.Amount
return gameData, assertTradePostcond(gameData, payload)
}
func stateValidationString(src tfcPb.Player, state tfcPb.GameState) string {
return fmt.Sprintf("%v%v", src, state)
}
var tradeStateValidationRegexp = regexp.MustCompile(
fmt.Sprintf("%vRTRADE", tfcPb.Player_RED) +
fmt.Sprintf("|%vBTRADE", tfcPb.Player_BLUE) +
fmt.Sprintf("|%vGTRADE", tfcPb.Player_GREEN))
// TODO: implement this
func assertTradePrecond(APIstub shim.ChaincodeStubInterface,
gameData tfcPb.GameData, creatorSign []byte, payload tfcPb.TradeTrxPayload) error {
state := gameData.State
creator, err := getCreator(APIstub, creatorSign)
if err != nil || creator != payload.Source {
return fmt.Errorf("invalid trx creator, or creator not identified (<0): expected %v, got %v",
creator, payload.Source)
}
stateValidationStr := stateValidationString(creator, state)
if !tradeStateValidationRegexp.MatchString(stateValidationStr) {
return fmt.Errorf("expected state to match one of %v, got %v",
tradeStateValidationRegexp, stateValidationStr)
}
return nil
}
func assertTradePostcond(gameData tfcPb.GameData, payload tfcPb.TradeTrxPayload) error {
res := payload.Resource
if err := hasValidPostTradeAmount(payload.Source, gameData, res); err != nil {
return err
}
if err := hasValidPostTradeAmount(payload.Dest, gameData, res); err != nil {
return err
}
return nil
}
func hasValidPostTradeAmount(p tfcPb.Player, gameData tfcPb.GameData, r tfcPb.Resource) error {
rID := GetResourceId(r)
pP := *gameData.Profiles[GetPlayerId(p)]
available := pP.Resources[rID]
if available < 0 {
return fmt.Errorf("player %v does not have required %v resources: %s",
p, r,
fmt.Sprintf("available: %v", available))
}
return nil
}