Skip to content

Commit a732296

Browse files
Merge pull request #144 from ethscriptions-protocol/fix_collections
Implement Compression and Extraction for Collection JSON Files
2 parents f4d16ea + 035e154 commit a732296

File tree

9 files changed

+123
-8
lines changed

9 files changed

+123
-8
lines changed

.gitignore

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,3 +33,9 @@
3333
/config/master.key
3434

3535
.DS_Store
36+
37+
# Ignore uncompressed collection JSON files (keep only the tar.gz archive)
38+
items_by_ethscription.json
39+
collections_by_name.json
40+
# Keep the compressed archive
41+
# collections_data.tar.gz

Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ RUN chmod +x /usr/local/bin/docker-entrypoint.sh
6464

6565
# Set up non-root user
6666
RUN useradd rails --create-home --shell /bin/bash && \
67-
chown -R rails:rails log tmp storage db config
67+
chown -R rails:rails /rails
6868
USER rails:rails
6969

7070
# Database initialization moved to runtime in entrypoint script

app/models/erc721_ethscriptions_collection_parser.rb

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
require 'zlib'
2+
require 'rubygems/package'
3+
14
# Strict parser for the ERC-721 Ethscriptions collection protocol with canonical JSON validation
25
class Erc721EthscriptionsCollectionParser
36
# Default return for invalid input
@@ -125,6 +128,7 @@ class ValidationError < StandardError; end
125128

126129
DEFAULT_ITEMS_PATH = ENV['COLLECTIONS_ITEMS_PATH'] || Rails.root.join('items_by_ethscription.json')
127130
DEFAULT_COLLECTIONS_PATH = ENV['COLLECTIONS_META_PATH'] || Rails.root.join('collections_by_name.json')
131+
DEFAULT_ARCHIVE_PATH = ENV['COLLECTIONS_ARCHIVE_PATH'] || Rails.root.join('collections_data.tar.gz')
128132

129133
# New API: validate and encode protocol params
130134
# Unified interface - accepts all possible parameters, uses what it needs
@@ -264,6 +268,47 @@ class << self
264268
include Memery
265269

266270
def load_import_data(items_path:, collections_path:)
271+
archive_path = DEFAULT_ARCHIVE_PATH
272+
273+
# Check if we need to extract from the tar.gz archive
274+
if File.exist?(archive_path)
275+
# Check if JSON files don't exist or archive is newer
276+
extract_needed = !File.exist?(items_path) || !File.exist?(collections_path) ||
277+
File.mtime(archive_path) > File.mtime(items_path) ||
278+
File.mtime(archive_path) > File.mtime(collections_path)
279+
280+
if extract_needed
281+
Rails.logger.info "Extracting collections data from #{archive_path}" if defined?(Rails)
282+
283+
# Extract tar.gz archive
284+
Zlib::GzipReader.open(archive_path) do |gz|
285+
Gem::Package::TarReader.new(gz) do |tar|
286+
tar.each do |entry|
287+
if entry.file?
288+
case entry.full_name
289+
when 'items_by_ethscription.json'
290+
File.open(items_path, 'wb') do |f|
291+
f.write(entry.read)
292+
end
293+
Rails.logger.info "Extracted #{entry.full_name} to #{items_path}" if defined?(Rails)
294+
when 'collections_by_name.json'
295+
File.open(collections_path, 'wb') do |f|
296+
f.write(entry.read)
297+
end
298+
Rails.logger.info "Extracted #{entry.full_name} to #{collections_path}" if defined?(Rails)
299+
end
300+
end
301+
end
302+
end
303+
end
304+
end
305+
end
306+
307+
# Ensure files exist before reading
308+
unless File.exist?(items_path) && File.exist?(collections_path)
309+
raise "Collections data files not found. Please ensure #{archive_path} exists or provide JSON files directly."
310+
end
311+
267312
items = JSON.parse(File.read(items_path))
268313
collections = JSON.parse(File.read(collections_path))
269314

@@ -275,7 +320,7 @@ def load_import_data(items_path:, collections_path:)
275320
items_by_id.each do |iid, it|
276321
cname = it['collection_name']
277322
next unless cname.is_a?(String) && !cname.empty?
278-
num = it['ethscription_number'].to_i
323+
num = it.fetch('ethscription_number').to_i
279324
groups[cname] << [iid, num]
280325
end
281326

collections_data.tar.gz

23.7 MB
Binary file not shown.

