import (
"context"
stdjson "encoding/json"
+ "fmt"
"time"
log "github.com/sirupsen/logrus"
- "github.com/vapor/blockchain/signers"
"github.com/vapor/blockchain/txbuilder"
- "github.com/vapor/crypto/ed25519"
- "github.com/vapor/crypto/ed25519/chainkd"
+ "github.com/vapor/consensus/federation"
chainjson "github.com/vapor/encoding/json"
"github.com/vapor/errors"
"github.com/vapor/protocol/bc"
"github.com/vapor/protocol/bc/types"
- "github.com/vapor/protocol/vm/vmutil"
)
// DecodeCrossInAction convert input data to action struct
bc.AssetAmount
SourceID string `json:"source_id"`
SourcePos uint64 `json:"source_pos"`
- FedXPubs []chainkd.XPub `json:"fed_xpubs"`
- Quorum int `json:"fed_quorum"`
AssetDefinition map[string]interface{} `json:"asset_definition"`
}
-// TODO: also need to hard-code mapTx
-// TODO: check setArgs
-// TODO: check replay
func (a *crossInAction) Build(ctx context.Context, builder *txbuilder.TemplateBuilder) error {
var missing []string
- if len(a.FedXPubs) == 0 {
- missing = append(missing, "fed_xpubs")
- }
if a.SourceID == "" {
missing = append(missing, "source_id")
}
return txbuilder.MissingFieldsError(missing...)
}
+ 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 err error
asset := &Asset{}
if preAsset, _ := a.reg.GetAsset(a.AssetId.String()); preAsset != nil {
asset.AssetID = *a.AssetId
extAlias := a.AssetId.String()
asset.Alias = &(extAlias)
- a.reg.SaveExtAsset(asset, extAlias)
- }
-
- assetSigner, err := signers.Create("asset", a.FedXPubs, a.Quorum, 1, signers.BIP0032)
- if err != nil {
- return err
- }
-
- path := signers.GetBip0032Path(assetSigner, signers.AssetKeySpace)
- derivedXPubs := chainkd.DeriveXPubs(assetSigner.XPubs, path)
- derivedPKs := chainkd.XPubKeys(derivedXPubs)
- pegScript, err := buildPegScript(derivedPKs, assetSigner.Quorum)
- if err != nil {
- return err
+ a.reg.SaveExtAsset(asset)
}
var sourceID bc.Hash
return errors.New("invalid sourceID format")
}
- txin := types.NewCrossChainInput(nil, sourceID, *a.AssetId, a.Amount, a.SourcePos, pegScript, asset.RawDefinitionByte)
+ fed := federation.GetFederation()
+ // arguments will be set when materializeWitnesses
+ txin := types.NewCrossChainInput(nil, sourceID, *a.AssetId, a.Amount, a.SourcePos, fed.ControlProgram, asset.RawDefinitionByte)
log.Info("cross-chain input action built")
builder.RestrictMinTime(time.Now())
tplIn := &txbuilder.SigningInstruction{}
- tplIn.AddRawWitnessKeys(assetSigner.XPubs, path, assetSigner.Quorum)
+ tplIn.AddRawWitnessKeys(fed.XPubs, fed.Path, fed.Quorum)
+ a.reg.db.Set(sourceKey, []byte("true"))
return builder.AddInput(txin, tplIn)
}
func (a *crossInAction) ActionType() string {
return "cross_chain_in"
}
-
-func buildPegScript(pubkeys []ed25519.PublicKey, nrequired int) (program []byte, err error) {
- controlProg, err := vmutil.P2SPMultiSigProgram(pubkeys, nrequired)
- if err != nil {
- return nil, err
- }
- builder := vmutil.NewBuilder()
- builder.AddRawBytes(controlProg)
- prog, err := builder.Build()
- return prog, err
-}