import (
"context"
- "crypto/rand"
- "encoding/json"
- "time"
+ stdjson "encoding/json"
+ "fmt"
log "github.com/sirupsen/logrus"
- "github.com/vapor/blockchain/signers"
"github.com/vapor/blockchain/txbuilder"
+ "github.com/vapor/consensus/federation"
+ "github.com/vapor/errors"
"github.com/vapor/protocol/bc"
"github.com/vapor/protocol/bc/types"
)
-//NewIssueAction create a new asset issue action
-func (reg *Registry) NewIssueAction(assetAmount bc.AssetAmount) txbuilder.Action {
- return &issueAction{
- assets: reg,
- AssetAmount: assetAmount,
- }
-}
-
-//DecodeIssueAction unmarshal JSON-encoded data of asset issue action
-func (reg *Registry) DecodeIssueAction(data []byte) (txbuilder.Action, error) {
- a := &issueAction{assets: reg}
- err := json.Unmarshal(data, a)
+// DecodeCrossInAction convert input data to action struct
+func (r *Registry) DecodeCrossInAction(data []byte) (txbuilder.Action, error) {
+ a := &crossInAction{reg: r}
+ err := stdjson.Unmarshal(data, a)
return a, err
}
-type issueAction struct {
- assets *Registry
+type crossInAction struct {
+ reg *Registry
bc.AssetAmount
- Arguments []txbuilder.ContractArgument `json:"arguments"`
+ SourceID bc.Hash `json:"source_id"`
+ SourcePos uint64 `json:"source_pos"`
+ AssetDefinition map[string]interface{} `json:"asset_definition"`
}
-func (a *issueAction) Build(ctx context.Context, builder *txbuilder.TemplateBuilder) error {
+func (a *crossInAction) Build(ctx context.Context, builder *txbuilder.TemplateBuilder) error {
+ var missing []string
+ if a.SourceID.IsZero() {
+ missing = append(missing, "source_id")
+ }
if a.AssetId.IsZero() {
- return txbuilder.MissingFieldsError("asset_id")
+ missing = append(missing, "asset_id")
+ }
+ if a.Amount == 0 {
+ missing = append(missing, "amount")
+ }
+ if len(missing) > 0 {
+ return txbuilder.MissingFieldsError(missing...)
}
- asset, err := a.assets.FindByID(ctx, a.AssetId)
- if err != nil {
- return err
+ sourceKey := []byte(fmt.Sprintf("SC:%v:%v", a.SourceID, a.SourcePos))
+ a.reg.assetMu.Lock()
+ defer a.reg.assetMu.Unlock()
+ if existed := a.reg.db.Get(sourceKey); existed != nil {
+ return errors.New("mainchain output double spent")
}
- var nonce [8]byte
- _, err = rand.Read(nonce[:])
+ rawDefinitionByte, err := serializeAssetDef(a.AssetDefinition)
if err != nil {
- return err
+ return ErrSerializing
}
- txin := types.NewIssuanceInput(nonce[:], a.Amount, asset.IssuanceProgram, nil, asset.RawDefinitionByte)
+ // 1. arguments will be set when materializeWitnesses
+ // 2. need to fill in issuance program here
+ txin := types.NewCrossChainInput(nil, a.SourceID, *a.AssetId, a.Amount, a.SourcePos, nil, rawDefinitionByte)
+ log.Info("cross-chain input action built")
tplIn := &txbuilder.SigningInstruction{}
- if asset.Signer != nil {
- path := signers.GetBip0032Path(asset.Signer, signers.AssetKeySpace)
- tplIn.AddRawWitnessKeys(asset.Signer.XPubs, path, asset.Signer.Quorum)
- } else if a.Arguments != nil {
- if err := txbuilder.AddContractArgs(tplIn, a.Arguments); err != nil {
- return err
- }
- }
-
- log.Info("Issue action build")
- builder.RestrictMinTime(time.Now())
+ fed := federation.GetFederation()
+ tplIn.AddRawWitnessKeys(fed.XPubs, fed.Path(), fed.Quorum)
+ a.reg.db.Set(sourceKey, []byte("true"))
return builder.AddInput(txin, tplIn)
}
-func (a *issueAction) ActionType() string {
- return "issue"
+func (a *crossInAction) ActionType() string {
+ return "cross_chain_in"
}