-
Notifications
You must be signed in to change notification settings - Fork 664
/
create_subnet_tx.go
150 lines (129 loc) · 4.22 KB
/
create_subnet_tx.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
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
// Copyright (C) 2019-2021, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package platformvm
import (
"fmt"
"time"
"github.com/ava-labs/avalanchego/chains/atomic"
"github.com/ava-labs/avalanchego/ids"
"github.com/ava-labs/avalanchego/snow"
"github.com/ava-labs/avalanchego/utils/crypto"
"github.com/ava-labs/avalanchego/vms/components/avax"
"github.com/ava-labs/avalanchego/vms/secp256k1fx"
)
var _ UnsignedDecisionTx = &UnsignedCreateSubnetTx{}
// UnsignedCreateSubnetTx is an unsigned proposal to create a new subnet
type UnsignedCreateSubnetTx struct {
// Metadata, inputs and outputs
BaseTx `serialize:"true"`
// Who is authorized to manage this subnet
Owner Owner `serialize:"true" json:"owner"`
}
// InputUTXOs for [DecisionTxs] will return an empty set to diffrentiate from the [AtomicTxs] input UTXOs
func (tx *UnsignedCreateSubnetTx) InputUTXOs() ids.Set { return nil }
func (tx *UnsignedCreateSubnetTx) AtomicOperations() (ids.ID, *atomic.Requests, error) {
return ids.ID{}, nil, nil
}
// InitCtx sets the FxID fields in the inputs and outputs of this
// [UnsignedCreateSubnetTx]. Also sets the [ctx] to the given [vm.ctx] so that
// the addresses can be json marshalled into human readable format
func (tx *UnsignedCreateSubnetTx) InitCtx(ctx *snow.Context) {
tx.BaseTx.InitCtx(ctx)
tx.Owner.InitCtx(ctx)
}
// SyntacticVerify verifies that this transaction is well-formed
func (tx *UnsignedCreateSubnetTx) SyntacticVerify(ctx *snow.Context) error {
switch {
case tx == nil:
return errNilTx
case tx.syntacticallyVerified: // already passed syntactic verification
return nil
}
if err := tx.BaseTx.SyntacticVerify(ctx); err != nil {
return err
}
if err := tx.Owner.Verify(); err != nil {
return err
}
tx.syntacticallyVerified = true
return nil
}
// Attempts to verify this transaction with the provided state.
func (tx *UnsignedCreateSubnetTx) SemanticVerify(vm *VM, parentState MutableState, stx *Tx) error {
vs := newVersionedState(
parentState,
parentState.CurrentStakerChainState(),
parentState.PendingStakerChainState(),
)
_, err := tx.Execute(vm, vs, stx)
return err
}
// Execute this transaction.
func (tx *UnsignedCreateSubnetTx) Execute(
vm *VM,
vs VersionedState,
stx *Tx,
) (
func() error,
error,
) {
// Make sure this transaction is well formed.
if err := tx.SyntacticVerify(vm.ctx); err != nil {
return nil, err
}
// Verify the flowcheck
timestamp := vs.GetTimestamp()
createSubnetTxFee := vm.getCreateSubnetTxFee(timestamp)
if err := vm.semanticVerifySpend(vs, tx, tx.Ins, tx.Outs, stx.Creds, createSubnetTxFee, vm.ctx.AVAXAssetID); err != nil {
return nil, err
}
// Consume the UTXOS
consumeInputs(vs, tx.Ins)
// Produce the UTXOS
txID := tx.ID()
produceOutputs(vs, txID, vm.ctx.AVAXAssetID, tx.Outs)
// Attempt to the new chain to the database
vs.AddSubnet(stx)
return nil, nil
}
// [controlKeys] must be unique. They will be sorted by this method.
// If [controlKeys] is nil, [tx.Controlkeys] will be an empty list.
func (vm *VM) newCreateSubnetTx(
threshold uint32, // [threshold] of [ownerAddrs] needed to manage this subnet
ownerAddrs []ids.ShortID, // control addresses for the new subnet
keys []*crypto.PrivateKeySECP256K1R, // pay the fee
changeAddr ids.ShortID, // Address to send change to, if there is any
) (*Tx, error) {
timestamp := vm.internalState.GetTimestamp()
createSubnetTxFee := vm.getCreateSubnetTxFee(timestamp)
ins, outs, _, signers, err := vm.stake(keys, 0, createSubnetTxFee, changeAddr)
if err != nil {
return nil, fmt.Errorf("couldn't generate tx inputs/outputs: %w", err)
}
// Sort control addresses
ids.SortShortIDs(ownerAddrs)
// Create the tx
utx := &UnsignedCreateSubnetTx{
BaseTx: BaseTx{BaseTx: avax.BaseTx{
NetworkID: vm.ctx.NetworkID,
BlockchainID: vm.ctx.ChainID,
Ins: ins,
Outs: outs,
}},
Owner: &secp256k1fx.OutputOwners{
Threshold: threshold,
Addrs: ownerAddrs,
},
}
tx := &Tx{UnsignedTx: utx}
if err := tx.Sign(Codec, signers); err != nil {
return nil, err
}
return tx, utx.SyntacticVerify(vm.ctx)
}
func (vm *VM) getCreateSubnetTxFee(t time.Time) uint64 {
if t.Before(vm.ApricotPhase3Time) {
return vm.CreateAssetTxFee
}
return vm.CreateSubnetTxFee
}