Skip to content

Commit e061194

Browse files
committed
Only ascii alphanumeric in tokens after v1
1 parent 518baa9 commit e061194

File tree

11 files changed

+450
-52
lines changed

11 files changed

+450
-52
lines changed

chainstate/src/detail/block_checking.rs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
use super::Chainstate;
1717
use crate::{BlockError, TransactionVerificationStrategy};
1818
use chainstate_storage::BlockchainStorage;
19+
use chainstate_types::PropertyQueryError;
1920
use common::{
2021
chain::{block::signed_block_header::SignedBlockHeader, Block},
2122
primitives::id::WithId,
@@ -36,7 +37,17 @@ impl<'a, S: BlockchainStorage, V: TransactionVerificationStrategy> BlockChecker<
3637
block: WithId<Block>,
3738
) -> Result<WithId<Block>, BlockError> {
3839
let chainstate_ref = self.chainstate.make_db_tx_ro().map_err(BlockError::from)?;
39-
chainstate_ref.check_block(&block).log_err()?;
40+
let prev_block_id = block.prev_block_id();
41+
let parent_height = chainstate_ref
42+
.get_gen_block_index(&prev_block_id)
43+
.map_err(|e| BlockError::BlockIndexQueryError(prev_block_id, e))?
44+
.ok_or(BlockError::BlockIndexQueryError(
45+
prev_block_id,
46+
PropertyQueryError::BlockIndexNotFound(prev_block_id),
47+
))?
48+
.block_height();
49+
50+
chainstate_ref.check_block(&block, parent_height.next_height()).log_err()?;
4051
Ok(block)
4152
}
4253

chainstate/src/detail/chainstateref/mod.rs

Lines changed: 32 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -740,7 +740,11 @@ impl<'a, S: BlockchainStorageRead, V: TransactionVerificationStrategy> Chainstat
740740
Ok(())
741741
}
742742