compress_collections.sh

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
#!/bin/bash
2+
3+
# Script to compress collection JSON files into a single tar.gz archive
4+
5+
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
6+
cd "$SCRIPT_DIR"
7+
8+
ITEMS_FILE="items_by_ethscription.json"
9+
COLLECTIONS_FILE="collections_by_name.json"
10+
ARCHIVE_FILE="collections_data.tar.gz"
11+
12+
# Check if JSON files exist
13+
if [ ! -f "$ITEMS_FILE" ]; then
14+
echo "Error: $ITEMS_FILE not found!"
15+
exit 1
16+
fi
17+
18+
if [ ! -f "$COLLECTIONS_FILE" ]; then
19+
echo "Error: $COLLECTIONS_FILE not found!"
20+
exit 1
21+
fi
22+
23+
# Create tar.gz archive
24+
echo "Creating $ARCHIVE_FILE..."
25+
tar -czf "$ARCHIVE_FILE" "$ITEMS_FILE" "$COLLECTIONS_FILE"
26+
27+
if [ $? -eq 0 ]; then
28+
echo "Successfully created $ARCHIVE_FILE"
29+
30+
# Show file sizes for comparison
31+
echo ""
32+
echo "File sizes:"
33+
ls -lh "$ITEMS_FILE" "$COLLECTIONS_FILE" "$ARCHIVE_FILE" | awk '{print $9 ": " $5}'
34+
35+
# Calculate compression ratio (macOS compatible)
36+
ORIGINAL_SIZE=$(stat -f %z "$ITEMS_FILE" "$COLLECTIONS_FILE" 2>/dev/null | awk '{sum += $1} END {print sum}')
37+
if [ -z "$ORIGINAL_SIZE" ]; then
38+
# Linux fallback
39+
ORIGINAL_SIZE=$(stat -c %s "$ITEMS_FILE" "$COLLECTIONS_FILE" 2>/dev/null | awk '{sum += $1} END {print sum}')
40+
fi
41+
COMPRESSED_SIZE=$(stat -f %z "$ARCHIVE_FILE" 2>/dev/null || stat -c %s "$ARCHIVE_FILE" 2>/dev/null)
42+
if [ -n "$ORIGINAL_SIZE" ] && [ -n "$COMPRESSED_SIZE" ]; then
43+
RATIO=$(echo "scale=2; (1 - $COMPRESSED_SIZE / $ORIGINAL_SIZE) * 100" | bc)
44+
else
45+
RATIO="N/A"
46+
fi
47+
48+
echo ""
49+
echo "Compression ratio: ${RATIO}% size reduction"
50+
else
51+
echo "Error: Failed to create archive"
52+
exit 1
53+
fi

contracts/src/ERC20FixedDenominationManager.sol

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -168,8 +168,8 @@ contract ERC20FixedDenominationManager is IProtocolHandler {
168168

169169
bytes memory collectionInitCalldata = abi.encodeWithSelector(
170170
ERC721EthscriptionsCollection.initialize.selector,
171-
string.concat(deployOp.tick, " ERC-721"), // Collection name
172-
string.concat(deployOp.tick.upper(), "-ERC-721"), // Collection symbol
171+
deployOp.tick, // Collection name
172+
deployOp.tick.upper(), // Collection symbol
173173
address(this), // Manager owns the collection
174174
ethscriptionId // Collection ID is the deploy ethscription ID
175175
);

contracts/src/NameRegistry.sol

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,7 @@ contract NameRegistry is ERC721EthscriptionsEnumerableUpgradeable, IProtocolHand
197197
bytes memory json = abi.encodePacked(
198198
'{"name":"',
199199
name.escapeJSON(),
200-
'","description":"An Ethscriptions name"',
200+
'","description":"An Ethscription name"',
201201
',"ethscription_id":"',
202202
ethscriptionIdHex,
203203
'","ethscription_number":',
@@ -222,7 +222,7 @@ contract NameRegistry is ERC721EthscriptionsEnumerableUpgradeable, IProtocolHand
222222
return string(abi.encodePacked(
223223
'data:application/json;base64,',
224224
Base64.encode(bytes(
225-
'{"name":"Word Domains Registry",'
225+
'{"name":"Ethscription Names",'
226226
'"description":"On-chain name system for Ethscriptions. Allowed characters: a-z, 0-9, and _ (underscore). Max length: 30 characters.",'
227227
'"image":"data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNTAwIiBoZWlnaHQ9IjUwMCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cmVjdCB3aWR0aD0iNTAwIiBoZWlnaHQ9IjUwMCIgZmlsbD0iIzEwMTAxMCIvPjx0ZXh0IHg9IjI1MCIgeT0iMjUwIiBmb250LXNpemU9IjgwIiBmb250LWZhbWlseT0ibW9ub3NwYWNlIiB0ZXh0LWFuY2hvcj0ibWlkZGxlIiBmaWxsPSIjMDBmZjAwIj5bTkFNRVNdPC90ZXh0Pjwvc3ZnPg==",'
228228
'"external_link":"https://ethscriptions.com"}'

contracts/test/EthscriptionsToken.t.sol

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -639,8 +639,8 @@ contract EthscriptionsTokenTest is TestSetup {
639639

640640
// Verify collection properties
641641
ERC721EthscriptionsCollection collection = ERC721EthscriptionsCollection(collectionAddr);
642-
assertEq(collection.name(), "COLL ERC-721");
643-
assertEq(collection.symbol(), "COLL-ERC-721");
642+
assertEq(collection.name(), "COLL");
643+
assertEq(collection.symbol(), "COLL");
644644
assertEq(collection.collectionId(), DEPLOY_TX_HASH);
645645

646646
// Verify collection lookups work

lib/protocol_event_reader.rb

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,8 @@ def self.parse_log(log)
7777
parse_items_removed(log)
7878
when 'CollectionEdited'
7979
parse_collection_edited(log)
80+
when 'OwnershipTransferred'
81+
parse_collection_ownership_transferred(log)
8082
else
8183
{
8284
event: event_name,
@@ -370,6 +372,15 @@ def self.parse_collection_edited(log)
370372
}
371373
end
372374

375+
def self.parse_collection_ownership_transferred(log)
376+
{
377+
event: 'OwnershipTransferred',
378+
collection_id: log['topics'][1],
379+
previous_owner: log['topics'][2] ? '0x' + log['topics'][2][-40..] : nil,
380+
new_owner: log['topics'][3] ? '0x' + log['topics'][3][-40..] : nil
381+
}
382+
end
383+
373384
# Helper to check if a receipt contains a successful protocol execution
374385
def self.protocol_succeeded?(receipt)
375386
events = parse_receipt_events(receipt)

0 commit comments

Comments
 (0)