Compare commits

...

30 Commits

Author SHA1 Message Date
taw1313
1a25eda598
Community wip 2022 (#334)
* update tools script

* update community docs
2022-07-26 13:56:26 -06:00
David Rigby
495130a40f
Merge pull request #332 from dragonchain/txn-type-fix
check for null object
2021-11-30 23:38:36 +00:00
DRigby26
a7151a6520 removes log 2021-11-30 12:38:29 -08:00
DRigby26
a184a850a9 check for null object 2021-06-15 14:13:22 -07:00
Alex Benedetto
a1a8bb887b
Merge pull request #327 from dragonchain/object-storage-change
Increase block size by storing payloads in separate file
2020-11-19 11:25:51 -08:00
Alex Benedetto
4579be1fcd store payloads in separate file and fixed worker issue where long queries result in replay attack error 2020-11-19 10:58:53 -08:00
Alex Benedetto
24a28ac609 Fixed bug in re-indexing 2020-07-24 08:33:27 -07:00
Alex Benedetto
0d3fb63500
Querying interchain broadcast bug fix with UUID chain ID (#324)
* bug fix for querying redisearch with a UUID chain ID instead of public key
2020-07-23 13:40:23 -07:00
Alex Benedetto
0f60f78115 remove drop index 2020-07-22 16:55:39 -07:00
Adam
eb432480e9
update dependencies (#323) 2020-07-21 01:36:28 +00:00
Alex Benedetto
34d34e344b
Merge pull request #322 from dragonchain/verification-redisearch-index
Subsequent L5 verification search
2020-07-20 12:28:41 -07:00
Alex Benedetto
53ba26d629 add new endpoint for querying subsequent interchain transactions 2020-07-20 12:20:52 -07:00
Adam
5ae03cc0b2
Merge pull request #320 from cheeseandcereal/update_dependencies
update dependencies
2020-06-19 14:07:38 -07:00
Adam Crowder
f1d7a88b48
update dependencies/fix lint errors
Signed-off-by: Adam Crowder <adam@adamcrowder.net>
2020-06-19 14:03:00 -07:00
Adam Crowder
7bf7b756e0
update dependencies
Signed-off-by: Adam Crowder <adam@adamcrowder.net>
2020-06-01 22:46:11 -07:00
David Rigby
b817ea1de6
Merge pull request #319 from dragonchain/block-level-fix
check current level for -1
2020-06-01 09:37:56 -07:00
DavidR
0aa8658c40 fix 2020-06-01 09:23:56 -07:00
David Rigby
cbd7f0dea8
Update dragonchain/broadcast_processor/broadcast_processor.py
Co-authored-by: Alex Benedetto <alex061994@gmail.com>
2020-05-29 15:40:22 -07:00
DavidR
d3f1f808dc replaced break with continue 2020-05-29 15:38:02 -07:00
DavidR
7855f47432 removed bad f strings 2020-05-29 15:30:32 -07:00
DavidR
9cc1439227 updated readme 2020-05-29 14:23:25 -07:00
DavidR
7d3f59d756 added break to if statements 2020-05-29 14:19:36 -07:00
DavidR
9f84f21f6c check current level for -1 2020-05-29 14:03:10 -07:00
Adam
55b6fe4256
update various dependencies and containers (#318) 2020-03-19 12:06:46 -07:00
Adam
9103ee4c42
update dependencies (#317)
* update dependencies and typing for web3

* update dependency containers
2020-03-04 12:45:01 -08:00
Adam
8e68babfd7
update dependencies (#316) 2020-02-24 15:14:55 -08:00
Adam
6dc803cb27
update dependencies (#315) 2020-02-20 09:42:31 -08:00
Adam
f7e2227791
bump dependencies (#314)
* bump dependencies
2020-02-18 10:19:43 -08:00
Adam
2be3d2bcd3
update dependencies (#313) 2020-02-12 18:59:18 +00:00
Adam
364fe2ee05
version bumps (#312) 2020-02-05 21:10:27 +00:00
45 changed files with 361 additions and 142 deletions

1
.gitignore vendored
View File

@ -11,6 +11,7 @@ coverage.xml
.envrc
.direnv
.venv
venv
# Installer logs
pip-log.txt

View File

@ -1 +1 @@
4.4.0
4.5.1

24
.vscode/settings.json vendored
View File

@ -1,16 +1,12 @@
{
"files.watcherExclude": {
"**/.mypy_cache": true,
"**/.venv": true
},
"python.linting.flake8Enabled": true,
"python.formatting.provider": "black",
"python.formatting.blackArgs": [
"-l",
"150",
"-t",
"py38"
],
"editor.formatOnSave": true,
"restructuredtext.confPath": "${workspaceFolder}/docs"
"files.watcherExclude": {
"**/.mypy_cache": true,
"**/.venv": true
},
"python.linting.flake8Enabled": true,
"python.formatting.provider": "black",
"python.formatting.blackArgs": ["-l", "150", "-t", "py38"],
"editor.formatOnSave": true,
"restructuredtext.confPath": "${workspaceFolder}/docs",
"cSpell.words": ["Dragonchain"]
}

View File

@ -1,5 +1,26 @@
# Changelog
## 4.5.1
- **Bugs**
- Fixed bug in querying transactions that takes longer than `10s` result in replay attack error
- Fixed bug with retrieving transactions with payloads larger than `1mb` results in S3 Select error `OverMaxRecordSize`
## 4.5.0
- **Feature:**
- Add new endpoint `GET /v1/verifications/interchains/<block_id>` for getting the subsequent interchain broadcasts
- **Packaging:**
- Update web3, docker, bit, requests, fastjsonschema, kubernetes, redis, redisearch, Flask, pycoin, base58, and boto3 dependencies
- Update redisearch in helm chart to 1.6.13
- Update redis in helm chart to 6.0.5
- **Bugs**
- Fixed bug in broadcast processor causing failure when a block cannot be found in redis
- Fixed bug in querying interchain broadcasts when the old L5 chain ID is a UUID and not public key
- Fixed bug in re-indexing of L5 verifications where redisearch throws document exists error
- **Development:**
- Use helm 3.2.4 and yq 3.3.2 for dependency container and lint checking
## 4.4.0
- **Feature:**

View File

@ -17,9 +17,9 @@ RUN python3 -m pip install --no-cache-dir --upgrade -r dev_requirements.txt
# Install Helm for chart linting and/or yq for doc builds if it doesn't exist
RUN if ! command -v helm; then \
wget -O helm-v3.0.2-linux-amd64.tar.gz 'https://get.helm.sh/helm-v3.0.2-linux-amd64.tar.gz' && \
tar xzf helm-v3.0.2-linux-amd64.tar.gz && mv linux-amd64/helm /usr/local/bin/helm && \
rm -rf helm-v3.0.2-linux-amd64.tar.gz linux-amd64; fi && \
wget -O helm-v3.2.4-linux-amd64.tar.gz 'https://get.helm.sh/helm-v3.2.4-linux-amd64.tar.gz' && \
tar xzf helm-v3.2.4-linux-amd64.tar.gz && mv linux-amd64/helm /usr/local/bin/helm && \
rm -rf helm-v3.2.4-linux-amd64.tar.gz linux-amd64; fi && \
if ! command -v yq; then \
wget -O yq 'https://github.com/mikefarah/yq/releases/download/2.4.1/yq_linux_amd64' && \
wget -O yq 'https://github.com/mikefarah/yq/releases/download/3.3.2/yq_linux_amd64' && \
chmod +x yq && mv yq /usr/local/bin/; fi

View File

@ -17,9 +17,9 @@ RUN python3 -m pip install --no-cache-dir --upgrade -r dev_requirements.txt
# Install Helm for chart linting and/or yq for doc builds if it doesn't exist
RUN if ! command -v helm; then \
wget -O helm-v3.0.2-linux-arm64.tar.gz 'https://get.helm.sh/helm-v3.0.2-linux-arm64.tar.gz' && \
tar xzf helm-v3.0.2-linux-arm64.tar.gz && mv linux-arm64/helm /usr/local/bin/helm && \
rm -rf helm-v3.0.2-linux-arm64.tar.gz linux-arm64; fi && \
wget -O helm-v3.2.4-linux-arm64.tar.gz 'https://get.helm.sh/helm-v3.2.4-linux-arm64.tar.gz' && \
tar xzf helm-v3.2.4-linux-arm64.tar.gz && mv linux-arm64/helm /usr/local/bin/helm && \
rm -rf helm-v3.2.4-linux-arm64.tar.gz linux-arm64; fi && \
if ! command -v yq; then \
wget -O yq 'https://github.com/mikefarah/yq/releases/download/2.4.1/yq_linux_arm64' && \
wget -O yq 'https://github.com/mikefarah/yq/releases/download/3.3.2/yq_linux_arm64' && \
chmod +x yq && mv yq /usr/local/bin/; fi

View File

@ -17,11 +17,11 @@ RUN python3 -m pip install --no-cache-dir --upgrade -r dev_requirements.txt
# Install Helm for chart linting and/or yq for doc builds if it doesn't exist
RUN if ! command -v helm; then \
wget -O helm-v3.0.2-linux-amd64.tar.gz 'https://get.helm.sh/helm-v3.0.2-linux-amd64.tar.gz' && \
tar xzf helm-v3.0.2-linux-amd64.tar.gz && mv linux-amd64/helm /usr/local/bin/helm && \
rm -rf helm-v3.0.2-linux-amd64.tar.gz linux-amd64; fi && \
wget -O helm-v3.2.4-linux-amd64.tar.gz 'https://get.helm.sh/helm-v3.2.4-linux-amd64.tar.gz' && \
tar xzf helm-v3.2.4-linux-amd64.tar.gz && mv linux-amd64/helm /usr/local/bin/helm && \
rm -rf helm-v3.2.4-linux-amd64.tar.gz linux-amd64; fi && \
if ! command -v yq; then \
wget -O yq 'https://github.com/mikefarah/yq/releases/download/2.4.1/yq_linux_amd64' && \
wget -O yq 'https://github.com/mikefarah/yq/releases/download/3.3.2/yq_linux_amd64' && \
chmod +x yq && mv yq /usr/local/bin/; fi
# Copy our actual application

View File

@ -17,11 +17,11 @@ RUN python3 -m pip install --no-cache-dir --upgrade -r dev_requirements.txt
# Install Helm for chart linting and/or yq for doc builds if it doesn't exist
RUN if ! command -v helm; then \
wget -O helm-v3.0.2-linux-arm64.tar.gz 'https://get.helm.sh/helm-v3.0.2-linux-arm64.tar.gz' && \
tar xzf helm-v3.0.2-linux-arm64.tar.gz && mv linux-arm64/helm /usr/local/bin/helm && \
rm -rf helm-v3.0.2-linux-arm64.tar.gz linux-arm64; fi && \
wget -O helm-v3.2.4-linux-arm64.tar.gz 'https://get.helm.sh/helm-v3.2.4-linux-arm64.tar.gz' && \
tar xzf helm-v3.2.4-linux-arm64.tar.gz && mv linux-arm64/helm /usr/local/bin/helm && \
rm -rf helm-v3.2.4-linux-arm64.tar.gz linux-arm64; fi && \
if ! command -v yq; then \
wget -O yq 'https://github.com/mikefarah/yq/releases/download/2.4.1/yq_linux_arm64' && \
wget -O yq 'https://github.com/mikefarah/yq/releases/download/3.3.2/yq_linux_arm64' && \
chmod +x yq && mv yq /usr/local/bin/; fi
# Copy our actual application

View File

@ -72,7 +72,7 @@ Once the values are set, install the helm chart with:
```sh
helm repo add dragonchain https://dragonchain-charts.s3.amazonaws.com
helm repo update
helm upgrade --install my-dragonchain --values opensource-config.yaml --namespace dragonchain dragonchain/dragonchain-k8s --version 1.0.8
helm upgrade --install my-dragonchain --values opensource-config.yaml --namespace dragonchain dragonchain/dragonchain-k8s --version 1.0.9
```
If you need to change any values AFTER the helm chart has already been

View File

@ -1,18 +1,9 @@
# Community
Dragonchain has a slack for technical discussion and support.
If you need technical support please email info@dragonchain.com.
We highly recommend joining if you want to participate in technical discussion
to try to understand or contribute to dragonchain, or need technical support.
For general Dragonchain (company/business) chat please join us in the [Dragonchain Lair](https://den.social/l/Dragonchain/) on Den.social.
Please note that this slack is for technical purposes only, and not general
Dragonchain (company/business) chat. For that, please use the
[Dragonchain Telegram](https://t.me/dragontalk).
## More Information
## Form
If you are interested in joining this slack, please fill out
[this form](https://forms.gle/ec7sACnfnpLCv6tXA).
After submitting the form, we will review the application and send an
invitation via email.
More information about Dragonchain [can be found here](https://docs.dragonchain.com/).

View File

@ -99,7 +99,7 @@ their operation type, and whether or not their endpoint permission object has a
custom schema:
| API Resource | Endpoint Name | Operation Type | Endpoint Schema |
| ------------------- | -------------------------------------- | -------------- | --------------- |
|---------------------|----------------------------------------|----------------|-----------------|
| `api_keys` | `create_api_key` | `create` | default |
| `api_keys` | `get_api_key` | `read` | default |
| `api_keys` | `list_api_keys` | `read` | default |
@ -136,6 +136,7 @@ custom schema:
| `transactions` | `get_transaction` | `read` | default |
| `verifications` | `get_verifications` | `read` | default |
| `verifications` | `get_pending_verifications` | `read` | default |
| `verifications` | `query_interchain_verifications` | `read` | default |
### Custom Endpoint Permissions

View File

@ -208,7 +208,7 @@ def schedule_notification_for_broadcast_sync(notification_location: str) -> None
def verification_storage_location(l1_block_id: str, level_received_from: int, chain_id: str) -> str:
""" Format the path for the storage of a verification object
"""Format the path for the storage of a verification object
Args:
l1_block_id: the id of the L1 block which this verification verifies
level_received_from: the level from which this verification was received

View File

@ -199,7 +199,7 @@ async def process_verification_notifications(session: aiohttp.ClientSession) ->
async def send_notification_verification(
session: aiohttp.ClientSession, url: str, verification_bytes: bytes, signature: str, redis_list_value: str
) -> None:
""" Send a notification verification to a preconfigured address
"""Send a notification verification to a preconfigured address
This is the actual async broadcast of a single notification at its most atomic
@ -223,7 +223,7 @@ async def send_notification_verification(
)
_log.debug(f"Notification <- {resp.status} {url}")
except Exception:
_log.exception(f"Unable to send verification notification.")
_log.exception("Unable to send verification notification.")
await broadcast_functions.remove_notification_verification_for_broadcast_async(redis_list_value)
@ -245,6 +245,9 @@ async def process_blocks_for_broadcast(session: aiohttp.ClientSession) -> None:
for block_id, score in await broadcast_functions.get_blocks_to_process_for_broadcast_async():
_log.info(f"[BROADCAST PROCESSOR] Checking block {block_id}")
current_level = await broadcast_functions.get_current_block_level_async(block_id)
if current_level == -1:
_log.warning(f"Failed to lookup current level for block {block_id}.")
continue
try:
claim: Any = matchmaking.get_or_create_claim_check(block_id, _requirements)
except exceptions.InsufficientFunds:

View File

@ -285,11 +285,11 @@ class ContractJob(object):
def create_openfaas_secrets(self) -> None:
"""Creates secrets for openfaas functions
Args:
existing_model (obj, optional): The existing model for this contract if action is update
Args:
existing_model (obj, optional): The existing model for this contract if action is update
Returns:
None
Returns:
None
"""
existing_secrets = self.model.existing_secrets or []
@ -320,8 +320,8 @@ class ContractJob(object):
def delete_openfaas_secrets(self) -> None:
"""Deletes secrets for an openfaas function
Returns:
None
Returns:
None
"""
_log.info(f"Deleting OpenFaaS secrets: {self.model.existing_secrets}")
for secret in self.model.existing_secrets:
@ -334,8 +334,8 @@ class ContractJob(object):
def deploy_to_openfaas(self) -> None:
"""Deploy this job's smart contract to OpenFaaS and update the faas_spec
Returns:
None, or throws exceptions.InternalServerError
Returns:
None, or throws exceptions.InternalServerError
"""
_log.info("Deploying to OpenFaaS cluster")
spec = self.get_openfaas_spec()
@ -356,8 +356,8 @@ class ContractJob(object):
def delete_openfaas_function(self) -> None:
"""Delete this job's smart contract in OpenFaaS and remove the faas_spec
Returns:
None, or throws exceptions.InternalServerError
Returns:
None, or throws exceptions.InternalServerError
"""
_log.info("Deleting OpenFaaS function")
response = requests.delete(

View File

@ -356,7 +356,7 @@ def verify_request_authorization( # noqa: C901
# Signature is valid and key is allowed; Return the api key used on success
return auth_key
except Exception:
_log.exception(f"Uncaught exception checking if api key is allowed")
_log.exception("Uncaught exception checking if api key is allowed")
raise exceptions.ActionForbidden(f"This key is not allowed to perform {api_name}")
else:
# HMAC doesn't match

View File

@ -32,7 +32,7 @@ def register_callback(txn_id: str, callback_url: str) -> None:
def fire_if_exists(txn_id: str, transaction_model: transaction_model.TransactionModel) -> None:
""" Fires a callback with a given payload, then removes from redis"""
"""Fires a callback with a given payload, then removes from redis"""
url = redis.hget_sync(CALLBACK_REDIS_KEY, txn_id)
if url is not None:
try:

View File

@ -105,3 +105,9 @@ def insert_block(block: "model.BlockModel") -> None:
# Upload ref
storage.put_object_as_json(f"{FOLDER}/{LAST_CLOSED_KEY}", last_block_ref)
def insert_l5_verification(storage_location: str, block: "model.BlockModel") -> None:
if redisearch.ENABLED:
index_id = storage_location.split("/")[1]
redisearch.put_document(redisearch.Indexes.verification.value, index_id, block.export_as_search_index(), upsert=True)

View File

@ -63,6 +63,7 @@ def store_full_txns(block_model: "l1_block_model.L1BlockModel") -> None:
"""
_log.info("[TRANSACTION DAO] Putting transaction to storage")
storage.put(f"{FOLDER}/{block_model.block_id}", block_model.export_as_full_transactions().encode("utf-8"))
block_model.store_transaction_payloads()
txn_dict: Dict[str, Dict[str, Dict[str, Any]]] = {}
txn_dict[redisearch.Indexes.transaction.value] = {}
# O(N) loop where N = # of txn

View File

@ -114,7 +114,7 @@ def create_new_transaction_type(txn_type_model: transaction_type_model.Transacti
txn_type_dto = txn_type_model.export_as_at_rest()
_log.info(f"Adding transaction index for {txn_type_model.txn_type}")
redisearch.create_transaction_index(txn_type_model.txn_type, txn_type_model.custom_indexes)
_log.debug(f"Queuing for activation")
_log.debug("Queuing for activation")
redis.lpush_sync(QUEUED_TXN_TYPES, txn_type_model.txn_type)
_log.debug(f"Adding the transaction type to storage")
_log.debug("Adding the transaction type to storage")
storage.put_object_as_json(f"{FOLDER}/{txn_type_model.txn_type}", txn_type_dto)

View File

@ -32,9 +32,9 @@ REDIS_ENDPOINT = os.environ["REDIS_ENDPOINT"]
LRU_REDIS_ENDPOINT = os.environ["LRU_REDIS_ENDPOINT"]
REDIS_PORT = int(os.environ["REDIS_PORT"]) or 6379
redis_client: redis.Redis = cast(redis.Redis, None)
redis_client_lru: redis.Redis = cast(redis.Redis, None)
async_redis_client: aioredis.Redis = cast(aioredis.Redis, None)
redis_client = cast(redis.Redis, None)
redis_client_lru = cast(redis.Redis, None)
async_redis_client = cast(aioredis.Redis, None)
def _set_redis_client_if_necessary() -> None:
@ -396,4 +396,4 @@ def hexists_sync(name: str, key: str) -> bool:
def zadd_sync(name: str, mapping: Dict[str, int], nx: bool = False, xx: bool = False, ch: bool = False, incr: bool = False) -> int:
_set_redis_client_if_necessary()
return redis_client.zadd(name, mapping, nx=nx, xx=xx, ch=ch, incr=incr)
return redis_client.zadd(name, mapping, nx=nx, xx=xx, ch=ch, incr=incr) # noqa: T484

View File

@ -44,15 +44,19 @@ if TYPE_CHECKING:
_log = logger.get_logger()
BROADCAST_ENABLED = os.environ["BROADCAST"].lower() != "false"
LEVEL = os.environ["LEVEL"]
ENABLED = not (LEVEL != "1" and os.environ.get("USE_REDISEARCH") == "false")
if ENABLED:
REDISEARCH_ENDPOINT = os.environ["REDISEARCH_ENDPOINT"]
REDIS_PORT = int(os.environ["REDIS_PORT"]) or 6379
INDEX_L5_VERIFICATION_GENERATION_KEY = "dc:l5_index_generation_complete"
INDEX_GENERATION_KEY = "dc:index_generation_complete"
L5_BLOCK_MIGRATION_KEY = "dc:migrations:l5_block"
BLOCK_MIGRATION_KEY = "dc:migrations:block"
TXN_MIGRATION_KEY = "dc:migrations:txn"
L5_NODES = "dc:nodes:l5"
_escape_transformation = str.maketrans(
{
@ -91,6 +95,7 @@ class Indexes(enum.Enum):
block = "bk"
smartcontract = "sc"
transaction = "tx"
verification = "ver"
_redis_connection = None
@ -299,23 +304,69 @@ def generate_indexes_if_necessary() -> None:
"""Initialize redisearch with necessary indexes and fill them from storage if migration has not been marked as complete"""
redisearch_redis_client = _get_redisearch_index_client("").redis
needs_generation = not bool(redisearch_redis_client.get(INDEX_GENERATION_KEY))
needs_l5_generation = not bool(redisearch_redis_client.get(INDEX_L5_VERIFICATION_GENERATION_KEY))
# No-op if indexes are marked as already generated
if not needs_generation:
if not needs_generation and not needs_l5_generation:
return
# Create block index
_log.info("Creating block indexes")
_generate_block_indexes()
# Create indexes for transactions
_log.info("Creating transaction indexes")
_generate_transaction_indexes()
# Create smart contract index
_log.info("Creating smart contract indexes")
_generate_smart_contract_indexes()
# Mark index generation as complete
_log.info("Marking redisearch index generation complete")
redisearch_redis_client.delete(BLOCK_MIGRATION_KEY)
redisearch_redis_client.delete(TXN_MIGRATION_KEY)
redisearch_redis_client.set(INDEX_GENERATION_KEY, "a")
if needs_l5_generation:
# Create L5 verification indexes
_generate_l5_verification_indexes()
# Mark index generation as complete
redisearch_redis_client.delete(L5_BLOCK_MIGRATION_KEY)
redisearch_redis_client.set(INDEX_L5_VERIFICATION_GENERATION_KEY, "a")
if needs_generation:
# Create block index
_log.info("Creating block indexes")
_generate_block_indexes()
# Create indexes for transactions
_log.info("Creating transaction indexes")
_generate_transaction_indexes()
# Create smart contract index
_log.info("Creating smart contract indexes")
_generate_smart_contract_indexes()
# Mark index generation as complete
_log.info("Marking redisearch index generation complete")
redisearch_redis_client.delete(BLOCK_MIGRATION_KEY)
redisearch_redis_client.delete(TXN_MIGRATION_KEY)
redisearch_redis_client.set(INDEX_GENERATION_KEY, "a")
def _generate_l5_verification_indexes() -> None:
client = _get_redisearch_index_client(Indexes.verification.value)
try:
client.create_index(
[
redisearch.NumericField("block_id", sortable=True),
redisearch.NumericField("prev_id", sortable=True),
redisearch.NumericField("timestamp", sortable=True),
redisearch.TagField("dc_id"),
]
)
except redis.exceptions.ResponseError as e:
if not str(e).startswith("Index already exists"): # We don't care if index already exists
raise
_log.info("Listing all blocks in storage")
block_paths = storage.list_objects("BLOCK/")
pattern = re.compile(r"BLOCK\/([0-9]+)-([Ll])5(.*)$")
for block_path in block_paths:
if LEVEL == "1" and BROADCAST_ENABLED and re.search(pattern, block_path):
if not client.redis.sismember(L5_BLOCK_MIGRATION_KEY, block_path):
raw_block = storage.get_json_from_object(block_path)
block = l5_block_model.new_from_at_rest(raw_block)
storage_location = block_path.split("/")[1]
try:
put_document(Indexes.verification.value, storage_location, block.export_as_search_index())
except redis.exceptions.ResponseError as e:
if not str(e).startswith("Document already exists"):
raise
else:
_log.info(f"Document {storage_location} already exists")
client.redis.sadd(L5_NODES, block.dc_id)
client.redis.sadd(L5_BLOCK_MIGRATION_KEY, block_path)
else:
_log.info(f"Skipping already indexed L5 block {block_path}")
def _generate_block_indexes() -> None:

View File

@ -17,7 +17,7 @@
import os
import unittest
from unittest.mock import patch, MagicMock
from unittest.mock import patch, MagicMock, call
import redis
@ -194,6 +194,7 @@ class TestRedisearch(unittest.TestCase):
redisearch._get_redisearch_index_client.assert_any_call("bk")
redisearch._get_redisearch_index_client.assert_any_call("sc")
redisearch._get_redisearch_index_client.assert_any_call("tx")
mock_redis.get.assert_called_once_with("dc:index_generation_complete")
mock_redis.set.assert_called_once()
redisearch._get_redisearch_index_client.assert_any_call("ver")
mock_redis.get.assert_has_calls([call("dc:index_generation_complete"), call("dc:l5_index_generation_complete")])
self.assertEqual(mock_redis.set.call_count, 2)
mock_put_document.assert_called()

View File

@ -112,6 +112,7 @@ ENDPOINT_MAP = {
"get_transaction": _check_default_endpoint_permission,
"get_verifications": _check_default_endpoint_permission,
"get_pending_verifications": _check_default_endpoint_permission,
"query_interchain_verifications": _check_default_endpoint_permission,
}

View File

@ -163,7 +163,7 @@ class BinanceNetwork(model.InterchainModel):
response_rpc = self._call_node_rpc("status", {}).json()
response_api = self._call_node_api("tokens/BNB").json()
if response_rpc.get("error") or response_api.get("error"):
raise exceptions.InterchainConnectionError(f"[BINANCE] Node ping checks failed!")
raise exceptions.InterchainConnectionError("[BINANCE] Node ping checks failed!")
# https://docs.binance.org/api-reference/node-rpc.html#6114-query-tx
def is_transaction_confirmed(self, transaction_hash: str) -> bool:
@ -203,7 +203,7 @@ class BinanceNetwork(model.InterchainModel):
# cannot check HTTP status codes, errors will return 200 :
if response_json.get("error") is not None:
if "interface is nil, not types.NamedAccount" in response_json["error"]["data"] and response.status_code == 500:
_log.warning(f"[BINANCE] Non 200 response from Binance node:")
_log.warning("[BINANCE] Non 200 response from Binance node:")
_log.warning(f"[BINANCE] response code: {response.status_code}")
_log.warning(f"[BINANCE] response error: {response_json['error']['data']}")
_log.warning("[BINANCE] This is actually expected for a zero balance address.")

View File

@ -18,6 +18,7 @@
import base64
from typing import Dict, Any
from eth_typing import URI, ChecksumAddress, HexStr
import secp256k1
import web3
import web3.gas_strategies.time_based
@ -127,6 +128,8 @@ def new_from_at_rest(ethereum_network_at_rest: Dict[str, Any]) -> "EthereumNetwo
class EthereumNetwork(model.InterchainModel):
address: ChecksumAddress
def __init__(self, name: str, rpc_address: str, chain_id: int, b64_private_key: str):
self.blockchain = "ethereum"
self.name = name
@ -134,7 +137,7 @@ class EthereumNetwork(model.InterchainModel):
self.chain_id = chain_id
self.priv_key = eth_keys.keys.PrivateKey(base64.b64decode(b64_private_key))
self.address = self.priv_key.public_key.to_checksum_address()
self.w3 = web3.Web3(web3.HTTPProvider(self.rpc_address))
self.w3 = web3.Web3(web3.HTTPProvider(URI(self.rpc_address)))
# Set gas strategy
self.w3.eth.setGasPriceStrategy(web3.gas_strategies.time_based.medium_gas_price_strategy)
@ -181,12 +184,12 @@ class EthereumNetwork(model.InterchainModel):
"""
_log.info(f"[ETHEREUM] Getting confirmations for {transaction_hash}")
try:
transaction_block_number = self.w3.eth.getTransaction(transaction_hash)["blockNumber"]
transaction_block_number = self.w3.eth.getTransaction(HexStr(transaction_hash))["blockNumber"]
except web3.exceptions.TransactionNotFound:
raise exceptions.TransactionNotFound(f"Transaction {transaction_hash} not found")
latest_block_number = self.get_current_block()
_log.info(f"[ETHEREUM] Latest ethereum block number: {latest_block_number} | Block number of transaction: {transaction_block_number}")
return transaction_block_number and (latest_block_number - transaction_block_number) >= CONFIRMATIONS_CONSIDERED_FINAL
return bool(transaction_block_number) and (latest_block_number - transaction_block_number) >= CONFIRMATIONS_CONSIDERED_FINAL
def check_balance(self) -> int:
"""Check the balance of the address for this network
@ -242,7 +245,7 @@ class EthereumNetwork(model.InterchainModel):
The hex string of the published transaction hash
"""
_log.debug(f"[ETH] Publishing transaction {signed_transaction}")
return self.w3.toHex(self.w3.eth.sendRawTransaction(signed_transaction))
return self.w3.toHex(self.w3.eth.sendRawTransaction(HexStr(signed_transaction)))
def _publish_l5_transaction(self, transaction_payload: str) -> str:
"""Publish a transaction to this network with a certain data payload
@ -268,8 +271,8 @@ class EthereumNetwork(model.InterchainModel):
Returns:
Gas price estimate in wei
"""
_log.debug(f"[ETHEREUM] Getting estimated gas price")
gas_price = max(int(self.w3.eth.generateGasPrice()), 100000000) # Calculate gas price, but set minimum to 0.1 gwei for safety
_log.debug("[ETHEREUM] Getting estimated gas price")
gas_price = max(int(self.w3.eth.generateGasPrice() or 0), 100000000) # Calculate gas price, but set minimum to 0.1 gwei for safety
_log.info(f"[ETHEREUM] Current estimated gas price: {gas_price}")
return gas_price

View File

@ -22,6 +22,7 @@ from typing import Dict, Any, List, Set, TYPE_CHECKING
import fastjsonschema
from dragonchain.lib.interfaces import storage
from dragonchain.lib.dto import transaction_model
from dragonchain.lib.dto import schema
from dragonchain.lib.dto import model
@ -182,6 +183,11 @@ class L1BlockModel(model.BlockModel):
"""Export full transactions in block as NDJSON (for storage select when querying)"""
txn_string = ""
for transaction in self.transactions:
txn_string += '{"txn_id": "' + transaction.txn_id + '", '
txn_string += '{"txn_id": "' + transaction.txn_id + '", "stripped_payload": true, '
txn_string += '"txn": ' + json.dumps(transaction.export_as_full(), separators=(",", ":")) + "}\n"
return txn_string
def store_transaction_payloads(self) -> None:
"""Stores full transaction payloads for block"""
for transaction in self.transactions:
storage.put(f"PAYLOADS/{transaction.txn_id}", json.dumps(transaction.payload, separators=(",", ":")).encode("utf-8"))

View File

@ -16,6 +16,7 @@
# language governing permissions and limitations under the Apache License.
import json
from typing import Dict, Any
import fastjsonschema
@ -29,7 +30,7 @@ _validate_l5_block_at_rest = fastjsonschema.compile(schema.l5_block_at_rest_sche
def new_from_at_rest(block: dict) -> "L5BlockModel":
"""
Used in querying from the DAO
Input: Block::L4::AtRest DTO
Input: Block::L5::AtRest DTO
Returns: BlockModel object
"""
# Validate inputted schema
@ -139,3 +140,12 @@ class L5BlockModel(model.BlockModel):
"l4-blocks": self.l4_blocks,
"proof": proof,
}
def export_as_search_index(self) -> Dict[str, Any]:
"""Export as block search index DTO"""
return {
"block_id": int(self.block_id),
"timestamp": int(self.timestamp),
"prev_id": int(self.prev_id) if self.prev_id else 0,
"dc_id": self.dc_id if self.dc_id else "",
}

View File

@ -106,7 +106,7 @@ transaction_full_schema = {
"payload": {"type": "string"},
"proof": {"type": "object", "properties": {"full": {"type": "string"}, "stripped": {"type": "string"}}, "required": ["full", "stripped"]},
},
"required": ["version", "dcrn", "header", "payload", "proof"],
"required": ["version", "dcrn", "header", "proof"],
}
@ -848,7 +848,11 @@ permission_document_schema_v1 = {
"verifications": {
"type": "object",
"properties": add_crud_default_properties(
{"get_verifications": default_endpoint_property_schema, "get_pending_verifications": default_endpoint_property_schema}
{
"get_verifications": default_endpoint_property_schema,
"get_pending_verifications": default_endpoint_property_schema,
"query_interchain_verifications": default_endpoint_property_schema,
}
),
"additionalProperties": False,
},

View File

@ -164,7 +164,6 @@ class TransactionModel(model.Model):
"tag": self.tag,
"invoker": self.invoker or "",
},
"payload": self.payload,
"proof": {"full": self.full_hash, "stripped": self.signature},
}
@ -234,7 +233,7 @@ class TransactionModel(model.Model):
indexable_object = jsonpath.jsonpath(json_payload, path)
_log.debug(f"indexable_object: {indexable_object}")
# If we found a valid item at the specified indexable path
if indexable_object and isinstance(indexable_object, list) and len(indexable_object) == 1:
if indexable_object and indexable_object[0] and isinstance(indexable_object, list) and len(indexable_object) == 1:
index_item = indexable_object[0]
# Check that the item we extracted is a string for tag or text type custom indexes
if index["type"] == "tag" or index["type"] == "text":

View File

@ -91,7 +91,7 @@ def select_transaction(location: str, block_id: str, txn_id: str) -> dict:
obj = s3.select_object_content(
Bucket=location,
Key=f"TRANSACTION/{block_id}",
Expression=f"select s.txn from s3object s where s.txn_id = '{txn_id}' limit 1", # nosec (this s3 select query is safe)
Expression=f"select s.txn, s.stripped_payload from s3object s where s.txn_id = '{txn_id}' limit 1", # nosec (this s3 select query is safe)
ExpressionType="SQL",
InputSerialization={"JSON": {"Type": "DOCUMENT"}},
OutputSerialization={"JSON": {"RecordDelimiter": "\n"}},
@ -104,7 +104,14 @@ def select_transaction(location: str, block_id: str, txn_id: str) -> dict:
if event.get("Records"):
txn_data = f'{txn_data}{event["Records"]["Payload"].decode("utf-8")}'
if txn_data:
return json.loads(txn_data)["txn"]
loaded_txn = json.loads(txn_data)
if loaded_txn.get("stripped_payload"):
payload_key = f"PAYLOADS/{txn_id}"
if does_object_exist(location, payload_key):
loaded_txn["txn"]["payload"] = json.loads(get(location, payload_key).decode("utf-8"))
else:
loaded_txn["txn"]["payload"] = json.dumps({})
return loaded_txn["txn"]
raise exceptions.NotFound

View File

@ -62,7 +62,7 @@ class TestS3Interface(unittest.TestCase):
mock_select_object_content.assert_called_once_with(
Bucket="loc",
Key="TRANSACTION/block",
Expression="select s.txn from s3object s where s.txn_id = 'txn' limit 1",
Expression="select s.txn, s.stripped_payload from s3object s where s.txn_id = 'txn' limit 1",
ExpressionType="SQL",
InputSerialization={"JSON": {"Type": "DOCUMENT"}},
OutputSerialization={"JSON": {"RecordDelimiter": "\n"}},

View File

@ -100,6 +100,12 @@ def select_transaction(location: str, block_id: str, txn_id: str) -> dict:
try:
loaded_txn = json.loads(transaction)
if loaded_txn["txn_id"] == txn_id:
if loaded_txn.get("stripped_payload"):
payload_key = os.path.join("PAYLOADS", txn_id)
if does_object_exist(location, payload_key):
loaded_txn["txn"]["payload"] = json.loads(get(location, payload_key).decode("utf-8"))
else:
loaded_txn["txn"]["payload"] = json.dumps({})
return loaded_txn["txn"]
except Exception:
_log.exception("Error loading retrieved transaction from disk select_transaction")

View File

@ -191,4 +191,4 @@ class TestStorageInterface(unittest.TestCase):
def test_save_error_message(self, mock_time):
storage.put = MagicMock()
storage.save_error_message("some message")
storage.put.assert_called_once_with(f"error_testing_123.log", b"some message", should_cache=False)
storage.put.assert_called_once_with("error_testing_123.log", b"some message", should_cache=False)

View File

@ -23,7 +23,7 @@ bind = f"0.0.0.0:{os.environ['WEB_PORT']}"
reuse_port = True
backlog = 4000
worker_class = "gevent"
workers = 4
workers = 3
keepalive = 90 # Make sure this is higher than the load balancer/ingress controller tcp keepalive timeout
sendfile = False
accesslog = "-"

View File

@ -27,6 +27,8 @@ from dragonchain.lib.dto import l4_block_model
from dragonchain.lib.dto import l5_block_model
from dragonchain.lib.dto import api_key_model
from dragonchain.lib.dao import api_key_dao
from dragonchain.lib.dao import block_dao
from dragonchain.lib.database import redisearch
from dragonchain.lib import matchmaking
from dragonchain.lib import keys
from dragonchain.lib import queue
@ -89,6 +91,10 @@ def process_receipt_v1(block_dto: Dict[str, Any]) -> None:
_log.exception("matchmaking add_receipt failed!")
# Update the broadcast system about this receipt
broadcast_functions.set_receieved_verification_for_block_from_chain_sync(l1_block_id, level_received_from, block_model.dc_id)
if level_received_from == 5:
client = redisearch._get_redisearch_index_client(redisearch.Indexes.verification.value)
client.redis.sadd(redisearch.L5_NODES, block_model.dc_id)
block_dao.insert_l5_verification(storage_location, block_model)
else:
_log.warning(
f"Chain {block_model.dc_id} (level {level_received_from}) returned a receipt that wasn't expected (possibly expired?) for block {l1_block_id}. Rejecting receipt" # noqa: B950

View File

@ -46,7 +46,7 @@ def get_id_by_txn_type_v1(txn_type: str) -> str:
def list_contracts_v1() -> Dict[str, List[Dict[str, Any]]]:
""" Function used by the smartcontract endpoint with method GET.
"""Function used by the smartcontract endpoint with method GET.
Returns a list of all smart contracts.
Returns:
The search results of the query specified.

View File

@ -14,17 +14,20 @@
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the Apache License for the specific
# language governing permissions and limitations under the Apache License.
from typing import Dict, Union, List, Any, Optional
import re
from typing import Dict, Union, List, Any, Optional, cast
from dragonchain.broadcast_processor import broadcast_functions
from dragonchain.lib.interfaces import storage
from dragonchain.lib.database import redisearch
from dragonchain.lib import matchmaking
from dragonchain import exceptions
from dragonchain import logger
_log = logger.get_logger()
_uuid_regex = re.compile(r"[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}")
def get_pending_verifications_v1(block_id: str) -> Dict[str, List[str]]:
"""Get any scheduled pending verifications"""
@ -50,6 +53,38 @@ def query_verifications_v1(block_id: str, params: Optional[Dict[str, Any]] = Non
return _get_verification_records(block_id, level)
def query_interchain_broadcasts_v1(block_id: str) -> List[Any]:
"""Return the subsequent broadcasts to other L5 networks"""
_log.info(f"Getting subsequent L5 verifications for {block_id}")
results = []
l5_block = None
l5_verifications = _get_verification_records(block_id, 5)
if len(l5_verifications) > 0:
l5_block = cast(List[Any], l5_verifications)[0]
timestamp = l5_block["header"]["timestamp"]
dc_id = l5_block["header"]["dc_id"]
l5_nodes = redisearch._get_redisearch_index_client(redisearch.Indexes.verification.value).redis.smembers(redisearch.L5_NODES)
results = [
_query_l5_verification(l5_dc_id.decode("utf-8"), timestamp)
for l5_dc_id in l5_nodes
if l5_dc_id.decode("utf-8") != dc_id and not re.match(_uuid_regex, l5_dc_id.decode("utf-8"))
]
return ([l5_block] if l5_block else []) + [storage.get_json_from_object(f"BLOCK/{x}") for x in results if x is not None]
def _query_l5_verification(l5_dc_id: str, timestamp: str) -> str:
query_result = redisearch.search(
index=redisearch.Indexes.verification.value,
query_str=f"@dc_id:{{{l5_dc_id}}} @timestamp:[{int(timestamp)+1} +inf]",
only_id=True,
limit=1,
sort_by="timestamp",
sort_asc=True,
)
return query_result.docs[0].id if query_result and len(query_result.docs) > 0 else None
def _get_verification_records(block_id: str, level: int = 0) -> Union[List[Any], Dict[str, List[Any]]]:
if level:
if level in [2, 3, 4, 5]:

View File

@ -14,13 +14,13 @@
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the Apache License for the specific
# language governing permissions and limitations under the Apache License.
import unittest
from unittest.mock import patch, call
from unittest.mock import patch, call, MagicMock
from dragonchain import test_env # noqa: F401
from dragonchain import exceptions
from dragonchain.webserver.lib import verifications
from dragonchain.lib.database import redisearch
class TestVerificationDAO(unittest.TestCase):
@ -76,3 +76,60 @@ class TestVerificationDAO(unittest.TestCase):
def test__all_records_returns_correctly(self, mock_level_records):
self.assertEqual(verifications._all_records(1), {"2": ["return"], "3": ["return"], "4": ["return"], "5": ["return"]})
mock_level_records.assert_has_calls([call(1, 2), call(1, 3), call(1, 4), call(1, 5)])
@patch("dragonchain.lib.database.redisearch.search", return_value=MagicMock(docs=[MagicMock(id="banana")]))
def test__query_l5_verifications_returns_correctly(self, mock_redisearch_search):
self.assertEqual(verifications._query_l5_verification("banana", "123456789"), "banana")
mock_redisearch_search.assert_called_once_with(
index="ver", query_str="@dc_id:{banana} @timestamp:[123456790 +inf]", only_id=True, limit=1, sort_by="timestamp", sort_asc=True
)
@patch("dragonchain.lib.database.redisearch.search", return_value=MagicMock(docs=[]))
def test__query_l5_verifications_returns_correctly_when_no_results_found(self, mock_redisearch_search):
self.assertIsNone(verifications._query_l5_verification("banana", "123456789"))
mock_redisearch_search.assert_called_once_with(
index="ver", query_str="@dc_id:{banana} @timestamp:[123456790 +inf]", only_id=True, limit=1, sort_by="timestamp", sort_asc=True
)
@patch("dragonchain.webserver.lib.verifications._get_verification_records", return_value=[])
def test_query_interchain_broadcasts_v1_returns_correctly_when_block_id_doesnt_exist(self, mock_get_verification_records):
self.assertEqual(verifications.query_interchain_broadcasts_v1("123"), [])
mock_get_verification_records.assert_called_once_with("123", 5)
@patch("dragonchain.webserver.lib.verifications._query_l5_verification", return_value="banana")
@patch(
"dragonchain.webserver.lib.verifications._get_verification_records", return_value=[{"header": {"dc_id": "banana", "timestamp": "12345987"}}]
)
@patch("dragonchain.webserver.lib.verifications.storage.get_json_from_object", return_value="return")
def test_query_interchain_broadcasts_v1_returns_correctly(self, mock_get_object, mock_get_verification_records, mock_query_l5_verifications):
mock_redis = MagicMock(smembers=MagicMock(return_value=[b"mydragonchain"]))
redisearch._get_redisearch_index_client = MagicMock(return_value=MagicMock(redis=mock_redis))
self.assertEqual(verifications.query_interchain_broadcasts_v1("12345"), [{"header": {"dc_id": "banana", "timestamp": "12345987"}}, "return"])
mock_query_l5_verifications.assert_called_once_with("mydragonchain", "12345987")
mock_get_object.assert_called_once_with("BLOCK/banana")
@patch("dragonchain.webserver.lib.verifications._query_l5_verification", return_value=None)
@patch(
"dragonchain.webserver.lib.verifications._get_verification_records", return_value=[{"header": {"dc_id": "banana", "timestamp": "12345987"}}]
)
@patch("dragonchain.webserver.lib.verifications.storage.get_json_from_object")
def test_query_interchain_broadcasts_v1_returns_correctly_when_verification_not_found(
self, mock_get_object, mock_get_verification_records, mock_query_l5_verifications
):
mock_redis = MagicMock(smembers=MagicMock(return_value=[b"mydragonchain"]))
redisearch._get_redisearch_index_client = MagicMock(return_value=MagicMock(redis=mock_redis))
self.assertEqual(verifications.query_interchain_broadcasts_v1("12345"), [{"header": {"dc_id": "banana", "timestamp": "12345987"}}])
mock_query_l5_verifications.assert_called_once_with("mydragonchain", "12345987")
mock_get_object.assert_not_called()
@patch("dragonchain.webserver.lib.verifications._query_l5_verification", return_value=None)
@patch("dragonchain.webserver.lib.verifications._get_verification_records", return_value=[])
@patch("dragonchain.webserver.lib.verifications.storage.get_json_from_object")
def test_query_interchain_broadcasts_v1_returns_correctly_when_block_doesnt_exist(
self, mock_get_object, mock_get_verification_records, mock_query_l5_verifications
):
mock_redis = MagicMock(smembers=MagicMock(return_value=[b"mydragonchain"]))
redisearch._get_redisearch_index_client = MagicMock(return_value=MagicMock(redis=mock_redis))
self.assertEqual(verifications.query_interchain_broadcasts_v1("12345"), [])
mock_query_l5_verifications.assert_not_called()
mock_get_object.assert_not_called()

View File

@ -28,6 +28,7 @@ def apply_routes(app: flask.Flask):
app.add_url_rule("/verifications/<block_id>", "get_verification_v1", get_verification_v1, methods=["GET"])
app.add_url_rule("/v1/verifications/<block_id>", "get_verification_v1", get_verification_v1, methods=["GET"])
app.add_url_rule("/v1/verifications/pending/<block_id>", "get_pending_verifications_v1", get_pending_verifications_v1, methods=["GET"])
app.add_url_rule("/v1/verifications/interchains/<block_id>", "query_l5_verifications_v1", query_l5_verifications_v1, methods=["GET"])
@request_authorizer.Authenticated(api_resource="verifications", api_operation="read", api_name="get_verifications")
@ -39,3 +40,8 @@ def get_verification_v1(block_id: str, **kwargs) -> Tuple[str, int, Dict[str, st
@request_authorizer.Authenticated(api_resource="verifications", api_operation="read", api_name="get_pending_verifications")
def get_pending_verifications_v1(block_id: str, **kwargs) -> Tuple[str, int, Dict[str, str]]:
return helpers.flask_http_response(200, verifications.get_pending_verifications_v1(block_id))
@request_authorizer.Authenticated(api_resource="verifications", api_operation="read", api_name="query_interchain_verifications")
def query_l5_verifications_v1(block_id: str, **kwargs) -> Tuple[str, int, Dict[str, str]]:
return helpers.flask_http_response(200, verifications.query_interchain_broadcasts_v1(block_id))

View File

@ -1,9 +1,9 @@
apiVersion: v1
name: dragonchain-k8s
version: 1.0.8
version: 1.0.9
icon: https://dragonchain-assets.s3.amazonaws.com/jojo.png
description: Dragonchain on kubernetes
appVersion: 4.4.0
appVersion: 4.5.1
keywords:
- dragonchain
- blockchain

View File

@ -2,7 +2,7 @@
[Dragonchain](https://dragonchain.com/) is an enterprise blockchain platform which simplifies the integration of real business applications onto a blockchain.
We recommend visiting [docs.dragonchain.com](https://docs.dragonchain.com/) to get started with using Dragonchain.
We recommend visiting [docs.dragonchain.com](https://docs.dragonchain.com/) to get started with using Dragonchain.
## Information

View File

@ -61,6 +61,17 @@ redisearch:
requests:
cpu: 50m
memory: 300Mi
image:
repository: docker.io/redislabs/redisearch
tag: 1.6.13
storage:
spec:
storageClassName: standard
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
# Webserver configuration
webserver:
@ -142,7 +153,7 @@ dragonchain:
image:
pullPolicy: Always
value: docker.io/dragonchain/dragonchain_core
version: 4.4.0
version: 4.5.1
storage:
spec:
storageClassName: standard
@ -155,20 +166,7 @@ dragonchain:
redis:
image:
repository: docker.io/redis
tag: 5.0.7-alpine
storage:
spec:
storageClassName: standard
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
redisearch:
image:
repository: docker.io/redislabs/redisearch
tag: 1.6.7
tag: 6.0.5-alpine
storage:
spec:
storageClassName: standard

View File

@ -72,7 +72,7 @@ dragonchain:
# -- dragonchain.image.version --
# The tag to use with the dragonchain image
# Check here for available values: https://hub.docker.com/r/dragonchain/dragonchain_core/tags
version: 4.4.0
version: 4.5.1
# -- dragonchain.storage --
# The mount path of a persistent volume to be used by all dragonchain microservices.

View File

@ -1,20 +1,20 @@
boto3==1.11.9
redis==3.4.1
boto3==1.14.24
redis==3.5.3
apscheduler==3.6.3
jsonpath==0.82
Flask==1.1.1
requests==2.22.0
fastjsonschema==2.14.2
Flask==1.1.2
requests==2.24.0
fastjsonschema==2.14.4
secp256k1==0.13.2
web3==5.5.0
kubernetes==10.0.1
docker==4.1.0
web3==5.12.0
kubernetes==11.0.0
docker==4.2.2
gunicorn[gevent]==20.0.4
aiohttp[speedups]==3.6.2
aioredis==1.3.1
base58==2.0.0
bit==0.6.0
redisearch==0.8.3
base58==2.0.1
bit==0.6.2
redisearch==1.0.0
bnb-tx==0.0.4
pycoin==0.90.20190728
pycoin==0.90.20200322
mnemonic==0.19

View File

@ -59,8 +59,17 @@ elif [ "$1" = "bandit" ]; then
elif [ "$1" = "docs" ]; then
rm -rf docs/static/chart && mkdir -p docs/static/chart
cp -v helm/opensource-config.yaml docs/static/chart/
CHART_VERSION="$(yq r helm/dragonchain-k8s/Chart.yaml version)"
sed -i "s/--version [0-9]\\{1,\\}\\.[0-9]\\{1,\\}\\.[0-9]\\{1,\\}/--version $CHART_VERSION/" docs/deployment/deploying.md
######################################
# yq version 3 syntax
######################################
#CHART_VERSION="$(yq r helm/dragonchain-k8s/Chart.yaml version)"
######################################
# yq version 4 syntax
######################################
#NOT WORKING CHART_VERSION="$(yq '.version' helm/dragonchain-k8s/Chart.yaml | head -n 1)"
# use hard coded version
#sed -i '' "s/--version [0-9]\\{1,\\}\\.[0-9]\\{1,\\}\\.[0-9]\\{1,\\}/--version $CHART_VERSION/" docs/deployment/deploying.md
sed -i '' "s/--version [0-9]\\{1,\\}\\.[0-9]\\{1,\\}\\.[0-9]\\{1,\\}/--version 1.0.9/" docs/deployment/deploying.md
(
cd docs || exit 1
make html