743-
fn check_tokens_txs(&self, block: &Block) -> Result<(), CheckBlockTransactionsError> {
743+
fn check_tokens_txs(
744+
&self,
745+
block: &Block,
746+
block_height: BlockHeight,
747+
) -> Result<(), CheckBlockTransactionsError> {
744748
for tx in block.transactions() {
745749
// We can't issue multiple tokens in a single tx
746750
let issuance_count = get_tokens_issuance_count(tx.outputs());
@@ -767,29 +771,32 @@ impl<'a, S: BlockchainStorageRead, V: TransactionVerificationStrategy> Chainstat
767771
token_data,
768772
tx.transaction(),
769773
block.get_id(),
774+
block_height,
770775
)?;
771776
}
772777
Ok(())
773778
}
774779
TxOutput::TokensOp(token_output) => match token_output {
775780
TokenOutput::IssueFungibleToken(issuance) => {
776-
check_tokens_issuance(self.chain_config, issuance).map_err(|e| {
777-
TokensError::IssueError(
778-
e,
779-
tx.transaction().get_id(),
780-
block.get_id(),
781-
)
782-
})
783-
}
784-
TokenOutput::IssueNft(_, issuance, _) => match issuance.as_ref() {
785-
NftIssuance::V0(data) => {
786-
check_nft_issuance_data(self.chain_config, data).map_err(|e| {
781+
check_tokens_issuance(self.chain_config, block_height, issuance)
782+
.map_err(|e| {
787783
TokensError::IssueError(
788784
e,
789785
tx.transaction().get_id(),
790786
block.get_id(),
791787
)
792788
})
789+
}
790+
TokenOutput::IssueNft(_, issuance, _) => match issuance.as_ref() {
791+
NftIssuance::V0(data) => {
792+
check_nft_issuance_data(self.chain_config, block_height, data)
793+
.map_err(|e| {
794+
TokensError::IssueError(
795+
e,
796+
tx.transaction().get_id(),
797+
block.get_id(),
798+
)
799+
})
793800
}
794801
},
795802
},
@@ -826,11 +833,15 @@ impl<'a, S: BlockchainStorageRead, V: TransactionVerificationStrategy> Chainstat
826833
Ok(())
827834
}
828835

829-
fn check_transactions(&self, block: &Block) -> Result<(), CheckBlockTransactionsError> {
836+
fn check_transactions(
837+
&self,
838+
block: &Block,
839+
block_height: BlockHeight,
840+
) -> Result<(), CheckBlockTransactionsError> {
830841
// Note: duplicate txs are detected through duplicate inputs
831842
self.check_witness_count(block).log_err()?;
832843
self.check_duplicate_inputs(block).log_err()?;
833-
self.check_tokens_txs(block).log_err()?;
844+
self.check_tokens_txs(block, block_height).log_err()?;
834845
self.check_no_signature_size(block).log_err()?;
835846
Ok(())
836847
}
@@ -842,7 +853,11 @@ impl<'a, S: BlockchainStorageRead, V: TransactionVerificationStrategy> Chainstat
842853
self.db_tx.get_block(*block_index.block_id()).log_err()
843854
}
844855

845-
pub fn check_block(&self, block: &WithId<Block>) -> Result<(), CheckBlockError> {
856+
pub fn check_block(
857+
&self,
858+
block: &WithId<Block>,
859+
block_height: BlockHeight,
860+
) -> Result<(), CheckBlockError> {
846861
self.check_block_header(block.header()).log_err()?;
847862

848863
self.check_block_size(block)
@@ -874,7 +889,7 @@ impl<'a, S: BlockchainStorageRead, V: TransactionVerificationStrategy> Chainstat
874889
);
875890
}
876891

877-
self.check_transactions(block)
892+
self.check_transactions(block, block_height)
878893
.map_err(CheckBlockError::CheckTransactionFailed)
879894
.log_err()?;
880895

@@ -1164,7 +1179,7 @@ impl<'a, S: BlockchainStorageWrite, V: TransactionVerificationStrategy> Chainsta
11641179
);
11651180

11661181
if new_tip_status.last_valid_stage() < BlockValidationStage::CheckBlockOk {
1167-
self.check_block(new_tip)?;
1182+
self.check_block(new_tip, new_tip_block_index.block_height())?;
11681183
new_tip_status.advance_validation_stage_to(BlockValidationStage::CheckBlockOk);
11691184
}
11701185

chainstate/src/detail/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -330,7 +330,7 @@ impl<S: BlockchainStorage, V: TransactionVerificationStrategy> Chainstate<S, V>
330330
) -> Result<bool, BlockIntegrationError> {
331331
let mut block_status = BlockStatus::new();
332332

333-
let result = chainstate_ref.check_block(block);
333+
let result = chainstate_ref.check_block(block, block_index.block_height());
334334
if result.is_err() {
335335
// TODO: "technical" errors (e.g. a DB error) should not lead to permanent
336336
// block invalidation. The same applies to the other unconditional

chainstate/src/detail/tokens/check_utils.rs

Lines changed: 79 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,21 @@
1313
// See the License for the specific language governing permissions and
1414
// limitations under the License.
1515

16-
use common::chain::ChainConfig;
16+
use common::{
17+
chain::{tokens::TokenIssuanceVersion, ChainConfig},
18+
primitives::BlockHeight,
19+
};
1720
use tx_verifier::error::TokenIssuanceError;
1821
use utils::ensure;
1922

2023
fn check_is_text_alphanumeric(str: &[u8]) -> bool {
24+
match String::from_utf8(str.to_vec()) {
25+
Ok(text) => text.chars().all(char::is_alphanumeric),
26+
Err(_) => false,
27+
}
28+
}
29+
30+
fn check_is_text_ascii_alphanumeric(str: &[u8]) -> bool {
2131
match String::from_utf8(str.to_vec()) {
2232
Ok(text) => text.chars().all(|c| c.is_ascii_alphanumeric()),
2333
Err(_) => false,
@@ -53,6 +63,7 @@ pub fn check_media_hash(chain_config: &ChainConfig, hash: &[u8]) -> Result<(), T
5363

5464
pub fn check_token_ticker(
5565
chain_config: &ChainConfig,
66+
current_height: BlockHeight,
5667
ticker: &[u8],
5768
) -> Result<(), TokenIssuanceError> {
5869
// Check length
@@ -62,30 +73,68 @@ pub fn check_token_ticker(
6273
);
6374

6475
// Check is ticker has alphanumeric chars
65-
ensure!(
66-
check_is_text_alphanumeric(ticker),
67-
TokenIssuanceError::IssueErrorTickerHasNoneAlphaNumericChar
68-
);
76+
let tokens_version = chain_config
77+
.chainstate_upgrades()
78+
.version_at_height(current_height)
79+
.1
80+
.token_issuance_version();
81+
82+
match tokens_version {
83+
TokenIssuanceVersion::V0 => {
84+
ensure!(
85+
check_is_text_alphanumeric(ticker),
86+
TokenIssuanceError::IssueErrorTickerHasNoneAlphaNumericChar
87+
);
88+
}
89+
TokenIssuanceVersion::V1 => {
90+
ensure!(
91+
check_is_text_ascii_alphanumeric(ticker),
92+
TokenIssuanceError::IssueErrorTickerHasNoneAlphaNumericChar
93+
);
94+
}
95+
}
96+
6997
Ok(())
7098
}
7199

72-
pub fn check_nft_name(chain_config: &ChainConfig, name: &[u8]) -> Result<(), TokenIssuanceError> {
100+
pub fn check_nft_name(
101+
chain_config: &ChainConfig,
102+
current_height: BlockHeight,
103+
name: &[u8],
104+
) -> Result<(), TokenIssuanceError> {
73105
// Check length
74106
ensure!(
75107
name.len() <= chain_config.token_max_name_len() && !name.is_empty(),
76108
TokenIssuanceError::IssueErrorInvalidNameLength
77109
);
78110

79111
// Check is name has alphanumeric chars
80-
ensure!(
81-
check_is_text_alphanumeric(name),
82-
TokenIssuanceError::IssueErrorNameHasNoneAlphaNumericChar
83-
);
112+
let tokens_version = chain_config
113+
.chainstate_upgrades()
114+
.version_at_height(current_height)
115+
.1
116+
.token_issuance_version();
117+
118+
match tokens_version {
119+
TokenIssuanceVersion::V0 => {
120+
ensure!(
121+
check_is_text_alphanumeric(name),
122+
TokenIssuanceError::IssueErrorNameHasNoneAlphaNumericChar
123+
);
124+
}
125+
TokenIssuanceVersion::V1 => {
126+
ensure!(
127+
check_is_text_ascii_alphanumeric(name),
128+
TokenIssuanceError::IssueErrorNameHasNoneAlphaNumericChar
129+
);
130+
}
131+
}
84132
Ok(())
85133
}
86134

87135
pub fn check_nft_description(
88136
chain_config: &ChainConfig,
137+
current_height: BlockHeight,
89138
description: &[u8],
90139
) -> Result<(), TokenIssuanceError> {
91140
// Check length
@@ -95,9 +144,25 @@ pub fn check_nft_description(
95144
);
96145

97146
// Check is description has alphanumeric chars
98-
ensure!(
99-
check_is_text_alphanumeric(description),
100-
TokenIssuanceError::IssueErrorDescriptionHasNoneAlphaNumericChar
101-
);
147+
let tokens_version = chain_config
148+
.chainstate_upgrades()
149+
.version_at_height(current_height)
150+
.1
151+
.token_issuance_version();
152+
153+
match tokens_version {
154+
TokenIssuanceVersion::V0 => {
155+
ensure!(
156+
check_is_text_alphanumeric(description),
157+
TokenIssuanceError::IssueErrorDescriptionHasNoneAlphaNumericChar
158+
);
159+
}
160+
TokenIssuanceVersion::V1 => {
161+
ensure!(
162+
check_is_text_ascii_alphanumeric(description),
163+
TokenIssuanceError::IssueErrorDescriptionHasNoneAlphaNumericChar
164+
);
165+
}
166+
}
102167
Ok(())
103168
}

chainstate/src/detail/tokens/mod.rs

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ use common::{
2121
tokens::{NftIssuanceV0, TokenData, TokenIssuance, TokenIssuanceV0},
2222
Block, ChainConfig, Transaction,
2323
},
24-
primitives::{Amount, Id, Idable},
24+
primitives::{Amount, BlockHeight, Id, Idable},
2525
};
2626
use serialization::{DecodeAll, Encode};
2727
use tx_verifier::error::TokenIssuanceError;
@@ -33,11 +33,12 @@ use check_utils::{check_nft_description, check_nft_name, check_token_ticker, is_
3333

3434
pub fn check_nft_issuance_data(
3535
chain_config: &ChainConfig,
36+
current_height: BlockHeight,
3637
issuance: &NftIssuanceV0,
3738
) -> Result<(), TokenIssuanceError> {
38-
check_token_ticker(chain_config, &issuance.metadata.ticker)?;
39-
check_nft_name(chain_config, &issuance.metadata.name)?;
40-
check_nft_description(chain_config, &issuance.metadata.description)?;
39+
check_token_ticker(chain_config, current_height, &issuance.metadata.ticker)?;
40+
check_nft_name(chain_config, current_height, &issuance.metadata.name)?;
41+
check_nft_description(chain_config, current_height, &issuance.metadata.description)?;
4142

4243
let icon_uri = Vec::<u8>::decode_all(&mut issuance.metadata.icon_uri.encode().as_slice())
4344
.map_err(|_| TokenIssuanceError::IssueErrorIncorrectIconURI)?;
@@ -84,10 +85,11 @@ pub fn check_nft_issuance_data(
8485

8586
pub fn check_tokens_issuance_data_v0(
8687
chain_config: &ChainConfig,
88+
current_height: BlockHeight,
8789
issuance_data: &TokenIssuanceV0,
8890
) -> Result<(), TokenIssuanceError> {
8991
// Check token ticker
90-
check_token_ticker(chain_config, &issuance_data.token_ticker)?;
92+
check_token_ticker(chain_config, current_height, &issuance_data.token_ticker)?;
9193

9294
// Check amount
9395
ensure!(
@@ -116,12 +118,13 @@ pub fn check_tokens_issuance_data_v0(
116118

117119
pub fn check_tokens_issuance(
118120
chain_config: &ChainConfig,
121+
current_height: BlockHeight,
119122
issuance: &TokenIssuance,
120123
) -> Result<(), TokenIssuanceError> {
121124
match issuance {
122125
TokenIssuance::V1(issuance_data) => {
123126
// Check token ticker
124-
check_token_ticker(chain_config, &issuance_data.token_ticker)?;
127+
check_token_ticker(chain_config, current_height, &issuance_data.token_ticker)?;
125128

126129
// Check decimals
127130
ensure!(
@@ -150,6 +153,7 @@ pub fn check_tokens_data(
150153
token_data: &TokenData,
151154
tx: &Transaction,
152155
source_block_id: Id<Block>,
156+
source_block_height: BlockHeight,
153157
) -> Result<(), TokensError> {
154158
match token_data {
155159
TokenData::TokenTransfer(transfer) => {
@@ -159,9 +163,13 @@ pub fn check_tokens_data(
159163
);
160164
Ok(())
161165
}
162-
TokenData::TokenIssuance(issuance) => check_tokens_issuance_data_v0(chain_config, issuance)
163-
.map_err(|err| TokensError::IssueError(err, tx.get_id(), source_block_id)),
164-
TokenData::NftIssuance(issuance) => check_nft_issuance_data(chain_config, issuance)
165-
.map_err(|err| TokensError::IssueError(err, tx.get_id(), source_block_id)),
166+
TokenData::TokenIssuance(issuance) => {
167+
check_tokens_issuance_data_v0(chain_config, source_block_height, issuance)
168+
.map_err(|err| TokensError::IssueError(err, tx.get_id(), source_block_id))
169+
}
170+
TokenData::NftIssuance(issuance) => {
171+
check_nft_issuance_data(chain_config, source_block_height, issuance)
172+
.map_err(|err| TokensError::IssueError(err, tx.get_id(), source_block_id))
173+
}
166174
}
167175
}

0 commit comments

Comments
 (0)