-
Notifications
You must be signed in to change notification settings - Fork 969
/
OperationFrame.cpp
169 lines (150 loc) · 5.03 KB
/
OperationFrame.cpp
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
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
// Copyright 2014 Stellar Development Foundation and contributors. Licensed
// under the Apache License, Version 2.0. See the COPYING file at the root
// of this distribution or at http://www.apache.org/licenses/LICENSE-2.0
#include "util/asio.h"
#include "OperationFrame.h"
#include "main/Application.h"
#include "xdrpp/marshal.h"
#include <string>
#include "util/Logging.h"
#include "ledger/LedgerDelta.h"
#include "transactions/TransactionFrame.h"
#include "transactions/AllowTrustOpFrame.h"
#include "transactions/CreateAccountOpFrame.h"
#include "transactions/ManageOfferOpFrame.h"
#include "transactions/CreatePassiveOfferOpFrame.h"
#include "transactions/ChangeTrustOpFrame.h"
#include "transactions/InflationOpFrame.h"
#include "transactions/MergeOpFrame.h"
#include "transactions/PathPaymentOpFrame.h"
#include "transactions/PaymentOpFrame.h"
#include "transactions/SetOptionsOpFrame.h"
#include "transactions/ManageDataOpFrame.h"
#include "database/Database.h"
#include "medida/meter.h"
#include "medida/metrics_registry.h"
namespace stellar
{
using namespace std;
shared_ptr<OperationFrame>
OperationFrame::makeHelper(Operation const& op, OperationResult& res,
TransactionFrame& tx)
{
switch (op.body.type())
{
case CREATE_ACCOUNT:
return shared_ptr<OperationFrame>(
new CreateAccountOpFrame(op, res, tx));
case PAYMENT:
return shared_ptr<OperationFrame>(new PaymentOpFrame(op, res, tx));
case PATH_PAYMENT:
return shared_ptr<OperationFrame>(new PathPaymentOpFrame(op, res, tx));
case MANAGE_OFFER:
return shared_ptr<OperationFrame>(new ManageOfferOpFrame(op, res, tx));
case CREATE_PASSIVE_OFFER:
return shared_ptr<OperationFrame>(
new CreatePassiveOfferOpFrame(op, res, tx));
case SET_OPTIONS:
return shared_ptr<OperationFrame>(new SetOptionsOpFrame(op, res, tx));
case CHANGE_TRUST:
return shared_ptr<OperationFrame>(new ChangeTrustOpFrame(op, res, tx));
case ALLOW_TRUST:
return shared_ptr<OperationFrame>(new AllowTrustOpFrame(op, res, tx));
case ACCOUNT_MERGE:
return shared_ptr<OperationFrame>(new MergeOpFrame(op, res, tx));
case INFLATION:
return shared_ptr<OperationFrame>(new InflationOpFrame(op, res, tx));
case MANAGE_DATA:
return shared_ptr<OperationFrame>(new ManageDataOpFrame(op, res, tx));
default:
ostringstream err;
err << "Unknown Tx type: " << op.body.type();
throw std::invalid_argument(err.str());
}
}
OperationFrame::OperationFrame(Operation const& op, OperationResult& res,
TransactionFrame& parentTx)
: mOperation(op), mParentTx(parentTx), mResult(res)
{
}
bool
OperationFrame::apply(SignatureChecker& signatureChecker, LedgerDelta& delta, Application& app)
{
bool res;
res = checkValid(signatureChecker, app, &delta);
if (res)
{
res = doApply(app, delta, app.getLedgerManager());
}
return res;
}
int32_t
OperationFrame::getNeededThreshold() const
{
return mSourceAccount->getMediumThreshold();
}
bool
OperationFrame::checkSignature(SignatureChecker& signatureChecker) const
{
return mParentTx.checkSignature(signatureChecker, *mSourceAccount, getNeededThreshold());
}
AccountID const&
OperationFrame::getSourceID() const
{
return mOperation.sourceAccount ? *mOperation.sourceAccount
: mParentTx.getEnvelope().tx.sourceAccount;
}
bool
OperationFrame::loadAccount(LedgerDelta* delta, Database& db)
{
mSourceAccount = mParentTx.loadAccount(delta, db, getSourceID());
return !!mSourceAccount;
}
OperationResultCode
OperationFrame::getResultCode() const
{
return mResult.code();
}
// called when determining if we should accept this operation.
// called when determining if we should flood
// make sure sig is correct
// verifies that the operation is well formed (operation specific)
bool
OperationFrame::checkValid(SignatureChecker& signatureChecker, Application& app, LedgerDelta* delta)
{
bool forApply = (delta != nullptr);
if (!loadAccount(delta, app.getDatabase()))
{
if (forApply || !mOperation.sourceAccount)
{
app.getMetrics()
.NewMeter({"operation", "invalid", "no-account"}, "operation")
.Mark();
mResult.code(opNO_ACCOUNT);
return false;
}
else
{
mSourceAccount =
AccountFrame::makeAuthOnlyAccount(*mOperation.sourceAccount);
}
}
if (!checkSignature(signatureChecker))
{
app.getMetrics()
.NewMeter({"operation", "invalid", "bad-auth"}, "operation")
.Mark();
mResult.code(opBAD_AUTH);
return false;
}
if (!forApply)
{
// safety: operations should not rely on ledger state as
// previous operations may change it (can even create the account)
mSourceAccount.reset();
}
mResult.code(opINNER);
mResult.tr().type(mOperation.body.type());
return doCheckValid(app);
}
}